Browse Source

- Added account status of either active or banned.

- Cleaned up admin pages.
- Added Type and Status to user's profile page.
- Banned users cannot login, or associate API calls with their account
tags/3.0.0
Teknikode 1 year ago
parent
commit
51b4260f3c
30 changed files with 481 additions and 167 deletions
  1. 6
    6
      Teknik/Areas/Admin/AdminAreaRegistration.cs
  2. 22
    8
      Teknik/Areas/Admin/Controllers/AdminController.cs
  3. 25
    2
      Teknik/Areas/Admin/Scripts/UserInfo.js
  4. 3
    3
      Teknik/Areas/Admin/Scripts/UserSearch.js
  5. 3
    2
      Teknik/Areas/Admin/ViewModels/UserInfoViewModel.cs
  6. 3
    3
      Teknik/Areas/Admin/ViewModels/UserResultViewModel.cs
  7. 3
    3
      Teknik/Areas/Admin/ViewModels/UserSearchViewModel.cs
  8. 3
    3
      Teknik/Areas/Admin/Views/Admin/Dashboard.cshtml
  9. 32
    8
      Teknik/Areas/Admin/Views/Admin/UserInfo.cshtml
  10. 2
    2
      Teknik/Areas/Admin/Views/Admin/UserResult.cshtml
  11. 3
    3
      Teknik/Areas/Admin/Views/Admin/UserResults.cshtml
  12. 4
    4
      Teknik/Areas/Admin/Views/Admin/UserSearch.cshtml
  13. 3
    3
      Teknik/Areas/Error/Controllers/ErrorController.cs
  14. 2
    2
      Teknik/Areas/Error/ErrorAreaRegistration.cs
  15. 13
    2
      Teknik/Areas/User/Controllers/UserController.cs
  16. 5
    2
      Teknik/Areas/User/Models/User.cs
  17. 1
    1
      Teknik/Areas/User/Models/UserSettings.cs
  18. 113
    1
      Teknik/Areas/User/Utility/UserHelper.cs
  19. 3
    2
      Teknik/Areas/User/ViewModels/EditSettingsViewModel.cs
  20. 7
    2
      Teknik/Areas/User/ViewModels/ProfileViewModel.cs
  21. 19
    6
      Teknik/Areas/User/Views/User/ViewProfile.cshtml
  22. 4
    3
      Teknik/Attributes/TeknikAuthorizeAttribute.cs
  23. 63
    63
      Teknik/Global.asax.cs
  24. 113
    0
      Teknik/Modules/UserCheckModule.cs
  25. 4
    17
      Teknik/Security/TeknikPrincipal.cs
  26. 8
    6
      Teknik/Teknik.csproj
  27. 3
    2
      Teknik/Web.config
  28. 8
    0
      Utilities/Utilities/AccountStatus.cs
  29. 2
    8
      Utilities/Utilities/AccountType.cs
  30. 1
    0
      Utilities/Utilities/Utilities.csproj

+ 6
- 6
Teknik/Areas/Admin/AdminAreaRegistration.cs View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Optimization;
using Teknik.Configuration;
@@ -28,11 +28,11 @@ namespace Teknik.Areas.Admin
new[] { typeof(Controllers.AdminController).Namespace }
);
context.MapSubdomainRoute(
"Admin.Search", // Route name
"Admin.UserSearch", // Route name
new List<string>() { "admin" }, // Subdomains
new List<string>() { config.Host },
"Search/Users", // URL with parameters
new { controller = "Admin", action = "Search" }, // Parameter defaults
new { controller = "Admin", action = "UserSearch" }, // Parameter defaults
new[] { typeof(Controllers.AdminController).Namespace }
);
context.MapSubdomainRoute(
@@ -61,8 +61,8 @@ namespace Teknik.Areas.Admin
);

// Register Script Bundles
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/Search", config.CdnHost).Include(
"~/Areas/Admin/Scripts/Search.js"));
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/UserSearch", config.CdnHost).Include(
"~/Areas/Admin/Scripts/UserSearch.js"));

// Register Script Bundles
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/UploadSearch", config.CdnHost).Include(
@@ -73,4 +73,4 @@ namespace Teknik.Areas.Admin
"~/Areas/Admin/Scripts/UserInfo.js"));
}
}
}
}

