1
0
mirror of https://git.teknik.io/Teknikode/Teknik.git synced 2023-08-02 14:16:22 +02:00

- 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
This commit is contained in:
Uncled1023 2018-01-09 22:06:43 -08:00
parent e3e5a60de7
commit 51b4260f3c
30 changed files with 476 additions and 162 deletions

View File

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

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
@ -27,9 +27,9 @@ namespace Teknik.Areas.Admin.Controllers
} }
[HttpGet] [HttpGet]
public ActionResult Search() public ActionResult UserSearch()
{ {
SearchViewModel model = new SearchViewModel(); UserSearchViewModel model = new UserSearchViewModel();
return View(model); return View(model);
} }
@ -42,6 +42,7 @@ namespace Teknik.Areas.Admin.Controllers
UserInfoViewModel model = new UserInfoViewModel(); UserInfoViewModel model = new UserInfoViewModel();
model.Username = user.Username; model.Username = user.Username;
model.AccountType = user.AccountType; model.AccountType = user.AccountType;
model.AccountStatus = user.AccountStatus;
return View(model); return View(model);
} }
return Redirect(Url.SubRouteUrl("error", "Error.Http404")); return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
@ -55,9 +56,9 @@ namespace Teknik.Areas.Admin.Controllers
} }
[HttpPost] [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(); var results = db.Users.Where(u => u.Username.Contains(query)).ToList();
if (results != null) if (results != null)
@ -66,7 +67,7 @@ namespace Teknik.Areas.Admin.Controllers
{ {
try try
{ {
SearchResultViewModel model = new SearchResultViewModel(); UserResultViewModel model = new UserResultViewModel();
model.Username = user.Username; model.Username = user.Username;
if (Config.EmailConfig.Enabled) 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] [HttpPost]
@ -118,5 +119,18 @@ namespace Teknik.Areas.Admin.Controllers
} }
return Redirect(Url.SubRouteUrl("error", "Error.Http404")); 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"));
}
} }
} }

View File

@ -1,4 +1,4 @@
$(function () { $(function () {
$('.userAccountType').on('change', function () { $('.userAccountType').on('change', function () {
var selected = $(this).find("option:selected").val(); 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);
}
}
}
});
});
}); });

View File

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

