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

Added filter label for human readable explanation.

Separated Username Cleaning logic.
Updated Thunderbird auth method.
This commit is contained in:
Uncled1023 2016-05-19 16:17:08 -07:00
parent bd55b29de9
commit ee3f7d8ee2
6 changed files with 225 additions and 88 deletions

View File

@ -43,6 +43,18 @@ namespace ServerMaint
[Option('f', "last-seen-file", Required = false, HelpText = "The file in which you want the last seen stats to be saved to")] [Option('f', "last-seen-file", Required = false, HelpText = "The file in which you want the last seen stats to be saved to")]
public string LastSeenFile { get; set; } public string LastSeenFile { get; set; }
[Option('i', "invalid", DefaultValue = false, Required = false, HelpText = "Generate a list of invalid accounts")]
public bool GenerateInvalid { get; set; }
[Option('t', "invalid-file", Required = false, HelpText = "The file in which you want the invalid accounts to be saved to")]
public string InvalidFile { get; set; }
[Option('o', "to-clean", DefaultValue = false, Required = false, HelpText = "Generate a list of accounts to be cleaned")]
public bool GenerateCleaning { get; set; }
[Option('n', "to-clean-file", Required = false, HelpText = "The file in which you want the accounts to be cleaned to be saved to")]
public string CleaningFile { get; set; }
// Omitting long name, default --verbose // Omitting long name, default --verbose
[Option(HelpText = "Prints all messages to standard output.")] [Option(HelpText = "Prints all messages to standard output.")]
public bool Verbose { get; set; } public bool Verbose { get; set; }

View File