+ 22
- 8
Teknik/Areas/Admin/Controllers/AdminController.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -27,9 +27,9 @@ namespace Teknik.Areas.Admin.Controllers
}

[HttpGet]
public ActionResult Search()
public ActionResult UserSearch()
{
SearchViewModel model = new SearchViewModel();
UserSearchViewModel model = new UserSearchViewModel();
return View(model);
}

@@ -42,6 +42,7 @@ namespace Teknik.Areas.Admin.Controllers
UserInfoViewModel model = new UserInfoViewModel();
model.Username = user.Username;
model.AccountType = user.AccountType;
model.AccountStatus = user.AccountStatus;
return View(model);
}
return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
@@ -55,9 +56,9 @@ namespace Teknik.Areas.Admin.Controllers
}

[HttpPost]
public ActionResult GetSearchResults(string query)
public ActionResult GetUserSearchResults(string query)
{
List<SearchResultViewModel> models = new List<SearchResultViewModel>();
List<UserResultViewModel> models = new List<UserResultViewModel>();

var results = db.Users.Where(u => u.Username.Contains(query)).ToList();
if (results != null)
@@ -66,7 +67,7 @@ namespace Teknik.Areas.Admin.Controllers
{
try
{
SearchResultViewModel model = new SearchResultViewModel();
UserResultViewModel model = new UserResultViewModel();
model.Username = user.Username;
if (Config.EmailConfig.Enabled)
{
@@ -83,7 +84,7 @@ namespace Teknik.Areas.Admin.Controllers
}
}

return PartialView("~/Areas/Admin/Views/Admin/SearchResults.cshtml", models);
return PartialView("~/Areas/Admin/Views/Admin/UserResults.cshtml", models);
}

[HttpPost]
@@ -118,5 +119,18 @@ namespace Teknik.Areas.Admin.Controllers
}
return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditUserAccountStatus(string username, AccountStatus accountStatus)
{
if (UserHelper.UserExists(db, username))
{
// Edit the user's account type
UserHelper.EditAccountStatus(db, Config, username, accountStatus);
return Json(new { result = new { success = true } });
}
return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
}
}
}
}

+ 25
- 2
Teknik/Areas/Admin/Scripts/UserInfo.js View File

@@ -1,4 +1,4 @@
$(function () {
$(function () {

$('.userAccountType').on('change', function () {
var selected = $(this).find("option:selected").val();
@@ -23,4 +23,27 @@
});
});

});
$('.userAccountStatus').on('change', function () {
var selected = $(this).find("option:selected").val();

$.ajax({
type: "POST",
url: editAccountStatus,
data: AddAntiForgeryToken({ username: username, accountStatus: selected }),
success: function (html) {
if (html) {
if (html.error) {
$("#top_msg").css('display', 'inline', 'important');
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>' + html.error.message + '</div>');
}
else {
$("#top_msg").css('display', 'none');
$("#top_msg").html('');
alert('Successfully changed the account status for \'' + username + '\' to: ' + selected);
}
}
}
});
});

});

Teknik/Areas/Admin/Scripts/Search.js → Teknik/Areas/Admin/Scripts/UserSearch.js View File

@@ -1,9 +1,9 @@
$(document).ready(function () {
$(document).ready(function () {
$('#Query').on('input', function (e) {
query = $(this).val();
$.ajax({
type: "POST",
url: searchResultsURL,
url: userSearchResultsURL,
data: { query: query },
success: function (html) {
if (html) {
@@ -18,4 +18,4 @@
}
});
});
});
});

+ 3
- 2
Teknik/Areas/Admin/ViewModels/UserInfoViewModel.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -11,5 +11,6 @@ namespace Teknik.Areas.Admin.ViewModels
{
public string Username { get; set; }
public AccountType AccountType { get; set; }
public AccountStatus AccountStatus { get; set; }
}
}
}

Teknik/Areas/Admin/ViewModels/SearchResultViewModel.cs → Teknik/Areas/Admin/ViewModels/UserResultViewModel.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -6,7 +6,7 @@ using Teknik.ViewModels;