View File

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

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
@ -6,7 +6,7 @@ using Teknik.ViewModels;
namespace Teknik.Areas.Admin.ViewModels namespace Teknik.Areas.Admin.ViewModels
{ {
public class SearchResultViewModel : ViewModelBase public class UserResultViewModel : ViewModelBase
{ {
public string Username { get; set; } public string Username { get; set; }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
@ -6,7 +6,7 @@ using Teknik.ViewModels;
namespace Teknik.Areas.Admin.ViewModels namespace Teknik.Areas.Admin.ViewModels
{ {
public class SearchViewModel : ViewModelBase public class UserSearchViewModel : ViewModelBase
{ {
} }
} }

View File

@ -1,11 +1,11 @@
@model Teknik.Areas.Admin.ViewModels.DashboardViewModel @model Teknik.Areas.Admin.ViewModels.DashboardViewModel
@using Teknik.Utilities @using Teknik.Utilities
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-sm-10 col-sm-offset-1"> <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> </div>
<div class="row"> <div class="row">

View File

@ -1,10 +1,11 @@
@model Teknik.Areas.Admin.ViewModels.UserInfoViewModel @model Teknik.Areas.Admin.ViewModels.UserInfoViewModel
@using Teknik.Utilities @using Teknik.Utilities
<script> <script>
// We need to define the action URLs for the script // We need to define the action URLs for the script
var editAccountType = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountType" })'; var editAccountType = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountType" })';
var editAccountStatus = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountStatus" })';
var username = '@Model.Username'; var username = '@Model.Username';
</script> </script>
@ -12,18 +13,41 @@
<div class="container"> <div class="container">
<div class="row"> <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> <a href="@Url.SubRouteUrl("user", "User.ViewProfile", new { username = Model.Username })">@Model.Username</a>
</div> </div>
</div> </div>
<br />
<div class="row"> <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"> <select class="userAccountType">
@{ @{
foreach (AccountType value in Enum.GetValues(typeof(AccountType))) foreach (AccountType value in Enum.GetValues(typeof(AccountType)))
{ {
<option @(value == Model.AccountType ? "selected" : string.Empty)>@value.ToString()</option> <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> </select>
</div> </div>

View File

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

View File

@ -1,4 +1,4 @@
@model List<Teknik.Areas.Admin.ViewModels.SearchResultViewModel> @model List<Teknik.Areas.Admin.ViewModels.UserResultViewModel>
@if (Model.Any()) @if (Model.Any())
{ {
@ -10,7 +10,7 @@
</div> </div>
foreach (var post in Model) foreach (var post in Model)
{ {
@Html.Partial("SearchResult", post) @Html.Partial("UserResult", post)
} }
} }
else else

View File

@ -1,13 +1,13 @@
@model Teknik.Areas.Admin.ViewModels.SearchViewModel @model Teknik.Areas.Admin.ViewModels.UserSearchViewModel
@using Teknik.Utilities @using Teknik.Utilities
<script> <script>
// We need to define the action URLs for the 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> </script>
@Scripts.Render("~/bundles/Search") @Scripts.Render("~/bundles/UserSearch")
<div class="container"> <div class="container">
<div class="row"> <div class="row">

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Mail; using System.Net.Mail;

View File

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

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Entity; using System.Data.Entity;
using System.Linq; using System.Linq;
@ -69,6 +69,8 @@ namespace Teknik.Areas.Users.Controllers
} }
model.JoinDate = user.JoinDate; model.JoinDate = user.JoinDate;
model.LastSeen = UserHelper.GetLastAccountActivity(db, Config, user); model.LastSeen = UserHelper.GetLastAccountActivity(db, Config, user);
model.AccountType = user.AccountType;
model.AccountStatus = user.AccountStatus;
model.UserSettings = user.UserSettings; model.UserSettings = user.UserSettings;
model.SecuritySettings = user.SecuritySettings; model.SecuritySettings = user.SecuritySettings;
@ -197,6 +199,15 @@ namespace Teknik.Areas.Users.Controllers
db.Entry(user).State = EntityState.Modified; db.Entry(user).State = EntityState.Modified;
db.SaveChanges(); 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 // Let's double check their email and git accounts to make sure they exist
string email = UserHelper.GetUserEmailAddress(Config, username); string email = UserHelper.GetUserEmailAddress(Config, username);
if (Config.EmailConfig.Enabled && !UserHelper.UserEmailExists(Config, email)) if (Config.EmailConfig.Enabled && !UserHelper.UserEmailExists(Config, email))

View File

@ -1,4 +1,4 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.AspNet.Identity.EntityFramework;
using System.Collections.Generic; using System.Collections.Generic;
@ -26,6 +26,8 @@ namespace Teknik.Areas.Users.Models
public AccountType AccountType { get; set; } public AccountType AccountType { get; set; }
public AccountStatus AccountStatus { get; set; }
public virtual ICollection<Group> Groups { get; set; } public virtual ICollection<Group> Groups { get; set; }
public virtual UserSettings UserSettings { get; set; } public virtual UserSettings UserSettings { get; set; }
@ -56,6 +58,7 @@ namespace Teknik.Areas.Users.Models
JoinDate = DateTime.Now; JoinDate = DateTime.Now;
LastSeen = DateTime.Now; LastSeen = DateTime.Now;
AccountType = AccountType.Basic; AccountType = AccountType.Basic;
AccountStatus = AccountStatus.Active;
Groups = new List<Group>(); Groups = new List<Group>();
TrustedDevices = new List<TrustedDevice>(); TrustedDevices = new List<TrustedDevice>();
AuthTokens = new List<AuthToken>(); AuthTokens = new List<AuthToken>();

View File

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

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) public static void DeleteAccount(TeknikEntities db, Config config, User user)
{ {
try try
@ -385,7 +424,7 @@ namespace Teknik.Areas.Users.Utility
return false; 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; bool hasRole = true;
if (user != null) 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) public static void EditUserEmailPassword(Config config, string email, string password)
{ {
try 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) public static void CreateUserGitTwoFactor(Config config, string username, string secret, int unixTime)
{ {
try try

View File

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

View File

@ -1,8 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
using Teknik.Areas.Users.Models; using Teknik.Areas.Users.Models;
using Teknik.Utilities;
using Teknik.ViewModels; using Teknik.ViewModels;
namespace Teknik.Areas.Users.ViewModels namespace Teknik.Areas.Users.ViewModels
@ -19,6 +20,10 @@ namespace Teknik.Areas.Users.ViewModels
public DateTime LastSeen { get; set; } 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<Upload.Models.Upload> Uploads { get; set; }
public List<Paste.Models.Paste> Pastes { get; set; } public List<Paste.Models.Paste> Pastes { get; set; }

View File

@ -1,4 +1,4 @@
@model Teknik.Areas.Users.ViewModels.ProfileViewModel @model Teknik.Areas.Users.ViewModels.ProfileViewModel
@using Teknik.Utilities @using Teknik.Utilities
@using Teknik.Utilities.Cryptography @using Teknik.Utilities.Cryptography
@ -11,7 +11,7 @@
<div class="container"> <div class="container">
@if (!Model.Error) @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 gitHost = Model.Config.GitConfig.Host;
string gitFullUrl = string.Empty; string gitFullUrl = string.Empty;
if (!string.IsNullOrEmpty(gitHost)) if (!string.IsNullOrEmpty(gitHost))
@ -32,6 +32,12 @@
<div class="row text-center"> <div class="row text-center">
<div class="col-sm-3"><h1>@Model.Username</h1></div> <div class="col-sm-3"><h1>@Model.Username</h1></div>
</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 fade" id="pgpSignature" tabindex="-1" role="dialog" aria-labelledby="pgpSignatureLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
@ -78,11 +84,18 @@
<!-- Left Info Box --> <!-- Left Info Box -->
<div class="col-sm-3"><!--left col--> <div class="col-sm-3"><!--left col-->
<ul class="list-group"> <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> <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("MMMM dd, yyyy hh:mm tt")</time></li> <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>Account Status</strong></span> @Model.AccountStatus</li>
} }
@if (!string.IsNullOrEmpty(pgpFingerprint)) @if (!string.IsNullOrEmpty(pgpFingerprint))
{ {

View File

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

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
@ -77,70 +77,70 @@ namespace Teknik
} }
} }
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e) //protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{ //{
// We support both Auth Tokens and Cookie Authentication // // We support both Auth Tokens and Cookie Authentication
// Username and Roles for the current user // // Username and Roles for the current user
string username = string.Empty; // string username = string.Empty;
bool hasAuthToken = false; // bool hasAuthToken = false;
if (Request != null) // if (Request != null)
{ // {
if (Request.Headers.HasKeys()) // if (Request.Headers.HasKeys())
{ // {
string auth = Request.Headers["Authorization"]; // string auth = Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(auth)) // if (!string.IsNullOrEmpty(auth))
{ // {
string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string type = string.Empty; // string type = string.Empty;
string value = string.Empty; // string value = string.Empty;
if (parts.Length > 0) // if (parts.Length > 0)
{ // {
type = parts[0].ToLower(); // type = parts[0].ToLower();
} // }
if (parts.Length > 1) // if (parts.Length > 1)
{ // {
value = parts[1]; // value = parts[1];
} // }
using (TeknikEntities entities = new TeknikEntities()) // using (TeknikEntities entities = new TeknikEntities())
{ // {
// Get the user information based on the auth type // // Get the user information based on the auth type
switch (type) // switch (type)
{ // {
case "basic": // case "basic":
KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value); // KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value);
bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value); // bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
if (tokenValid) // if (tokenValid)
{ // {
// it's valid, so let's update it's Last Used date // // it's valid, so let's update it's Last Used date
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now); // UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);
// Set the username // // Set the username
username = authCreds.Key; // username = authCreds.Key;
} // }
break; // break;
default: // default:
break; // break;
} // }
} // }
} // }
} // }
} // }
if (FormsAuthentication.CookiesSupported == true && !hasAuthToken) // if (FormsAuthentication.CookiesSupported == true && !hasAuthToken)
{ // {
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null) // if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{ // {
//let us take out the username now // //let us take out the username now
username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name; // username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
} // }
} // }
HttpContext.Current.User = new TeknikPrincipal(username); // HttpContext.Current.User = new TeknikPrincipal(username);
} //}
protected void Application_Error(object sender, EventArgs e) protected void Application_Error(object sender, EventArgs e)
{ {

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);
}
}
}
}
}

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Principal; using System.Security.Principal;
@ -6,6 +6,7 @@ using System.Web;
using Teknik.Areas.Users.Models; using Teknik.Areas.Users.Models;
using Teknik.Areas.Users.Utility; using Teknik.Areas.Users.Utility;
using Teknik.Models; using Teknik.Models;
using Teknik.Utilities;
namespace Teknik.Security namespace Teknik.Security
{ {
@ -41,21 +42,7 @@ namespace Teknik.Security
public bool IsInRole(string role) public bool IsInRole(string role)
{ {
if (Info != null) return UserHelper.UserHasRoles(Info, role);
{
// Grab all their roles
foreach (Group grp in Info.Groups)
{
foreach (Role curRole in grp.Roles)
{
if (curRole.Name == role)
{
return true;
}
}
}
}
return false;
} }
} }
} }

View File

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

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 For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301880 http://go.microsoft.com/fwlink/?LinkId=301880
@ -55,6 +55,7 @@
<remove name="FormsAuthentication" /> <remove name="FormsAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" /> <add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" />
<add name="UserCheckModule" type="Teknik.Modules.UserCheckModule, Teknik" />
<remove name="UrlRoutingModule-4.0" /> <remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" /> <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules> </modules>

View File

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

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 namespace Teknik.Utilities
{ {
public enum AccountType public enum AccountType
{ {
Basic, Basic = 0,
Premium Premium = 1
} }
} }

View File

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