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

Moved user modification to helper class.

Added cleaning of users to server maintainence program.
Added cli args to server maint program.
Modified last activity to also grab from email and git.
This commit is contained in:
Uncled1023 2016-05-15 23:43:31 -07:00
parent 24e89c02aa
commit 19f5d28eaa
9 changed files with 512 additions and 236 deletions

View File

@ -0,0 +1,60 @@
using CommandLine;
using CommandLine.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerMaint
{
public class ArgumentOptions
{
[ParserState]
public IParserState LastParserState { get; set; }
[Option('a', "all", DefaultValue = false, Required = false, HelpText = "Run All Processes")]
public bool RunAll { get; set; }
[Option('u', "clean-users", DefaultValue = false, Required = false, HelpText = "Clean all inactive users")]
public bool CleanUsers { get; set; }
[Option('s', "scan", DefaultValue = false, Required = false, HelpText = "Scan all uploads for viruses")]
public bool ScanUploads { get; set; }
[Option('c', "config", Required = false, HelpText = "The path to the teknik config file")]
public string Config { get; set; }
[Option('d', "days", DefaultValue = 90, Required = false, HelpText = "Days before the user is deleted")]
public int DaysBeforeDeletion { get; set; }
[Option('e', "emails", DefaultValue = 2, Required = false, HelpText = "Number of emails to send before deletion")]
public int EmailsToSend { get; set; }
// Omitting long name, default --verbose
[Option(HelpText = "Prints all messages to standard output.")]
public bool Verbose { get; set; }
[HelpOption]
public string GetUsage()
{
var help = new HelpText();
// ...
if (this.LastParserState.Errors.Any())
{
var errors = help.RenderParsingErrorsText(this, 2); // indent with two spaces
if (!string.IsNullOrEmpty(errors))
{
help.AddPreOptionsLine(string.Concat(Environment.NewLine, "ERROR(S):"));
help.AddPreOptionsLine(errors);
}
}
// ...
return help;
}
}
}

View File