namespace Teknik.Areas.Admin.ViewModels
{
public class SearchResultViewModel : ViewModelBase
public class UserResultViewModel : ViewModelBase
{
public string Username { get; set; }

@@ -16,4 +16,4 @@ namespace Teknik.Areas.Admin.ViewModels

public DateTime LastSeen { get; set; }
}
}
}

Teknik/Areas/Admin/ViewModels/SearchViewModel.cs → Teknik/Areas/Admin/ViewModels/UserSearchViewModel.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -6,7 +6,7 @@ using Teknik.ViewModels;

namespace Teknik.Areas.Admin.ViewModels
{
public class SearchViewModel : ViewModelBase
public class UserSearchViewModel : ViewModelBase
{
}
}
}

+ 3
- 3
Teknik/Areas/Admin/Views/Admin/Dashboard.cshtml View File

@@ -1,11 +1,11 @@
@model Teknik.Areas.Admin.ViewModels.DashboardViewModel
@model Teknik.Areas.Admin.ViewModels.DashboardViewModel

@using Teknik.Utilities

<div class="container">
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
<a href="@Url.SubRouteUrl("admin", "Admin.Search")">Search</a>
<a href="@Url.SubRouteUrl("admin", "Admin.UserSearch")">User Search</a>
</div>
</div>
<div class="row">
@@ -13,4 +13,4 @@
<a href="@Url.SubRouteUrl("admin", "Admin.UploadSearch")">Upload Search</a>
</div>
</div>
</div>
</div>

+ 32
- 8
Teknik/Areas/Admin/Views/Admin/UserInfo.cshtml View File

@@ -1,10 +1,11 @@
@model Teknik.Areas.Admin.ViewModels.UserInfoViewModel
@model Teknik.Areas.Admin.ViewModels.UserInfoViewModel

@using Teknik.Utilities

<script>
// We need to define the action URLs for the script
var editAccountType = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountType" })';
var editAccountStatus = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountStatus" })';
var username = '@Model.Username';
</script>

@@ -12,20 +13,43 @@

<div class="container">
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
<div class="col-sm-2 col-sm-offset-1">
Username:
</div>
<div class="col-sm-8">
<a href="@Url.SubRouteUrl("user", "User.ViewProfile", new { username = Model.Username })">@Model.Username</a>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-4 col-sm-offset-1">Account Type:
<div class="col-sm-2 col-sm-offset-1">
Account Type:
</div>
<div class="col-sm-8">
<select class="userAccountType">
@{
foreach (AccountType value in Enum.GetValues(typeof(AccountType)))
{
<option @(value == Model.AccountType ? "selected" : string.Empty)>@value.ToString()</option>
}
foreach (AccountType value in Enum.GetValues(typeof(AccountType)))
{
<option @(value == Model.AccountType ? "selected" : string.Empty)>@value.ToString()</option>
}
}
</select>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-2 col-sm-offset-1">
Account Status:
</div>
<div class="col-sm-8">
<select class="userAccountStatus">
@{
foreach (AccountStatus value in Enum.GetValues(typeof(AccountStatus)))
{
<option @(value == Model.AccountStatus ? "selected" : string.Empty)>@value.ToString()</option>
}
}
</select>
</div>
</div>
</div>
</div>

Teknik/Areas/Admin/Views/Admin/SearchResult.cshtml → Teknik/Areas/Admin/Views/Admin/UserResult.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Admin.ViewModels.SearchResultViewModel
@model Teknik.Areas.Admin.ViewModels.UserResultViewModel

@using Teknik.Utilities

@@ -11,4 +11,4 @@
<div class="col-sm-3"><time datetime="@Model.JoinDate.ToString("s")">@Model.JoinDate.ToString("MMMM dd, yyyy hh:mm tt")</time></div>
<div class="col-sm-3"><time datetime="@Model.LastSeen.ToString("s")">@Model.LastSeen.ToString("MMMM dd, yyyy hh:mm tt")</time></div>
</div>
</div>
</div>

Teknik/Areas/Admin/Views/Admin/SearchResults.cshtml → Teknik/Areas/Admin/Views/Admin/UserResults.cshtml View File

@@ -1,4 +1,4 @@
@model List<Teknik.Areas.Admin.ViewModels.SearchResultViewModel>
@model List<Teknik.Areas.Admin.ViewModels.UserResultViewModel>

