Browse Source

Added filter label for human readable explanation.

Separated Username Cleaning logic.
Updated Thunderbird auth method.
tags/2.0.3
Teknikode 3 years ago
parent
commit
ee3f7d8ee2

+ 12
- 0
ServerMaint/ArgumentOptions.cs 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")]
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
[Option(HelpText = "Prints all messages to standard output.")]
public bool Verbose { get; set; }

+ 204
- 81
ServerMaint/Program.cs View File

@@ -83,6 +83,18 @@ namespace ServerMaint
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));
return 0;
}
@@ -217,7 +229,7 @@ namespace ServerMaint
mail.Body = string.Format(@"
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.

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!

- 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.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;

@@ -287,94 +299,56 @@ Thank you for your continued use of Teknik!

public static void CleanEmail(Config config, TeknikEntities db)
{
if (config.EmailConfig.Enabled)
Output(string.Format("[{0}] Started Cleaning of Orphaned Email Accounts.", DateTime.Now));
List<string> emails = GetOrphanedEmail(config, db);
foreach (string email in emails)
{
Output(string.Format("[{0}] Started Cleaning of Orphaned Email Accounts.", DateTime.Now));
List<User> curUsers = db.Users.ToList();
int totalAccounts = 0;

// 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.
UserHelper.DeleteUserEmail(config, account.Address);
totalAccounts++;
}
}

if (totalAccounts > 0)
{
// 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 = "Orphaned Email Account";
report.ActionTaken = string.Format("{0} Accounts Removed", totalAccounts);
report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report);
db.SaveChanges();
}
// User doesn't exist, and it isn't reserved. Let's nuke it.
UserHelper.DeleteUserEmail(config, email);
}

Output(string.Format("[{0}] Finished Cleaning of Orphaned Email Accounts. {1} Accounts Removed.", DateTime.Now, totalAccounts));
if (emails.Count > 0)
{
// 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 = "Orphaned Email Account";
report.ActionTaken = string.Format("{0} Accounts Removed", emails.Count);
report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report);
db.SaveChanges();
}

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)
{
if (config.GitConfig.Enabled)
Output(string.Format("[{0}] Started Cleaning of Orphaned Git Accounts.", DateTime.Now));
List<string> gitAccounts = GetOrphanedGit(config, db);
foreach (string account in gitAccounts)
{
Output(string.Format("[{0}] Started Cleaning of Orphaned Git Accounts.", DateTime.Now));
List<User> curUsers = db.Users.ToList();
int totalAccounts = 0;

// 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)
{
UserHelper.DeleteUserGit(config, account["username"].ToString());
totalAccounts++;
}
}
}

if (totalAccounts > 0)
{
// 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 = "Orphaned Git Account";
report.ActionTaken = string.Format("{0} Accounts Removed", totalAccounts);
report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report);
db.SaveChanges();
}
// User doesn't exist, and it isn't reserved. Let's nuke it.
UserHelper.DeleteUserGit(config, account);
}

Output(string.Format("[{0}] Finished Cleaning of Orphaned Git Accounts. {1} Accounts Removed.", DateTime.Now, totalAccounts));
if (gitAccounts.Count > 0)
{
// 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 = "Orphaned Git Account";
report.ActionTaken = string.Format("{0} Accounts Removed", gitAccounts.Count);
report.DateActionTaken = DateTime.Now;
db.Takedowns.Add(report);
db.SaveChanges();
}

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)
@@ -401,15 +375,107 @@ Thank you for your continued use of Teknik!
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)
{
List<string> foundUsers = new List<string>();
List<User> curUsers = db.Users.ToList();
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))
{
foundUsers.Add(user.Username);
continue;
}

@@ -500,6 +566,63 @@ Thank you for your continued use of Teknik!
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)
{
Console.WriteLine(message);

+ 2
- 2
Teknik/Areas/Help/Views/Help/Mail.cshtml 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">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">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>
</div>
<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">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">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>
</div>
</ul>

+ 2
- 2
Teknik/Areas/TOS/Views/TOS/Index.cshtml View File

@@ -13,7 +13,7 @@
<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>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>
<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>
@@ -24,7 +24,7 @@
</div>
<div class="row">
<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>

+ 1
- 1
Teknik/Areas/User/Views/User/Register.cshtml View File

@@ -20,7 +20,7 @@
</div>
<p class="text-center">
<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
</small>
</p>

+ 2
- 0
Teknik/Configuration/UserConfig.cs View File

@@ -11,6 +11,7 @@ namespace Teknik.Configuration
public bool RegistrationEnabled { get; set; }
public bool LoginEnabled { get; set; }
public string UsernameFilter { get; set; }
public string UsernameFilterLabel { get; set; }
public int MinUsernameLength { get; set; }
public int MaxUsernameLength { get; set; }
public string ReservedUsernameDefinitionFile { get; set; }
@@ -20,6 +21,7 @@ namespace Teknik.Configuration
RegistrationEnabled = true;
LoginEnabled = true;
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;
MaxUsernameLength = 35;
ReservedUsernameDefinitionFile = string.Empty;

Loading…
Cancel
Save