@ -83,6 +83,18 @@ namespace ServerMaint
GenerateLastSeen(config, db, options.LastSeenFile); GenerateLastSeen(config, db, options.LastSeenFile);
} }
// Generates a file for all of the invalid accounts
if (options.GenerateInvalid)
{
GenerateInvalidAccounts(config, db, options.InvalidFile);
}
// Generates a file for all of the accounts to be cleaned
if (options.GenerateCleaning)
{
GenerateCleaningList(config, db, options.CleaningFile, options.DaysBeforeDeletion);
}
Output(string.Format("[{0}] Finished Server Maintenance Process.", DateTime.Now)); Output(string.Format("[{0}] Finished Server Maintenance Process.", DateTime.Now));
return 0; return 0;
} }
@ -217,7 +229,7 @@ namespace ServerMaint
mail.Body = string.Format(@" mail.Body = string.Format(@"
The account {0} does not meet the requirements for a valid username. The account {0} does not meet the requirements for a valid username.
The username must match the following Regex Pattern: {1} The username must meet the following requirements: {1}
It must also be greater than or equal to {2} characters in length, and less than or equal to {3} characters in length. It must also be greater than or equal to {2} characters in length, and less than or equal to {3} characters in length.
This email is to let you know that this account will be deleted in {4} days ({5}) in order to comply with the username restrictions. If you would like to keep your data, you should create a new account and transfer the data over to the new account. This email is to let you know that this account will be deleted in {4} days ({5}) in order to comply with the username restrictions. If you would like to keep your data, you should create a new account and transfer the data over to the new account.
@ -226,7 +238,7 @@ In order to make the process as easy as possible, you can reply to this email to
Thank you for your continued use of Teknik! Thank you for your continued use of Teknik!
- Teknik Administration", account, config.UserConfig.UsernameFilter, config.UserConfig.MinUsernameLength, config.UserConfig.MaxUsernameLength, 30, DateTime.Now.AddDays(30).ToShortDateString(), 15, DateTime.Now.AddDays(15).ToShortDateString()); - Teknik Administration", account, config.UserConfig.UsernameFilterLabel, config.UserConfig.MinUsernameLength, config.UserConfig.MaxUsernameLength, 30, DateTime.Now.AddDays(30).ToShortDateString(), 15, DateTime.Now.AddDays(15).ToShortDateString());
mail.BodyEncoding = UTF8Encoding.UTF8; mail.BodyEncoding = UTF8Encoding.UTF8;
mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never; mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
@ -286,35 +298,16 @@ Thank you for your continued use of Teknik!
} }
public static void CleanEmail(Config config, TeknikEntities db) public static void CleanEmail(Config config, TeknikEntities db)
{
if (config.EmailConfig.Enabled)
{ {
Output(string.Format("[{0}] Started Cleaning of Orphaned Email Accounts.", DateTime.Now)); Output(string.Format("[{0}] Started Cleaning of Orphaned Email Accounts.", DateTime.Now));
List<User> curUsers = db.Users.ToList(); List<string> emails = GetOrphanedEmail(config, db);
int totalAccounts = 0; foreach (string email in emails)
// 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];
var accounts = domain.Accounts;
for (int i = 0; i < accounts.Count; i++)
{
var account = accounts[i];
bool userExists = curUsers.Exists(u => UserHelper.GetUserEmailAddress(config, u.Username) == account.Address);
bool isReserved = UserHelper.GetReservedUsernames(config).Exists(r => UserHelper.GetUserEmailAddress(config, r).ToLower() == account.Address.ToLower());
if (!userExists && !isReserved)
{ {
// User doesn't exist, and it isn't reserved. Let's nuke it. // User doesn't exist, and it isn't reserved. Let's nuke it.
UserHelper.DeleteUserEmail(config, account.Address); UserHelper.DeleteUserEmail(config, email);
totalAccounts++;
}
} }
if (totalAccounts > 0) if (emails.Count > 0)
{ {
// Add to transparency report if any users were removed // Add to transparency report if any users were removed
Takedown report = db.Takedowns.Create(); Takedown report = db.Takedowns.Create();
@ -322,44 +315,26 @@ Thank you for your continued use of Teknik!
report.RequesterContact = config.SupportEmail; report.RequesterContact = config.SupportEmail;
report.DateRequested = DateTime.Now; report.DateRequested = DateTime.Now;
report.Reason = "Orphaned Email Account"; report.Reason = "Orphaned Email Account";
report.ActionTaken = string.Format("{0} Accounts Removed", totalAccounts); report.ActionTaken = string.Format("{0} Accounts Removed", emails.Count);
report.DateActionTaken = DateTime.Now; report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report); db.Takedowns.Add(report);
db.SaveChanges(); db.SaveChanges();
} }
Output(string.Format("[{0}] Finished Cleaning of Orphaned Email Accounts. {1} Accounts Removed.", DateTime.Now, totalAccounts)); Output(string.Format("[{0}] Finished Cleaning of Orphaned Email Accounts. {1} Accounts Removed.", DateTime.Now, emails.Count));
}
} }
public static void CleanGit(Config config, TeknikEntities db) public static void CleanGit(Config config, TeknikEntities db)
{
if (config.GitConfig.Enabled)
{ {
Output(string.Format("[{0}] Started Cleaning of Orphaned Git Accounts.", DateTime.Now)); Output(string.Format("[{0}] Started Cleaning of Orphaned Git Accounts.", DateTime.Now));
List<User> curUsers = db.Users.ToList(); List<string> gitAccounts = GetOrphanedGit(config, db);
int totalAccounts = 0; foreach (string account in gitAccounts)
// We need to check the actual git database
MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database);
string sql = @"SELECT gogs.user.login_name AS login_name, gogs.user.lower_name AS username FROM gogs.user";
var results = mySQL.Query(sql);
if (results != null && results.Any())
{ {
foreach (var account in results) // User doesn't exist, and it isn't reserved. Let's nuke it.
{ UserHelper.DeleteUserGit(config, account);
bool userExists = curUsers.Exists(u => UserHelper.GetUserEmailAddress(config, u.Username).ToLower() == account["login_name"].ToString().ToLower());
bool isReserved = UserHelper.GetReservedUsernames(config).Exists(r => UserHelper.GetUserEmailAddress(config, r) == account["login_name"].ToString().ToLower());
if (!userExists && !isReserved)
{
UserHelper.DeleteUserGit(config, account["username"].ToString());
totalAccounts++;
}
}
} }
if (totalAccounts > 0) if (gitAccounts.Count > 0)
{ {
// Add to transparency report if any users were removed // Add to transparency report if any users were removed
Takedown report = db.Takedowns.Create(); Takedown report = db.Takedowns.Create();
@ -367,14 +342,13 @@ Thank you for your continued use of Teknik!
report.RequesterContact = config.SupportEmail; report.RequesterContact = config.SupportEmail;
report.DateRequested = DateTime.Now; report.DateRequested = DateTime.Now;
report.Reason = "Orphaned Git Account"; report.Reason = "Orphaned Git Account";
report.ActionTaken = string.Format("{0} Accounts Removed", totalAccounts); report.ActionTaken = string.Format("{0} Accounts Removed", gitAccounts.Count);
report.DateActionTaken = DateTime.Now; report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report); db.Takedowns.Add(report);
db.SaveChanges(); db.SaveChanges();
} }
Output(string.Format("[{0}] Finished Cleaning of Orphaned Git Accounts. {1} Accounts Removed.", DateTime.Now, totalAccounts)); Output(string.Format("[{0}] Finished Cleaning of Orphaned Git Accounts. {1} Accounts Removed.", DateTime.Now, gitAccounts.Count));
}
} }
public static void GenerateLastSeen(Config config, TeknikEntities db, string fileName) public static void GenerateLastSeen(Config config, TeknikEntities db, string fileName)
@ -401,15 +375,107 @@ Thank you for your continued use of Teknik!
Output(string.Format("[{0}] Finished Generating Last Activity List.", DateTime.Now)); Output(string.Format("[{0}] Finished Generating Last Activity List.", DateTime.Now));
} }
public static void GenerateInvalidAccounts(Config config, TeknikEntities db, string fileName)
{
Output(string.Format("[{0}] Started Generation of Invalid Account List.", DateTime.Now));
List<string> invalidAccounts = GetInvalidAccounts(config, db);
StringBuilder sb = new StringBuilder();
sb.AppendLine("Username,Last Activity,Creation Date,Last Website Activity,Last Email Activity,Last Git Activity");
foreach (string account in invalidAccounts)
{
User user = UserHelper.GetUser(db, account);
sb.AppendLine(string.Format("{0},{1},{2},{3},{4},{5}",
user.Username,
UserHelper.GetLastAccountActivity(db, config, user).ToString("g"),
user.JoinDate.ToString("g"),
user.LastSeen.ToString("g"),
UserHelper.UserEmailLastActive(config, UserHelper.GetUserEmailAddress(config, user.Username)).ToString("g"),
UserHelper.UserGitLastActive(config, user.Username).ToString("g")));
}
string dir = Path.GetDirectoryName(fileName);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
File.WriteAllText(fileName, sb.ToString());
Output(string.Format("[{0}] Finished Generating Invalid Account List.", DateTime.Now));
}
public static void GenerateCleaningList(Config config, TeknikEntities db, string fileName, int maxDays)
{
Output(string.Format("[{0}] Started Generation of Accounts to Clean List.", DateTime.Now));
List<string> invalidAccounts = GetInvalidAccounts(config, db);
List<string> inactiveAccounts = GetInactiveAccounts(config, db, maxDays);
List<string> emailAccounts = GetOrphanedEmail(config, db);
List<string> gitAccounts = GetOrphanedGit(config, db);
StringBuilder sb = new StringBuilder();
sb.AppendLine("Invalid Account Cleaning");
sb.AppendLine("Username,Last Activity,Creation Date,Last Website Activity,Last Email Activity,Last Git Activity");
foreach (string account in invalidAccounts)
{
User user = UserHelper.GetUser(db, account);
sb.AppendLine(string.Format("{0},{1},{2},{3},{4},{5}",
user.Username,
UserHelper.GetLastAccountActivity(db, config, user).ToString("g"),
user.JoinDate.ToString("g"),
user.LastSeen.ToString("g"),
UserHelper.UserEmailLastActive(config, UserHelper.GetUserEmailAddress(config, user.Username)).ToString("g"),
UserHelper.UserGitLastActive(config, user.Username).ToString("g")));
}
sb.AppendLine();
sb.AppendLine("Inactive Account Cleaning");
sb.AppendLine("Username,Last Activity,Creation Date,Last Website Activity,Last Email Activity,Last Git Activity");
foreach (string account in inactiveAccounts)
{
User user = UserHelper.GetUser(db, account);
sb.AppendLine(string.Format("{0},{1},{2},{3},{4},{5}",
user.Username,
UserHelper.GetLastAccountActivity(db, config, user).ToString("g"),
user.JoinDate.ToString("g"),
user.LastSeen.ToString("g"),
UserHelper.UserEmailLastActive(config, UserHelper.GetUserEmailAddress(config, user.Username)).ToString("g"),
UserHelper.UserGitLastActive(config, user.Username).ToString("g")));
}
sb.AppendLine();
sb.AppendLine("Orphaned Email Cleaning");
sb.AppendLine("Email,Last Activity");
foreach (string account in emailAccounts)
{
sb.AppendLine(string.Format("{0},{1}",
account,
UserHelper.UserEmailLastActive(config, account).ToString("g")));
}
sb.AppendLine();
sb.AppendLine("Orphaned Git Cleaning");
sb.AppendLine("Username,Last Activity");
foreach (string account in gitAccounts)
{
sb.AppendLine(string.Format("{0},{1}",
account,
UserHelper.UserGitLastActive(config, account).ToString("g")));
}
string dir = Path.GetDirectoryName(fileName);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
File.WriteAllText(fileName, sb.ToString());
Output(string.Format("[{0}] Finished Generating Accounts to Clean List.", DateTime.Now));
}
public static List<string> GetInvalidAccounts(Config config, TeknikEntities db) public static List<string> GetInvalidAccounts(Config config, TeknikEntities db)
{ {
List<string> foundUsers = new List<string>(); List<string> foundUsers = new List<string>();
List<User> curUsers = db.Users.ToList(); List<User> curUsers = db.Users.ToList();
foreach (User user in curUsers) foreach (User user in curUsers)
{ {
// If the username is reserved, don't worry about it // If the username is reserved, let's add it to the list
if (UserHelper.UsernameReserved(config, user.Username)) if (UserHelper.UsernameReserved(config, user.Username))
{ {
foundUsers.Add(user.Username);
continue; continue;
} }
@ -500,6 +566,63 @@ Thank you for your continued use of Teknik!
return foundUsers; return foundUsers;
} }
public static List<string> GetOrphanedEmail(Config config, TeknikEntities db)
{
List<string> foundEmail = new List<string>();
if (config.EmailConfig.Enabled)
{
List<User> curUsers = db.Users.ToList();
// 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];
var accounts = domain.Accounts;
for (int i = 0; i < accounts.Count; i++)
{
var account = accounts[i];
bool userExists = curUsers.Exists(u => UserHelper.GetUserEmailAddress(config, u.Username) == account.Address);
bool isReserved = UserHelper.GetReservedUsernames(config).Exists(r => UserHelper.GetUserEmailAddress(config, r).ToLower() == account.Address.ToLower());
if (!userExists && !isReserved)
{
foundEmail.Add(account.Address);
}
}
}
return foundEmail;
}
public static List<string> GetOrphanedGit(Config config, TeknikEntities db)
{
List<string> foundGit = new List<string>();
if (config.GitConfig.Enabled)
{
List<User> curUsers = db.Users.ToList();
// We need to check the actual git database
MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database);
string sql = @"SELECT gogs.user.login_name AS login_name, gogs.user.lower_name AS username FROM gogs.user";
var results = mySQL.Query(sql);
if (results != null && results.Any())
{
foreach (var account in results)
{
bool userExists = curUsers.Exists(u => UserHelper.GetUserEmailAddress(config, u.Username).ToLower() == account["login_name"].ToString().ToLower());
bool isReserved = UserHelper.GetReservedUsernames(config).Exists(r => UserHelper.GetUserEmailAddress(config, r) == account["login_name"].ToString().ToLower());
if (!userExists && !isReserved)
{
foundGit.Add(account["username"].ToString());
}
}
}
}
return foundGit;
}
public static void Output(string message) public static void Output(string message)
{ {
Console.WriteLine(message); Console.WriteLine(message);

View File

@ -49,7 +49,7 @@
<li class="list-group-item">Port:<div class="pull-right"><b>143 (993 SSL)</b></div></li> <li class="list-group-item">Port:<div class="pull-right"><b>143 (993 SSL)</b></div></li>
<li class="list-group-item">User Name:<div class="pull-right"><b>@string.Format("[username]@{0}", Model.Config.EmailConfig.Domain)</b></div></li> <li class="list-group-item">User Name:<div class="pull-right"><b>@string.Format("[username]@{0}", Model.Config.EmailConfig.Domain)</b></div></li>
<li class="list-group-item">Connection Security:<div class="pull-right"><b>None (SSL/TLS)</b></div></li> <li class="list-group-item">Connection Security:<div class="pull-right"><b>None (SSL/TLS)</b></div></li>
<li class="list-group-item">Authentication method:<div class="pull-right"><b>Password</b></div></li> <li class="list-group-item">Authentication method:<div class="pull-right"><b>Normal Password</b></div></li>
</ul> </ul>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
@ -59,7 +59,7 @@
<li class="list-group-item">Port:<div class="pull-right"><b>25 (465 SSL)</b></div></li> <li class="list-group-item">Port:<div class="pull-right"><b>25 (465 SSL)</b></div></li>
<li class="list-group-item">User Name:<div class="pull-right"><b>@string.Format("[username]@{0}", Model.Config.EmailConfig.Domain)</b></div></li> <li class="list-group-item">User Name:<div class="pull-right"><b>@string.Format("[username]@{0}", Model.Config.EmailConfig.Domain)</b></div></li>
<li class="list-group-item">Connection Security:<div class="pull-right"><b>None (SSL/TLS)</b></div></li> <li class="list-group-item">Connection Security:<div class="pull-right"><b>None (SSL/TLS)</b></div></li>
<li class="list-group-item">Authentication method:<div class="pull-right"><b>Password</b></div></li> <li class="list-group-item">Authentication method:<div class="pull-right"><b>Normal Password</b></div></li>
</ul> </ul>
</div> </div>
</ul> </ul>

View File

@ -13,7 +13,7 @@
<li>Any Malware uploads or otherwise hosted/linked content will be removed without notice.</li> <li>Any Malware uploads or otherwise hosted/linked content will be removed without notice.</li>
<li>Email is limited to a maximum of 100 outbound email messages per day. This is to prevent spam accounts. If your account is flagged as spamming, it will be deleted without notice.</li> <li>Email is limited to a maximum of 100 outbound email messages per day. This is to prevent spam accounts. If your account is flagged as spamming, it will be deleted without notice.</li>
<li>Copyrighted content will be removed only after a valid DMCA is recieved and verified.</li> <li>Copyrighted content will be removed only after a valid DMCA is recieved and verified.</li>
<li>Inactive Accounts with no data will be deleted after 180 days. <li>Inactive Accounts with no data will be deleted after 365 days (1 Year).
<ul> <ul>
<li>Activity is defined as logging into the Teknik Website, into the Git website, into the mail service (Either through webmail or via another client), or Modifying/Adding a Git Repository.</li> <li>Activity is defined as logging into the Teknik Website, into the Git website, into the mail service (Either through webmail or via another client), or Modifying/Adding a Git Repository.</li>
<li>Data is defined as Blog Posts/Comments, Podcast Comments, Emails, and Git Repositories.</li> <li>Data is defined as Blog Posts/Comments, Podcast Comments, Emails, and Git Repositories.</li>
@ -24,7 +24,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-10"> <div class="col-xs-10">
<p><i>Last Modified May 18, 2016</i></p> <p><i>Last Modified May 19, 2016</i></p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@
</div> </div>
<p class="text-center"> <p class="text-center">
<small> <small>
Username must match the following pattern <var>@Model.Config.UserConfig.UsernameFilter</var><br /> Username must meet the following requirements: <var>@Model.Config.UserConfig.UsernameFilterLabel</var><br />
and the length must be greater than <b>@Model.Config.UserConfig.MinUsernameLength</b> and less than <b>@Model.Config.UserConfig.MaxUsernameLength</b> characters and the length must be greater than <b>@Model.Config.UserConfig.MinUsernameLength</b> and less than <b>@Model.Config.UserConfig.MaxUsernameLength</b> characters
</small> </small>
</p> </p>

View File

@ -11,6 +11,7 @@ namespace Teknik.Configuration
public bool RegistrationEnabled { get; set; } public bool RegistrationEnabled { get; set; }
public bool LoginEnabled { get; set; } public bool LoginEnabled { get; set; }
public string UsernameFilter { get; set; } public string UsernameFilter { get; set; }
public string UsernameFilterLabel { get; set; }
public int MinUsernameLength { get; set; } public int MinUsernameLength { get; set; }
public int MaxUsernameLength { get; set; } public int MaxUsernameLength { get; set; }
public string ReservedUsernameDefinitionFile { get; set; } public string ReservedUsernameDefinitionFile { get; set; }
@ -20,6 +21,7 @@ namespace Teknik.Configuration
RegistrationEnabled = true; RegistrationEnabled = true;
LoginEnabled = true; LoginEnabled = true;
UsernameFilter = "^[a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*$"; UsernameFilter = "^[a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*$";
UsernameFilterLabel = "AlphaNumeric Characters with Dashes, Underlines, and 0-1 Periods not in the beginning or end.";
MinUsernameLength = 1; MinUsernameLength = 1;
MaxUsernameLength = 35; MaxUsernameLength = 35;
ReservedUsernameDefinitionFile = string.Empty; ReservedUsernameDefinitionFile = string.Empty;