@if (Model.Any())
{
@@ -10,10 +10,10 @@
</div>
foreach (var post in Model)
{
@Html.Partial("SearchResult", post)
@Html.Partial("UserResult", post)
}
}
else
{
<h3>No Results</h3>
}
}

Teknik/Areas/Admin/Views/Admin/Search.cshtml → Teknik/Areas/Admin/Views/Admin/UserSearch.cshtml View File

@@ -1,13 +1,13 @@
@model Teknik.Areas.Admin.ViewModels.SearchViewModel
@model Teknik.Areas.Admin.ViewModels.UserSearchViewModel

@using Teknik.Utilities

<script>
// We need to define the action URLs for the script
var searchResultsURL = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "GetSearchResults" })';
var userSearchResultsURL = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "GetUserSearchResults" })';
</script>

@Scripts.Render("~/bundles/Search")
@Scripts.Render("~/bundles/UserSearch")

<div class="container">
<div class="row">
@@ -24,4 +24,4 @@
<div class="results" id="results"></div>
</div>
</div>
</div>
</div>

+ 3
- 3
Teknik/Areas/Error/Controllers/ErrorController.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
@@ -99,7 +99,7 @@ namespace Teknik.Areas.Error.Controllers

return View("~/Areas/Error/Views/Error/Http403.cshtml", model);
}
[AllowAnonymous]
public ActionResult Http404(Exception exception)
{
@@ -163,4 +163,4 @@ namespace Teknik.Areas.Error.Controllers
Logger.WriteEntry(level, message, exception);
}
}
}
}

+ 2
- 2
Teknik/Areas/Error/ErrorAreaRegistration.cs View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Web.Mvc;
using Teknik.Configuration;

@@ -43,4 +43,4 @@ namespace Teknik.Areas.Error
);
}
}
}
}

+ 13
- 2
Teknik/Areas/User/Controllers/UserController.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
@@ -69,6 +69,8 @@ namespace Teknik.Areas.Users.Controllers
}
model.JoinDate = user.JoinDate;
model.LastSeen = UserHelper.GetLastAccountActivity(db, Config, user);
model.AccountType = user.AccountType;
model.AccountStatus = user.AccountStatus;

model.UserSettings = user.UserSettings;
model.SecuritySettings = user.SecuritySettings;
@@ -197,6 +199,15 @@ namespace Teknik.Areas.Users.Controllers
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();

// Make sure they aren't banned or anything
if (user.AccountStatus == AccountStatus.Banned)
{
model.Error = true;
model.ErrorMessage = "Account has been banned.";

return GenerateActionResult(new { error = model.ErrorMessage }, View("/Areas/User/Views/User/ViewLogin.cshtml", model));
}

// Let's double check their email and git accounts to make sure they exist
string email = UserHelper.GetUserEmailAddress(Config, username);
if (Config.EmailConfig.Enabled && !UserHelper.UserEmailExists(Config, email))
@@ -1012,4 +1023,4 @@ namespace Teknik.Areas.Users.Controllers
}
}
}
}
}

+ 5
- 2
Teknik/Areas/User/Models/User.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Collections.Generic;
@@ -26,6 +26,8 @@ namespace Teknik.Areas.Users.Models

public AccountType AccountType { get; set; }

public AccountStatus AccountStatus { get; set; }

public virtual ICollection<Group> Groups { get; set; }
public virtual UserSettings UserSettings { get; set; }
@@ -56,9 +58,10 @@ namespace Teknik.Areas.Users.Models
JoinDate = DateTime.Now;
LastSeen = DateTime.Now;
AccountType = AccountType.Basic;
AccountStatus = AccountStatus.Active;
Groups = new List<Group>();
TrustedDevices = new List<TrustedDevice>();
AuthTokens = new List<AuthToken>();
}
}
}
}

+ 1
- 1
Teknik/Areas/User/Models/UserSettings.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

+ 113
- 1
Teknik/Areas/User/Utility/UserHelper.cs View File

@@ -261,6 +261,45 @@ namespace Teknik.Areas.Users.Utility
}
}