@ -4,9 +4,14 @@ using System.Collections.Generic;
using System.Data.Entity; using System.Data.Entity;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Teknik.Areas.Transparency.Models;
using Teknik.Areas.Upload.Models; using Teknik.Areas.Upload.Models;
using Teknik.Areas.Users.Models;
using Teknik.Areas.Users.Utility;
using Teknik.Configuration; using Teknik.Configuration;
using Teknik.Helpers; using Teknik.Helpers;
using Teknik.Models; using Teknik.Models;
@ -16,26 +21,54 @@ namespace ServerMaint
public class Program public class Program
{ {
private static string currentPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); private static string currentPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
private static string parentPath = Directory.GetParent(currentPath).FullName;
private static string virusFile = Path.Combine(currentPath, "virusLogs.txt"); private static string virusFile = Path.Combine(currentPath, "virusLogs.txt");
private static string errorFile = Path.Combine(currentPath, "errorLogs.txt"); private static string errorFile = Path.Combine(currentPath, "errorLogs.txt");
private static string configPath = Path.Combine(parentPath, "App_Data"); private static string configPath = currentPath;
private const string TAKEDOWN_REPORTER = "Teknik Automated System";
public static event Action<string> OutputEvent; public static event Action<string> OutputEvent;
public static void Main(string[] args) public static int Main(string[] args)
{ {
// Let's clean some stuff!!
try try
{ {
Config config = Config.Load(configPath); ArgumentOptions options = new ArgumentOptions();
TeknikEntities db = new TeknikEntities(); var parser = new CommandLine.Parser(config => config.HelpWriter = Console.Out);
if (parser.ParseArguments(args, options))
// Scan all the uploads for viruses, and remove the bad ones
if (config.UploadConfig.VirusScanEnable)
{ {
ScanUploads(config, db); if (!string.IsNullOrEmpty(options.Config))
configPath = options.Config;
if (Directory.Exists(configPath))
{
Config config = Config.Load(configPath);
TeknikEntities db = new TeknikEntities();
// Scan all the uploads for viruses, and remove the bad ones
if (options.ScanUploads && config.UploadConfig.VirusScanEnable)
{
ScanUploads(config, db);
}
// Cleans all inactive users
if (options.CleanUsers)
{
CleanUsers(config, db, options.DaysBeforeDeletion, options.EmailsToSend);
}
Output(string.Format("[{0}] Finished Server Maintainence Process.", DateTime.Now));
return 0;
}
else
{
string msg = string.Format("[{0}] Config File does not exist.", DateTime.Now);
File.AppendAllLines(errorFile, new List<string> { msg });
Output(msg);
}
}
else
{
Output(options.GetUsage());
} }
} }
catch (Exception ex) catch (Exception ex)
@ -44,6 +77,7 @@ namespace ServerMaint
File.AppendAllLines(errorFile, new List<string> { msg }); File.AppendAllLines(errorFile, new List<string> { msg });
Output(msg); Output(msg);
} }
return -1;
} }
public static void ScanUploads(Config config, TeknikEntities db) public static void ScanUploads(Config config, TeknikEntities db)
@ -87,15 +121,15 @@ namespace ServerMaint
string msg = string.Format("[{0}] Virus Detected: {1} - {2} - {3}", DateTime.Now, upload.Url, upload.FileName, scanResult.InfectedFiles.First().VirusName); string msg = string.Format("[{0}] Virus Detected: {1} - {2} - {3}", DateTime.Now, upload.Url, upload.FileName, scanResult.InfectedFiles.First().VirusName);
File.AppendAllLines(virusFile, new List<string> { msg }); File.AppendAllLines(virusFile, new List<string> { msg });
Output(msg); Output(msg);
//// Delete from the DB // Delete from the DB
//db.Uploads.Remove(upload); db.Uploads.Remove(upload);
//db.SaveChanges(); db.SaveChanges();
//// Delete the File // Delete the File
//if (File.Exists(filePath)) if (File.Exists(filePath))
//{ {
// File.Delete(filePath); File.Delete(filePath);
//} }
break; break;
case ClamScanResults.Error: case ClamScanResults.Error:
string errorMsg = string.Format("[{0}] Scan Error: {1}", DateTime.Now, scanResult.RawResult); string errorMsg = string.Format("[{0}] Scan Error: {1}", DateTime.Now, scanResult.RawResult);
@ -111,9 +145,86 @@ namespace ServerMaint
} }
} }
// Add to transparency report if any were found
Takedown report = db.Takedowns.Create();
report.Requester = TAKEDOWN_REPORTER;
report.RequesterContact = config.SupportEmail;
report.DateRequested = DateTime.Now;
report.Reason = "Malware Found";
report.ActionTaken = string.Format("{0} Uploads removed", totalViruses);
report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report);
db.SaveChanges();
Output(string.Format("Scanning Complete. {0} Scanned | {1} Viruses Found | {2} Total Files", totalScans, totalViruses, totalCount)); Output(string.Format("Scanning Complete. {0} Scanned | {1} Viruses Found | {2} Total Files", totalScans, totalViruses, totalCount));
} }
public static void CleanUsers(Config config, TeknikEntities db, int maxDays, int numEmails)
{
int totalUsers = 0;
List<User> curUsers = db.Users.ToList();
foreach (User user in curUsers)
{
DateTime lastActivity = UserHelper.GetLastActivity(db, config, user);
TimeSpan inactiveTime = DateTime.Now.Subtract(lastActivity);
// If older than max days, delete
if (inactiveTime >= new TimeSpan(maxDays, 0, 0, 0, 0))
{
UserHelper.DeleteUser(db, config, user);
continue;
}
// Otherwise, send an email if they are within +-1 day of email days
int daysForEmail = (int)Math.Floor((double)(maxDays / (numEmails + 1)));
for (int i = daysForEmail; i < maxDays; i = i + daysForEmail)
{
if (inactiveTime.Days == daysForEmail)
{
string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
// Let's send them an email
SmtpClient client = new SmtpClient();
client.Host = config.ContactConfig.Host;
client.Port = config.ContactConfig.Port;
client.EnableSsl = config.ContactConfig.SSL;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = true;
client.Credentials = new NetworkCredential(config.ContactConfig.Username, config.ContactConfig.Password);
client.Timeout = 5000;
MailMessage mail = new MailMessage(config.SupportEmail, email);
mail.Subject = "Inactive Account Notice";
mail.Body = string.Format(@"
The account {0} has not had any activity for {1} days. After {2} days of inactivity, this account will be deleted permanently.
In order to avoid this, login into your email, or teknik website.
Thank you for your use of Teknik and I hope you decide to come back.
- Teknik Administration", user.Username, inactiveTime.Days, maxDays);
mail.BodyEncoding = UTF8Encoding.UTF8;
mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
client.Send(mail);
break;
}
}
}
// Add to transparency report if any users were removed
Takedown report = db.Takedowns.Create();
report.Requester = TAKEDOWN_REPORTER;
report.RequesterContact = config.SupportEmail;
report.DateRequested = DateTime.Now;
report.Reason = "User Inactive";
report.ActionTaken = string.Format("{0} Users Removed", totalUsers);
report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report);
db.SaveChanges();
}
public static void Output(string message) public static void Output(string message)
{ {
Console.WriteLine(message); Console.WriteLine(message);

View File

@ -52,8 +52,12 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL"> <Reference Include="BouncyCastle.Crypto, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath> <HintPath>..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="CommandLine, Version=1.9.71.2, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
@ -77,11 +81,11 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SecurityDriven.Inferno, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="SecurityDriven.Inferno, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Inferno.1.1.0\lib\net451\SecurityDriven.Inferno.dll</HintPath> <HintPath>..\packages\Inferno.1.2.0\lib\net452\SecurityDriven.Inferno.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
@ -94,6 +98,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ArgumentOptions.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
@ -120,12 +125,12 @@
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\GitVersionTask.3.4.1\build\dotnet\GitVersionTask.targets" Condition="Exists('..\packages\GitVersionTask.3.4.1\build\dotnet\GitVersionTask.targets')" /> <Import Project="..\packages\GitVersionTask.3.5.3\build\dotnet\GitVersionTask.targets" Condition="Exists('..\packages\GitVersionTask.3.5.3\build\dotnet\GitVersionTask.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('..\packages\GitVersionTask.3.4.1\build\dotnet\GitVersionTask.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GitVersionTask.3.4.1\build\dotnet\GitVersionTask.targets'))" /> <Error Condition="!Exists('..\packages\GitVersionTask.3.5.3\build\dotnet\GitVersionTask.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GitVersionTask.3.5.3\build\dotnet\GitVersionTask.targets'))" />
</Target> </Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net452" /> <package id="BouncyCastle" version="1.8.1" targetFramework="net452" />
<package id="CommandLineParser" version="1.9.71" targetFramework="net452" />
<package id="EntityFramework" version="6.1.3" targetFramework="net452" /> <package id="EntityFramework" version="6.1.3" targetFramework="net452" />
<package id="GitVersionTask" version="3.4.1" targetFramework="net452" developmentDependency="true" /> <package id="GitVersionTask" version="3.5.3" targetFramework="net452" developmentDependency="true" />
<package id="Inferno" version="1.1.0" targetFramework="net452" /> <package id="Inferno" version="1.2.0" targetFramework="net452" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net452" /> <package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net452" />
<package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net452" /> <package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net452" />
<package id="nClam" version="2.0.6.0" targetFramework="net452" /> <package id="nClam" version="2.0.6.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" /> <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net452" />
</packages> </packages>

View File

@ -18,6 +18,7 @@ using Teknik.Models;
using Teknik.ViewModels; using Teknik.ViewModels;
using System.Windows; using System.Windows;
using System.Net; using System.Net;
using Teknik.Areas.Users.Utility;
namespace Teknik.Areas.Users.Controllers namespace Teknik.Areas.Users.Controllers
{ {
@ -52,7 +53,7 @@ namespace Teknik.Areas.Users.Controllers
model.Email = string.Format("{0}@{1}", user.Username, Config.EmailConfig.Domain); model.Email = string.Format("{0}@{1}", user.Username, Config.EmailConfig.Domain);
} }
model.JoinDate = user.JoinDate; model.JoinDate = user.JoinDate;
model.LastSeen = user.LastSeen; model.LastSeen = UserHelper.GetLastActivity(db, Config, user);
model.UserSettings = user.UserSettings; model.UserSettings = user.UserSettings;
model.BlogSettings = user.BlogSettings; model.BlogSettings = user.BlogSettings;
@ -208,7 +209,7 @@ namespace Teknik.Areas.Users.Controllers
{ {
if (Config.UserConfig.RegistrationEnabled) if (Config.UserConfig.RegistrationEnabled)
{ {
if (Utility.UserHelper.UserExists(db, model.Username)) if (UserHelper.UserExists(db, model.Username))
{ {
return Json(new { error = "That username already exists." }); return Json(new { error = "That username already exists." });
} }
@ -216,51 +217,9 @@ namespace Teknik.Areas.Users.Controllers
{ {
return Json(new { error = "Passwords must match." }); return Json(new { error = "Passwords must match." });
} }
try try
{ {
string email = string.Format("{0}@{1}", model.Username, Config.EmailConfig.Domain);
// If Email Server is enabled
if (Config.EmailConfig.Enabled)
{
// Connect to hmailserver COM
var app = new hMailServer.Application();
app.Connect();
app.Authenticate(Config.EmailConfig.Username, Config.EmailConfig.Password);
var domain = app.Domains.ItemByName[Config.EmailConfig.Domain];
try
{
var account = domain.Accounts.ItemByAddress[email];
return Json(new { error = "That email already exists." });
}
catch { }
// If we got an exception, then the email doesnt exist and we continue on!
var newAccount = domain.Accounts.Add();
newAccount.Address = email;
newAccount.Password = model.Password;
newAccount.Active = true;
newAccount.MaxSize = Config.EmailConfig.MaxSize;
newAccount.Save();
}
// If Git is enabled
if (Config.GitConfig.Enabled)
{
// Add gogs user
using (var client = new WebClient())
{
var obj = new { source_id = Config.GitConfig.SourceId, username = model.Username, email = email, login_name = email, password = model.Password };
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?token=" + Config.GitConfig.AccessToken);
string result = client.UploadString(finalUri, "POST", json);
}
}
// Add User
User newUser = db.Users.Create(); User newUser = db.Users.Create();
newUser.JoinDate = DateTime.Now; newUser.JoinDate = DateTime.Now;
newUser.Username = model.Username; newUser.Username = model.Username;
@ -268,18 +227,12 @@ namespace Teknik.Areas.Users.Controllers
newUser.UserSettings = new UserSettings(); newUser.UserSettings = new UserSettings();
newUser.BlogSettings = new BlogSettings(); newUser.BlogSettings = new BlogSettings();
newUser.UploadSettings = new UploadSettings(); newUser.UploadSettings = new UploadSettings();
db.Users.Add(newUser);
db.SaveChanges();
// Generate blog for the user UserHelper.AddUser(db, Config, newUser, model.Password);
var newBlog = db.Blogs.Create();
newBlog.UserId = newUser.UserId;
db.Blogs.Add(newBlog);
db.SaveChanges();
} }
catch (Exception ex) catch (Exception ex)
{ {
return Json(new { error = "Unable to create the user." }); return Json(new { error = ex.Message });
} }
return Login(new LoginViewModel { Username = model.Username, Password = model.Password, RememberMe = false, ReturnUrl = model.ReturnUrl }); return Login(new LoginViewModel { Username = model.Username, Password = model.Password, RememberMe = false, ReturnUrl = model.ReturnUrl });
} }
@ -293,9 +246,10 @@ namespace Teknik.Areas.Users.Controllers
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
User user = Utility.UserHelper.GetUser(db, User.Identity.Name); User user = UserHelper.GetUser(db, User.Identity.Name);
if (user != null) if (user != null)
{ {
bool changePass = false;
string email = string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain); string email = string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain);
// Changing Password? // Changing Password?
if (!string.IsNullOrEmpty(curPass) && (!string.IsNullOrEmpty(newPass) || !string.IsNullOrEmpty(newPassConfirm))) if (!string.IsNullOrEmpty(curPass) && (!string.IsNullOrEmpty(newPass) || !string.IsNullOrEmpty(newPassConfirm)))
@ -311,37 +265,7 @@ namespace Teknik.Areas.Users.Controllers
return Json(new { error = "New Password Must Match." }); return Json(new { error = "New Password Must Match." });
} }
user.HashedPassword = SHA384.Hash(User.Identity.Name, newPass); user.HashedPassword = SHA384.Hash(User.Identity.Name, newPass);
changePass = true;
// Update Email Pass
if (Config.EmailConfig.Enabled)
{
try
{
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.Password = newPass;
account.Save();
}
catch (COMException)
{ }
}
// Update Git Pass
if (Config.GitConfig.Enabled)
{
using (var client = new WebClient())
{
var obj = new { source_id = Config.GitConfig.SourceId, email = email, password = newPass };
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/" + User.Identity.Name + "?token=" + Config.GitConfig.AccessToken);
string result = client.UploadString(finalUri, "PATCH", json);
}
}
} }
// PGP Key valid? // PGP Key valid?
@ -360,9 +284,7 @@ namespace Teknik.Areas.Users.Controllers
user.UploadSettings.SaveKey = saveKey; user.UploadSettings.SaveKey = saveKey;
user.UploadSettings.ServerSideEncrypt = serverSideEncrypt; user.UploadSettings.ServerSideEncrypt = serverSideEncrypt;
UserHelper.SaveUser(db, Config, user, changePass, newPass);
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return Json(new { result = true }); return Json(new { result = true });
} }
return Json(new { error = "User does not exist" }); return Json(new { error = "User does not exist" });
@ -375,130 +297,17 @@ namespace Teknik.Areas.Users.Controllers
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
if (Config.EmailConfig.Enabled) User user = UserHelper.GetUser(db, User.Identity.Name);
if (user != null)
{ {
try try
{ {
// Delete Email UserHelper.DeleteUser(db, Config, user);
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[string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain)];
if (account != null)
{
account.Delete();
}
}
catch (COMException)
{
}
catch (Exception)
{
return Json(new { error = "Unable to delete email account." });
}
}
// Delete Git
if (Config.GitConfig.Enabled)
{
try
{
Uri baseUri = new Uri(Config.GitConfig.Host);
Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + User.Identity.Name + "?token=" + Config.GitConfig.AccessToken);
WebRequest request = WebRequest.Create(finalUri);
request.Method = "DELETE";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.NotFound && response.StatusCode != HttpStatusCode.OK)
{
return Json(new { error = "Unable to delete git account. Response Code: " + response.StatusCode });
}
}
catch (HttpException htex)
{
if (htex.GetHttpCode() != 404)
return Json(new { error = "Unable to delete git account. Http Exception: " + htex.Message });
} }
catch (Exception ex) catch (Exception ex)
{ {
// This error signifies the user doesn't exist, so we can continue deleting return Json(new { error = ex.Message });
if (ex.Message != "The remote server returned an error: (404) Not Found.")
{
return Json(new { error = "Unable to delete git account. Exception: " + ex.Message });
}
} }
}
// Update uploads
List<Upload.Models.Upload> uploads = db.Uploads.Include("User").Where(u => u.User.Username == User.Identity.Name).ToList();
if (uploads != null)
{
foreach (Upload.Models.Upload upload in uploads)
{
upload.UserId = null;
db.Entry(upload).State = EntityState.Modified;
}
}
// Update pastes
List<Paste.Models.Paste> pastes = db.Pastes.Include("User").Where(u => u.User.Username == User.Identity.Name).ToList();
if (pastes != null)
{
foreach (Paste.Models.Paste paste in pastes)
{
paste.UserId = null;
db.Entry(paste).State = EntityState.Modified;
}
}
// Update shortened urls
List<ShortenedUrl> shortUrls = db.ShortenedUrls.Include("User").Where(u => u.User.Username == User.Identity.Name).ToList();
if (shortUrls != null)
{
foreach (ShortenedUrl shortUrl in shortUrls)
{
shortUrl.UserId = null;
db.Entry(shortUrl).State = EntityState.Modified;
}
}
// Delete Blogs
Blog.Models.Blog blog = db.Blogs.Include("BlogPosts").Include("BlogPosts.Comments").Include("User").Where(u => u.User.Username == User.Identity.Name).FirstOrDefault();
if (blog != null)
{
db.Blogs.Remove(blog);
}
// Delete post comments
List<BlogPostComment> postComments = db.BlogComments.Include("User").Where(u => u.User.Username == User.Identity.Name).ToList();
if (postComments != null)
{
foreach (BlogPostComment postComment in postComments)
{
db.BlogComments.Remove(postComment);
}
}
// Delete post comments
List<Podcast.Models.PodcastComment> podComments = db.PodcastComments.Include("User").Where(u => u.User.Username == User.Identity.Name).ToList();
if (podComments != null)
{
foreach (Podcast.Models.PodcastComment podComment in podComments)
{
db.PodcastComments.Remove(podComment);
}
}
// Delete User
User user = Utility.UserHelper.GetUser(db, User.Identity.Name);
if (user != null)
{
user.UserSettings = db.UserSettings.Find(user.UserId);
user.BlogSettings = db.BlogSettings.Find(user.UserId);
user.UploadSettings = db.UploadSettings.Find(user.UserId);
db.Users.Remove(user);
db.SaveChanges();
// Sign Out // Sign Out
Logout(); Logout();
return Json(new { result = true }); return Json(new { result = true });

View File

@ -1,12 +1,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Entity;
using System.Linq; using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Security; using System.Web.Security;
using Teknik.Areas.Blog.Models;
using Teknik.Areas.Shortener.Models;
using Teknik.Areas.Users.Models; using Teknik.Areas.Users.Models;
using Teknik.Configuration; using Teknik.Configuration;
using Teknik.Helpers;
using Teknik.Models; using Teknik.Models;
namespace Teknik.Areas.Users.Utility namespace Teknik.Areas.Users.Utility
@ -16,6 +22,12 @@ namespace Teknik.Areas.Users.Utility
public static User GetUser(TeknikEntities db, string username) public static User GetUser(TeknikEntities db, string username)
{ {
User user = db.Users.Where(b => b.Username == username).FirstOrDefault(); User user = db.Users.Where(b => b.Username == username).FirstOrDefault();
if (user != null)
{
user.UserSettings = db.UserSettings.Find(user.UserId);
user.BlogSettings = db.BlogSettings.Find(user.UserId);
user.UploadSettings = db.UploadSettings.Find(user.UserId);
}
return user; return user;
} }
@ -31,6 +43,280 @@ namespace Teknik.Areas.Users.Utility
return false; return false;
} }
public static void AddUser(TeknikEntities db, Config config, User user, string password)
{
try
{
string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
// If Email Server is enabled
if (config.EmailConfig.Enabled)
{
// Connect to hmailserver COM
var app = new hMailServer.Application();
app.Connect();
app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
try
{
var account = domain.Accounts.ItemByAddress[email];
throw new Exception("That email already exists.");
}
catch { }
// If we got an exception, then the email doesnt exist and we continue on!
var newAccount = domain.Accounts.Add();
newAccount.Address = email;
newAccount.Password = password;
newAccount.Active = true;
newAccount.MaxSize = config.EmailConfig.MaxSize;
newAccount.Save();
}
// If Git is enabled
if (config.GitConfig.Enabled)
{
// Add gogs user
using (var client = new WebClient())
{
var obj = new { source_id = config.GitConfig.SourceId, username = user.Username, email = email, login_name = email, password = password };
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?token=" + config.GitConfig.AccessToken);
string result = client.UploadString(finalUri, "POST", json);
}
}
// Add User
db.Users.Add(user);
db.SaveChanges();
// Generate blog for the user
var newBlog = db.Blogs.Create();
newBlog.UserId = user.UserId;
db.Blogs.Add(newBlog);
db.SaveChanges();
}
catch (Exception ex)
{
throw new Exception("Unable to create user.", ex);
}
}
public static void SaveUser(TeknikEntities db, Config config, User user, bool changePass, string newPass)
{
string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
// Changing Password?
if (changePass)
{
// Update Email Pass
if (config.EmailConfig.Enabled)
{
try
{
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.Password = newPass;
account.Save();
}
catch (COMException)
{ }
}
// Update Git Pass
if (config.GitConfig.Enabled)
{
using (var client = new WebClient())
{
var obj = new { source_id = config.GitConfig.SourceId, email = email, password = newPass };
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/" + user.Username + "?token=" + config.GitConfig.AccessToken);
string result = client.UploadString(finalUri, "PATCH", json);
}
}
}
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
}
public static void DeleteUser(TeknikEntities db, Config config, User user)
{
// Check to see if we need to delete their email.
if (config.EmailConfig.Enabled)
{
try
{
// Delete Email
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[string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain)];
if (account != null)
{
account.Delete();
}
}
catch (COMException)
{
}
catch (Exception ex)
{
throw new Exception("Unable to delete email account.", ex);
}
}
// Delete Git
if (config.GitConfig.Enabled)
{
try
{
Uri baseUri = new Uri(config.GitConfig.Host);
Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + user.Username + "?token=" + config.GitConfig.AccessToken);
WebRequest request = WebRequest.Create(finalUri);
request.Method = "DELETE";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.NotFound && response.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Unable to delete git account. Response Code: " + response.StatusCode);
}
}
catch (HttpException htex)
{
if (htex.GetHttpCode() != 404)
throw new Exception("Unable to delete git account. Http Exception: " + htex.Message);
}
catch (Exception ex)
{
// This error signifies the user doesn't exist, so we can continue deleting
if (ex.Message != "The remote server returned an error: (404) Not Found.")
{
throw new Exception("Unable to delete git account. Exception: " + ex.Message);
}
}
}
// Update uploads
List<Upload.Models.Upload> uploads = db.Uploads.Include("User").Where(u => u.User.Username == user.Username).ToList();
if (uploads != null)
{
foreach (Upload.Models.Upload upload in uploads)
{
upload.UserId = null;
db.Entry(upload).State = EntityState.Modified;
}
}
// Update pastes
List<Paste.Models.Paste> pastes = db.Pastes.Include("User").Where(u => u.User.Username == user.Username).ToList();
if (pastes != null)
{
foreach (Paste.Models.Paste paste in pastes)
{
paste.UserId = null;
db.Entry(paste).State = EntityState.Modified;
}
}
// Update shortened urls
List<ShortenedUrl> shortUrls = db.ShortenedUrls.Include("User").Where(u => u.User.Username == user.Username).ToList();
if (shortUrls != null)
{
foreach (ShortenedUrl shortUrl in shortUrls)
{
shortUrl.UserId = null;
db.Entry(shortUrl).State = EntityState.Modified;
}
}
// Delete Blogs
Blog.Models.Blog blog = db.Blogs.Include("BlogPosts").Include("BlogPosts.Comments").Include("User").Where(u => u.User.Username == user.Username).FirstOrDefault();
if (blog != null)
{
db.Blogs.Remove(blog);
}
// Delete post comments
List<BlogPostComment> postComments = db.BlogComments.Include("User").Where(u => u.User.Username == user.Username).ToList();
if (postComments != null)
{
foreach (BlogPostComment postComment in postComments)
{
db.BlogComments.Remove(postComment);
}
}
// Delete post comments
List<Podcast.Models.PodcastComment> podComments = db.PodcastComments.Include("User").Where(u => u.User.Username == user.Username).ToList();
if (podComments != null)
{
foreach (Podcast.Models.PodcastComment podComment in podComments)
{
db.PodcastComments.Remove(podComment);
}
}
// Delete User
db.Users.Remove(user);
db.SaveChanges();
}
public static DateTime GetLastActivity(TeknikEntities db, Config config, User user)
{
DateTime lastActive = new DateTime(1900, 1, 1);
string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
if (config.EmailConfig.Enabled)
{
// Connect to hmailserver COM
var app = new hMailServer.Application();
app.Connect();
app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
try
{
var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
var account = domain.Accounts.ItemByAddress[email];
DateTime lastEmail = (DateTime)account.LastLogonTime;
if (lastActive < lastEmail)
lastActive = lastEmail;
}
catch (Exception ex) { }
}
if (config.GitConfig.Enabled)
{
// We need to check the actual git database
MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database);
string sql = @"SELECT MAX(gogs.repository.updated) AS LastUpdate
FROM gogs.repository
INNER JOIN gogs.user
WHERE gogs.user.login_name = {0} AND gogs.user.id = gogs.repository.owner_id";
object result = mySQL.ScalarQuery(sql, new object[] { email });
if (result != null)
{
DateTime tmpLast = lastActive;
DateTime.TryParse(result.ToString(), out tmpLast);
if (lastActive < tmpLast)
lastActive = tmpLast;
}
}
if (lastActive < user.LastSeen)
lastActive = user.LastSeen;
return lastActive;
}
public static HttpCookie CreateAuthCookie(string username, bool remember, string domain, bool local) public static HttpCookie CreateAuthCookie(string username, bool remember, string domain, bool local)
{ {
Config config = Config.Load(); Config config = Config.Load();

View File

@ -73,7 +73,7 @@
<li class="list-group-item text-right"><span class="pull-left"><strong>Joined</strong></span> <time datetime="@Model.LastSeen.ToString("o")">@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("o")">@Model.JoinDate.ToString("MMMM dd, yyyy")</time></li>
@if (OwnProfile && User.Identity.IsAuthenticated) @if (OwnProfile && User.Identity.IsAuthenticated)
{ {
<li class="list-group-item text-right"><span class="pull-left"><strong>Last Seen</strong></span> <time datetime="@Model.LastSeen.ToString("o")">@Model.LastSeen.ToString("MMMM dd, yyyy")</time></li> <li class="list-group-item text-right"><span class="pull-left"><strong>Last Seen</strong></span> <time datetime="@Model.LastSeen.ToString("o")">@Model.LastSeen.ToString("MMMM dd, yyyy hh:mm:ss")</time></li>
} }
@if (!string.IsNullOrEmpty(pgpFingerprint)) @if (!string.IsNullOrEmpty(pgpFingerprint))
{ {

View File

@ -16,12 +16,15 @@ namespace Teknik.Configuration
public int SourceId { get; set; } public int SourceId { get; set; }
public DatabaseConfig Database { get; set; }
public GitConfig() public GitConfig()
{ {
Enabled = true; Enabled = true;
Host = string.Empty; Host = string.Empty;
AccessToken = string.Empty; AccessToken = string.Empty;
SourceId = 1; SourceId = 1;
Database = new DatabaseConfig();
} }
} }
} }

View File

@ -612,6 +612,7 @@
<Folder Include="Areas\TOS\Views\TOS\" /> <Folder Include="Areas\TOS\Views\TOS\" />
<Folder Include="Areas\Transparency\Views\Shared\" /> <Folder Include="Areas\Transparency\Views\Shared\" />
<Folder Include="Areas\Upload\Views\Shared\" /> <Folder Include="Areas\Upload\Views\Shared\" />
<Folder Include="Areas\User\Repositories\" />
<Folder Include="Areas\User\Views\Shared\" /> <Folder Include="Areas\User\Views\Shared\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>