public static void EditAccountStatus(TeknikEntities db, Config config, string username, AccountStatus status)
{
try
{
if (!UserExists(db, username))
throw new Exception($"The user provided does not exist: {username}");

// Get the user to edit
User user = GetUser(db, username);

string email = GetUserEmailAddress(config, username);

// Edit the user type
user.AccountStatus = status;
EditUser(db, config, user);

// Add/Remove account type features depending on the type
switch (status)
{
case AccountStatus.Active:
// Enable Email
EnableUserEmail(config, email);
// Enable Git
EnableUserGit(config, username);
break;
case AccountStatus.Banned:
// Disable Email
DisableUserEmail(config, email);
// Disable Git
DisableUserGit(config, username);
break;
}
}
catch (Exception ex)
{
throw new Exception($"Unable to edit the account status [{status}] for: {username}", ex);
}
}

public static void DeleteAccount(TeknikEntities db, Config config, User user)
{
try
@@ -385,7 +424,7 @@ namespace Teknik.Areas.Users.Utility
return false;
}

public static bool UserHasRoles(TeknikEntities db, User user, params string[] roles)
public static bool UserHasRoles(User user, params string[] roles)
{
bool hasRole = true;
if (user != null)
@@ -862,6 +901,38 @@ If you recieved this email and you did not reset your password, you can ignore t
}
}

public static void EnableUserEmail(Config config, string email)
{
EditUserEmailActivity(config, email, true);
}

public static void DisableUserEmail(Config config, string email)
{
EditUserEmailActivity(config, email, false);
}

public static void EditUserEmailActivity(Config config, string email, bool active)
{
try
{
// If Email Server is enabled
if (config.EmailConfig.Enabled)
{
var app = new hMailServer.Application();
app.Connect();
app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
var account = domain.Accounts.ItemByAddress[email];
account.Active = active;
account.Save();
}
}
catch (Exception ex)
{
throw new Exception("Unable to edit email account mailbox size.", ex);
}
}

public static void EditUserEmailPassword(Config config, string email, string password)
{
try
@@ -1069,6 +1140,47 @@ If you recieved this email and you did not reset your password, you can ignore t
}
}

public static void EnableUserGit(Config config, string username)
{
EditUserGitActivity(config, username, true);
}

public static void DisableUserGit(Config config, string username)
{
EditUserGitActivity(config, username, false);
}

public static void EditUserGitActivity(Config config, string username, bool active)
{
try
{
// If Git is enabled
if (config.GitConfig.Enabled)
{
// Git user exists?
if (!UserGitExists(config, username))
{
throw new Exception($"Git User '{username}' does not exist.");
}

string email = GetUserEmailAddress(config, username);
using (var client = new WebClient())
{
var obj = new { active = active, email = email };
string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
client.Headers[HttpRequestHeader.ContentType] = "application/json";
Uri baseUri = new Uri(config.GitConfig.Host);
Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + username + "?token=" + config.GitConfig.AccessToken);
string result = client.UploadString(finalUri, "PATCH", json);
}
}
}
catch (Exception ex)
{
throw new Exception("Unable to edit git account password.", ex);
}
}

public static void CreateUserGitTwoFactor(Config config, string username, string secret, int unixTime)
{
try

+ 3
- 2
Teknik/Areas/User/ViewModels/EditSettingsViewModel.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -29,6 +29,7 @@ namespace Teknik.Areas.Users.ViewModels
public string Quote { get; set; }
[AllowHtml]
public string About { get; set; }
public string BlogTitle { get; set; }
@@ -37,4 +38,4 @@ namespace Teknik.Areas.Users.ViewModels
public bool Encrypt { get; set; }
}
}
}

+ 7
- 2
Teknik/Areas/User/ViewModels/ProfileViewModel.cs View File

@@ -1,8 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Teknik.Areas.Users.Models;
using Teknik.Utilities;
using Teknik.ViewModels;

namespace Teknik.Areas.Users.ViewModels
@@ -19,6 +20,10 @@ namespace Teknik.Areas.Users.ViewModels

public DateTime LastSeen { get; set; }

public AccountType AccountType { get; set; }

public AccountStatus AccountStatus { get; set; }

public List<Upload.Models.Upload> Uploads { get; set; }

public List<Paste.Models.Paste> Pastes { get; set; }
@@ -35,4 +40,4 @@ namespace Teknik.Areas.Users.ViewModels

public UploadSettings UploadSettings { get; set; }
}
}
}

+ 19
- 6
Teknik/Areas/User/Views/User/ViewProfile.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Users.ViewModels.ProfileViewModel
@model Teknik.Areas.Users.ViewModels.ProfileViewModel

@using Teknik.Utilities
@using Teknik.Utilities.Cryptography
@@ -11,7 +11,7 @@
<div class="container">
@if (!Model.Error)
{
bool OwnProfile = (Model.Username == User.Identity.Name || User.IsInRole("Admin"));
bool OwnProfile = (Model.Username == User.Identity.Name || User.IsInRole("Admin")) && User.Identity.IsAuthenticated;
string gitHost = Model.Config.GitConfig.Host;
string gitFullUrl = string.Empty;
if (!string.IsNullOrEmpty(gitHost))
@@ -32,6 +32,12 @@
<div class="row text-center">
<div class="col-sm-3"><h1>@Model.Username</h1></div>
</div>
if (User.IsInRole("Admin"))
{
<div class="row text-center">
<div class="col-sm-3"><a href="@Url.SubRouteUrl("admin", "Admin.UserInfo", new { username = Model.Username })">edit</a></div>
</div>
}
<div class="modal fade" id="pgpSignature" tabindex="-1" role="dialog" aria-labelledby="pgpSignatureLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
@@ -78,11 +84,18 @@
<!-- Left Info Box -->
<div class="col-sm-3"><!--left col-->
<ul class="list-group">
<li class="list-group-item text-muted">Profile</li>
<li class="list-group-item text-right"><span class="pull-left"><strong>Joined</strong></span> <time datetime="@Model.LastSeen.ToString("s")">@Model.JoinDate.ToString("MMMM dd, yyyy")</time></li>
@if (OwnProfile && User.Identity.IsAuthenticated)
@if (OwnProfile)
{
<li class="list-group-item text-right"><span class="pull-left"><strong>Last Seen</strong></span> <time datetime="@Model.LastSeen.ToString("s")">@Model.LastSeen.ToString("dd/MM/yyyy hh:mm tt")</time></li>
}
@if (OwnProfile)
{
<li class="list-group-item text-right"><span class="pull-left"><strong>Account Type</strong></span> @Model.AccountType</li>
}
@if (User.IsInRole("Admin"))
{
<li class="list-group-item text-right"><span class="pull-left"><strong>Last Seen</strong></span> <time datetime="@Model.LastSeen.ToString("s")">@Model.LastSeen.ToString("MMMM dd, yyyy hh:mm tt")</time></li>
<li class="list-group-item text-right"><span class="pull-left"><strong>Account Status</strong></span> @Model.AccountStatus</li>
}
@if (!string.IsNullOrEmpty(pgpFingerprint))
{
@@ -276,4 +289,4 @@
}
</div>

@Scripts.Render("~/bundles/profile")
@Scripts.Render("~/bundles/profile")

+ 4
- 3
Teknik/Attributes/TeknikAuthorizeAttribute.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -122,7 +122,8 @@ namespace Teknik.Attributes
if (validToken)
{
User user = UserHelper.GetUserFromToken(entities, authCreds.Key, authCreds.Value);
return UserHelper.UserHasRoles(entities, user, Roles);

return UserHelper.UserHasRoles(user, Roles);
}
break;
default:
@@ -204,4 +205,4 @@ namespace Teknik.Attributes
validationStatus = base.OnCacheAuthorization(new HttpContextWrapper(context));
}
}
}
}

+ 63
- 63
Teknik/Global.asax.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -77,70 +77,70 @@ namespace Teknik
}
}

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
// We support both Auth Tokens and Cookie Authentication
//protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
//{
// // We support both Auth Tokens and Cookie Authentication

// Username and Roles for the current user
string username = string.Empty;
// // Username and Roles for the current user
// string username = string.Empty;
bool hasAuthToken = false;
if (Request != null)
{
if (Request.Headers.HasKeys())
{
string auth = Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(auth))
{
string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string type = string.Empty;
string value = string.Empty;
if (parts.Length > 0)
{
type = parts[0].ToLower();
}
if (parts.Length > 1)
{
value = parts[1];
}
using (TeknikEntities entities = new TeknikEntities())
{
// Get the user information based on the auth type
switch (type)
{
case "basic":
KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value);
bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
if (tokenValid)
{
// it's valid, so let's update it's Last Used date
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);
// Set the username
username = authCreds.Key;
}
break;
default:
break;
}
}
}
}
}
if (FormsAuthentication.CookiesSupported == true && !hasAuthToken)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
//let us take out the username now
username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
}
}
HttpContext.Current.User = new TeknikPrincipal(username);
}
// bool hasAuthToken = false;
// if (Request != null)
// {
// if (Request.Headers.HasKeys())
// {
// string auth = Request.Headers["Authorization"];
// if (!string.IsNullOrEmpty(auth))
// {
// string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
// string type = string.Empty;
// string value = string.Empty;
// if (parts.Length > 0)
// {
// type = parts[0].ToLower();
// }
// if (parts.Length > 1)
// {
// value = parts[1];
// }
// using (TeknikEntities entities = new TeknikEntities())
// {
// // Get the user information based on the auth type
// switch (type)
// {
// case "basic":
// KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value);
// bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
// if (tokenValid)
// {
// // it's valid, so let's update it's Last Used date
// UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);
// // Set the username
// username = authCreds.Key;
// }
// break;
// default:
// break;
// }
// }
// }
// }
// }
// if (FormsAuthentication.CookiesSupported == true && !hasAuthToken)
// {
// if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
// {
// //let us take out the username now
// username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
// }
// }
// HttpContext.Current.User = new TeknikPrincipal(username);
//}

protected void Application_Error(object sender, EventArgs e)
{

+ 113
- 0
Teknik/Modules/UserCheckModule.cs View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using Teknik.Areas.Error.Controllers;
using Teknik.Areas.Users.Utility;
using Teknik.Models;
using Teknik.Security;
using Teknik.Utilities;

namespace Teknik.Modules
{
public class UserCheckModule : IHttpModule
{
public void Dispose()
{
}

public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += OnPostAuthenticateRequestHandlerExecute;
}

private void OnPostAuthenticateRequestHandlerExecute(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
string username = string.Empty;

bool hasAuthToken = false;
if (context.Request != null)
{
if (context.Request.Headers.HasKeys())
{
string auth = context.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(auth))
{
string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string type = string.Empty;
string value = string.Empty;
if (parts.Length > 0)
{
type = parts[0].ToLower();
}
if (parts.Length > 1)
{
value = parts[1];
}

using (TeknikEntities entities = new TeknikEntities())
{
// Get the user information based on the auth type
switch (type)
{
case "basic":
KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value);

bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
if (tokenValid)
{
// it's valid, so let's update it's Last Used date
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);

// Set the username
username = authCreds.Key;
}
break;
default:
break;
}
}
}
}
}

// Check if they have a Forms Auth cookie
if (FormsAuthentication.CookiesSupported == true && !hasAuthToken)
{
if (context.Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
//let us take out the username now
username = FormsAuthentication.Decrypt(context.Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
}
}

context.User = new TeknikPrincipal(username);

// Check to see if we need to logout this user
if (context.User != null && context.User.Identity.IsAuthenticated)
{
TeknikPrincipal user = (context.User as TeknikPrincipal);
// Is the user banned?
if (user?.Info.AccountStatus == AccountStatus.Banned)
{
// Get cookie
HttpCookie authCookie = UserHelper.CreateAuthCookie(user.Identity.Name, false, context.Request.Url.Host.GetDomain(), context.Request.IsLocal);

// Signout
FormsAuthentication.SignOut();
context.Session?.Abandon();

// Destroy Cookies
authCookie.Expires = DateTime.Now.AddYears(-1);
context.Response.Cookies.Add(authCookie);

// Reset the context user
context.User = new TeknikPrincipal(string.Empty);
}
}
}
}
}

+ 4
- 17
Teknik/Security/TeknikPrincipal.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
@@ -6,6 +6,7 @@ using System.Web;
using Teknik.Areas.Users.Models;
using Teknik.Areas.Users.Utility;
using Teknik.Models;
using Teknik.Utilities;

namespace Teknik.Security
{
@@ -41,21 +42,7 @@ namespace Teknik.Security

public bool IsInRole(string role)
{
if (Info != null)
{
// Grab all their roles
foreach (Group grp in Info.Groups)
{
foreach (Role curRole in grp.Roles)
{
if (curRole.Name == role)
{
return true;
}
}
}
}
return false;
return UserHelper.UserHasRoles(Info, role);
}
}
}
}

+ 8
- 6
Teknik/Teknik.csproj View File

@@ -26,6 +26,7 @@
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<Use64BitIISExpress />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -219,10 +220,10 @@
<Compile Include="Areas\Admin\AdminAreaRegistration.cs" />
<Compile Include="Areas\Admin\Controllers\AdminController.cs" />
<Compile Include="Areas\Admin\ViewModels\DashboardViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\SearchResultViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\UserResultViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\UploadResultViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\UploadSearchViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\SearchViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\UserSearchViewModel.cs" />
<Compile Include="Areas\Admin\ViewModels\UserInfoViewModel.cs" />
<Compile Include="Areas\API\APIAreaRegistration.cs" />
<Compile Include="Areas\API\Controllers\APIController.cs" />
@@ -309,6 +310,7 @@
<Compile Include="Areas\Vault\ViewModels\VaultItemViewModel.cs" />
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" />
<Compile Include="Hubs\IRCClientHub.cs" />
<Compile Include="Modules\UserCheckModule.cs" />
<Compile Include="Security\ITeknikPrincipal.cs" />
<Compile Include="Security\TeknikPrincipal.cs" />
<Compile Include="Filters\CORSActionFilter.cs" />
@@ -389,7 +391,7 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Areas\Admin\Scripts\UploadSearch.js" />
<Content Include="Areas\Admin\Scripts\Search.js" />
<Content Include="Areas\Admin\Scripts\UserSearch.js" />
<Content Include="Areas\Admin\Scripts\UserInfo.js" />
<Content Include="Areas\Blog\Content\Blog.css" />
<Content Include="Areas\Blog\Scripts\Blog.js" />
@@ -628,10 +630,10 @@
<Content Include="Areas\Help\Views\Help\Markdown.cshtml" />
<Content Include="Areas\Help\Views\Help\Tools.cshtml" />
<Content Include="Areas\Admin\Views\web.config" />
<Content Include="Areas\Admin\Views\Admin\Search.cshtml" />
<Content Include="Areas\Admin\Views\Admin\UserSearch.cshtml" />
<Content Include="Areas\Admin\Views\Admin\Dashboard.cshtml" />
<Content Include="Areas\Admin\Views\Admin\SearchResult.cshtml" />
<Content Include="Areas\Admin\Views\Admin\SearchResults.cshtml" />
<Content Include="Areas\Admin\Views\Admin\UserResult.cshtml" />
<Content Include="Areas\Admin\Views\Admin\UserResults.cshtml" />
<Content Include="Areas\Admin\Views\_ViewStart.cshtml" />
<Content Include="App_Data\MachineKey.config" />
<Content Include="Areas\Admin\Views\Admin\UserInfo.cshtml" />

+ 3
- 2
Teknik/Web.config View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301880
@@ -55,6 +55,7 @@
<remove name="FormsAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" />
<add name="UserCheckModule" type="Teknik.Modules.UserCheckModule, Teknik" />
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>
@@ -199,4 +200,4 @@
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
</compilers>
</system.codedom>
</configuration>
</configuration>

+ 8
- 0
Utilities/Utilities/AccountStatus.cs View File

@@ -0,0 +1,8 @@
namespace Teknik.Utilities
{
public enum AccountStatus
{
Active = 0,
Banned = 1
}
}

+ 2
- 8
Utilities/Utilities/AccountType.cs View File

@@ -1,14 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Teknik.Utilities
{
public enum AccountType
{
Basic,
Premium
Basic = 0,
Premium = 1
}
}

+ 1
- 0
Utilities/Utilities/Utilities.csproj View File

@@ -104,6 +104,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AccountStatus.cs" />
<Compile Include="AccountType.cs" />
<Compile Include="Cryptography\AES.cs" />
<Compile Include="Cryptography\Aes128CFB.cs" />

Loading…
Cancel
Save