Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
9aa5d21
Added AWS-related settings to appsettings
belmirp Feb 16, 2023
ecd3ce4
Added basic implementation of Amazon SES
belmirp Feb 16, 2023
6593288
Exposed sending email in AdminPanelController for testing purposes
belmirp Feb 16, 2023
d7edf22
Refactored ApplicationStartupService
belmirp Feb 16, 2023
2dd3d81
Exposed endpoint for sending email as HTML in AdminPanelController
belmirp Feb 16, 2023
7712703
Added status and activation GUID to Account model
belmirp Feb 16, 2023
4c0e67f
Added NoReplyEmail to appsettings
belmirp Feb 16, 2023
9f1c404
Formatted appsettings
belmirp Feb 16, 2023
41891d9
Sending activation link on account creation
belmirp Feb 16, 2023
061f8dd
Added WebsiteDomain to development appsettings
belmirp Feb 16, 2023
3101779
Saving account status always
belmirp Feb 16, 2023
cc61671
Added endpoint and method for activating account
belmirp Feb 16, 2023
7b983c9
Added getRouteParamBooleanValue to utilities
belmirp Feb 16, 2023
74bb5dc
Showing alert for activation link after registration
belmirp Feb 16, 2023
a3ad9fe
Changed path for activation link
belmirp Feb 16, 2023
aa33596
Added activation route and component on the frontent
belmirp Feb 16, 2023
8fd986d
Added fields needed for reset password to account
belmirp Feb 18, 2023
494d76c
Added RateLimitService
belmirp Feb 18, 2023
b42b55f
Added initiate reset password methods to backend
belmirp Feb 18, 2023
88d43eb
Added NotFoundException and RateLimitExceededException to ErrorsContr…
belmirp Feb 18, 2023
703c08d
Added Forgot Password page on frontend
belmirp Feb 18, 2023
a8656c7
Added ResetPassword methods and UI components
belmirp Feb 18, 2023
4cbc651
Reverted WebsitePort settings
belmirp Feb 18, 2023
2c8ba5a
Hiding components when reset password completes
belmirp Feb 18, 2023
111fdfa
Merged master
belmirp Feb 19, 2023
58f385f
Reverted deleted endpoints after merge
belmirp Feb 19, 2023
772073b
Added ability to resend activation link
belmirp Feb 19, 2023
58e80e2
Merge branch 'master' into aws-ses-implementation
belmirp Feb 19, 2023
4ab43f5
Changed code to string for HttpError
belmirp Feb 20, 2023
e588e2d
Changed logic for parsing query string
belmirp Feb 20, 2023
c816003
Removed unnecessary utility function
belmirp Feb 20, 2023
08ef845
Fixed casting for query variables
belmirp Feb 21, 2023
db5599b
Merge branch 'master' into aws-ses-implementation
belmirp Feb 21, 2023
43cad17
Added AccountActivationException specific for activate account flow
belmirp Feb 21, 2023
dd939aa
Refactored activate account to be POST request instead of GET
belmirp Feb 21, 2023
e81b8e2
Refactored resend activation link flow to use POST instead of GET req…
belmirp Feb 21, 2023
218706c
Changed initiate reset password flow to use POST instead of GET request
belmirp Feb 21, 2023
241483e
Renamed IResendActivationLink to IResendActivationLinkRequest
belmirp Feb 21, 2023
8113873
Renamed reset-password.ts to reset-password-request.ts
belmirp Feb 21, 2023
a8b3b8e
Standardized naming for master server error responses
belmirp Feb 21, 2023
394ea9a
Fixed how query strings are validated
belmirp Feb 21, 2023
c922aa1
Merge pull request #201 from belmirp/aws-ses-implementation
caseyswilliams Feb 21, 2023
a10b67b
Cleanup
caseyswilliams Feb 21, 2023
fb80e13
Added CleanupService for deleting account and all of its related data
belmirp Feb 22, 2023
2e33c8b
Changed method name
belmirp Feb 22, 2023
84356d3
Added domain check in ValidateEmail method to block disallowed domains
belmirp Feb 22, 2023
bfa485a
Fixed logs
belmirp Feb 22, 2023
6eb105e
Returning BadRequest instead of Conflict when data is not valid
belmirp Feb 22, 2023
ab7c96c
Added trailing comma
belmirp Feb 22, 2023
901203f
Merge pull request #204 from caseyswilliams/account-improvements
timiimit Feb 22, 2023
7ae5913
Merge pull request #207 from belmirp/email-domain-checking
timiimit Feb 22, 2023
403847b
Removed unnecessary check for list
belmirp Feb 23, 2023
e48a500
Merge pull request #205 from belmirp/account-cleanup
timiimit Feb 23, 2023
c203060
Fixed condition for removing non-activated accounts
belmirp Feb 24, 2023
4bbbdfb
Setting account to non-verified upon registration
belmirp Feb 25, 2023
ea0b90d
Updated logic for activating an account to use bitwise operations
belmirp Feb 25, 2023
bac5a3c
Changed variable for lambda
belmirp Feb 25, 2023
f5e212c
Changed logic for fetching non-activated accounts
belmirp Feb 25, 2023
5ef8785
Changed wording from Activated to Verified
belmirp Feb 25, 2023
c0fdd47
Changed filter for resending activation link
belmirp Feb 25, 2023
2587262
Changed filter for initiating password reset
belmirp Feb 25, 2023
6f11def
Removed status field from account
belmirp Feb 25, 2023
fd2b412
Removed publicGuard from ActivateAccount and ResendActivation routes
belmirp Mar 1, 2023
0350ffd
Added EmailVerified to Role enum
belmirp Mar 1, 2023
3f59444
Displaying "Click here to go to the login page" only when user is not…
belmirp Mar 1, 2023
94311fe
Extended IAccountExtended interface with additional fields
belmirp Mar 1, 2023
dc25a62
Added logic for sending verification email on PlayerCard component
belmirp Mar 1, 2023
da0073f
Changed wording from Activate to Verify
belmirp Mar 1, 2023
0b39181
Removed ResendActivation component and route
belmirp Mar 1, 2023
588e9b0
Changed alert message and type when verification link is sent and ema…
belmirp Mar 1, 2023
d78c773
Fixed linter errors
belmirp Mar 1, 2023
45c9c71
Requiring email verification after changing email
belmirp Mar 1, 2023
54f5917
Merge pull request #211 from timiimit/verified-flag
belmirp Mar 4, 2023
c92088a
Added layer of abstraction to email service
belmirp Mar 4, 2023
a93ff1a
Merge branch 'master' into account-improvements
belmirp Mar 4, 2023
d2c32ac
Merge branch 'account-improvements' of https://github.com/timiimit/UT…
belmirp Mar 4, 2023
c4e8ecc
Merge branch 'account-improvements' into email-service-improvements
belmirp Mar 4, 2023
10e40cf
Merge pull request #212 from timiimit/email-service-improvements
belmirp Mar 6, 2023
e094f0a
Merge master
timiimit May 9, 2024
edce0bd
Normalize line endings in `AdminPanelController`
timiimit May 9, 2024
a9bc32b
Fix formatting in `ErrorsController`
timiimit May 9, 2024
f86a9b9
Fix formatting and remove using in `Program.cs`
timiimit May 9, 2024
0e81273
Renamed AccountActivationException to EmailVerificationException
May 21, 2024
397a76e
Updated WebsiteDomain comment
May 21, 2024
0c66540
Added example for NoReplyEmail settings
May 21, 2024
a9408bc
Increased filter for non-verified accounts to 3 months
May 21, 2024
e093bdf
Validating no-reply email and website application settings
May 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions UT4MasterServer.Common/Enums/AccountFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,10 @@ public enum AccountFlags
/// </summary>
ACL_Maintenance = 0x1000,

/// <summary>
/// Flag to determine if email was verified
/// </summary>
EmailVerified = 0x2000,

/// NOTE: if you add more flags, make sure to update <see cref="AccountFlagsHelper"/> checks.
}
13 changes: 13 additions & 0 deletions UT4MasterServer.Common/Exceptions/AwsSesClientException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace UT4MasterServer.Common.Exceptions;

[Serializable]
public sealed class AwsSesClientException : Exception
{
public AwsSesClientException(string message) : base(message)
{
}

public AwsSesClientException(string message, Exception innerException) : base(message, innerException)
{
}
}
14 changes: 14 additions & 0 deletions UT4MasterServer.Common/Exceptions/EmailVerificationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace UT4MasterServer.Common.Exceptions;

[Serializable]
public sealed class EmailVerificationException : Exception
{
public EmailVerificationException(string message) : base(message)
{
}

public EmailVerificationException(string message, Exception innerException) : base(message, innerException)
{
}
}

13 changes: 13 additions & 0 deletions UT4MasterServer.Common/Exceptions/NotFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace UT4MasterServer.Common.Exceptions;

[Serializable]
public sealed class NotFoundException : Exception
{
public NotFoundException(string message) : base(message)
{
}

public NotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
13 changes: 13 additions & 0 deletions UT4MasterServer.Common/Exceptions/RateLimitExceededException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace UT4MasterServer.Common.Exceptions;

[Serializable]
public sealed class RateLimitExceededException : Exception
{
public RateLimitExceededException(string message) : base(message)
{
}

public RateLimitExceededException(string message, Exception innerException) : base(message, innerException)
{
}
}
3 changes: 2 additions & 1 deletion UT4MasterServer.Common/Helpers/AccountFlagsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static bool IsACLFlag(AccountFlags flag)
AccountFlags.ACL_CloudStorageAnnouncements |
AccountFlags.ACL_CloudStorageRulesets |
AccountFlags.ACL_CloudStorageChallenges |
AccountFlags.ACL_Maintenance);
AccountFlags.ACL_Maintenance |
AccountFlags.EmailVerified);
}
}
103 changes: 102 additions & 1 deletion UT4MasterServer.Common/Helpers/ValidationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public static class ValidationHelper
{
private static readonly Regex regexEmail;
private static readonly List<string> disallowedUsernameWords;
private static readonly List<string> disallowedEmailDomains;

static ValidationHelper()
{
Expand All @@ -17,6 +18,99 @@ static ValidationHelper()
"shit", "fuck", "bitch", "slut", "sex", "cum",
"nigger", "hitler", "nazi"
};
disallowedEmailDomains = new List<string>
{
"yopmail.com",
"maildrop.cc",
"dispostable.com",
"guerrillamail.com",
"mailinator.com",
"tempr.email",
"discard.email",
"discardmail.com",
"discardmail.de",
"spambog.com",
"spambog.de",
"spambog.ru",
"0815.ru",
"knol-power.nl",
"freundin.ru",
"smashmail.de",
"s0ny.net",
"1mail.x24hr.com",
"from.onmypc.info",
"now.mefound.com",
"mowgli.jungleheart.com",
"cr.cloudns.asia",
"tls.cloudns.asia",
"msft.cloudns.asia",
"b.cr.cloudns.asia",
"ssl.tls.cloudns.asia",
"sweetxxx.de",
"dvd.dns-cloud.net",
"dvd.dnsabr.com",
"bd.dns-cloud.net",
"yx.dns-cloud.net",
"shit.dns-cloud.net",
"shit.dnsabr.com",
"eu.dns-cloud.net",
"eu.dnsabr.com",
"asia.dnsabr.com",
"8.dnsabr.com",
"pw.8.dnsabr.com",
"mm.8.dnsabr.com",
"23.8.dnsabr.com",
"pw.epac.to",
"postheo.de",
"sexy.camdvr.org",
"888.dns-cloud.net",
"adult-work.info",
"trap-mail.de",
"m.cloudns.cl",
"t.woeishyang.com",
"pflege-schoene-haut.de",
"streamboost.xyz",
"okmail.p-e.kr",
"hotbird.giize.com",
"as10.dnsfree.com",
"mehr-bitcoin.de",
"a1b2.cloudns.ph",
"wacamole.soynashi.tk",
"temp69.email",
"secure.okay.email.safeds.tk",
"tajba.com",
"web.run.place",
"tempr-mail.line.pm",
"spam.ceo",
"healthydevelopimmune.com",
"infobisnisdigital.com",
"winayabeauty.com",
"nxyl.eu",
"edukansassu12a.cf",
"mail.checkermaker.me",
"mailcatch.com",
"emailondeck.com",
"mailnesia.com",
"superrito.com",
"armyspy.com",
"cuvox.de",
"dayrep.com",
"einrot.com",
"fleckens.hu",
"gustr.com",
"jourrapide.com",
"rhyta.com",
"superrito.com",
"teleworm.us",
"mintemail.com",
"bbitq.com",
"iucake.com",
"gufum.com",
"boxmail.lol",
"nfstripss.com",
"dropjar.com",
"33mail.com",
};
}

public static bool ValidateEmail(string email)
Expand All @@ -26,7 +120,14 @@ public static bool ValidateEmail(string email)
return false;
}

return regexEmail.IsMatch(email);
if (!regexEmail.IsMatch(email))
return false;

var emailDomain = email.ToLower().Split('@')[1];
if (disallowedEmailDomains.Contains(emailDomain))
return false;

return true;
}

public static bool ValidateUsername(string username)
Expand Down
9 changes: 9 additions & 0 deletions UT4MasterServer.Models/DTO/Request/SendEmailRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace UT4MasterServer.Models.DTO.Request;

public sealed class SendEmailRequest
{
public string From { get; set; } = string.Empty;
public List<string> To { get; set; } = new();
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
}
12 changes: 12 additions & 0 deletions UT4MasterServer.Models/Database/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ public class Account
[BsonElement("Flags")]
public AccountFlags Flags { get; set; } = 0;

[BsonIgnoreIfNull]
public string? VerificationLinkGUID { get; set; }

[BsonIgnoreIfNull]
public DateTime? VerificationLinkExpiration { get; set; }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make more sense to have something like LastEmailChangeAt because that gives more information and control than just having expiry date.

LastEmailChangeAt can be set to null when not needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These properties come in pair: GUID + ExpirationDate. Not sure if changing will help now because I used term "verification link" all over the place.


[BsonIgnoreIfNull]
public string? ResetLinkGUID { get; set; }

[BsonIgnoreIfNull]
public DateTime? ResetLinkExpiration { get; set; }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And something like LastPasswordChangeAt here.

LastPasswordChangeAt can be set to null when not needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These properties come in pair: GUID + ExpirationDate. Not sure if changing will help now because I used term "reset password" all over the place.


[BsonIgnore]
public float Level
{
Expand Down
8 changes: 8 additions & 0 deletions UT4MasterServer.Models/Settings/AWSSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace UT4MasterServer.Models.Settings;

public sealed class AWSSettings
{
public string AccessKey { get; set; } = string.Empty;
public string SecretKey { get; set; } = string.Empty;
public string RegionName { get; set; } = string.Empty;
}
22 changes: 20 additions & 2 deletions UT4MasterServer.Models/Settings/ApplicationSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace UT4MasterServer.Models.Settings;
namespace UT4MasterServer.Models.Settings;

public sealed class ApplicationSettings
{
Expand All @@ -11,10 +11,22 @@ public sealed class ApplicationSettings
public bool AllowPasswordGrantType { get; set; } = false;

/// <summary>
/// Used just to redirect users to correct domain when UT4UU is being used.
/// Used for URL generation when sending activation link, reset links, etc.
/// </summary>
public string WebsiteScheme { get; set; } = string.Empty;

/// <summary>
/// Used for
/// - email verification links
/// - reset password links
/// </summary>
public string WebsiteDomain { get; set; } = string.Empty;

/// <summary>
/// Used for URL generation when sending activation link, reset links, etc.
/// </summary>
public int WebsitePort { get; set; } = -1;

/// <summary>
/// File containing a list of trusted proxy servers (one per line).
/// This file is loaded only once when program starts and it add values to <see cref="ProxyServers"/>.
Expand All @@ -30,4 +42,10 @@ public sealed class ApplicationSettings
/// IP addresses of trusted proxy servers.
/// </summary>
public List<string> ProxyServers { get; set; } = new List<string>();

/// <summary>
/// No-reply email that will be used for activation links, reset password links, etc
/// </summary>
/// <example>no-reply@example.com</example>
public string NoReplyEmail { get; set; } = string.Empty;
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ private void DoWork(object? state)
logger.LogInformation("Background task deleted {DeleteCount} stale game servers.", deleteCount);
}

var cleanupService = scope.ServiceProvider.GetRequiredService<CleanupService>();
await cleanupService.RemoveNonVerifiedAccountsAsync();

await DeleteOldStatisticsAsync(scope);
await MergeOldStatisticsAsync(scope);
});
Expand Down
33 changes: 13 additions & 20 deletions UT4MasterServer.Services/Hosted/ApplicationStartupService.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using UT4MasterServer.Models.Settings;
using UT4MasterServer.Services.Scoped;

namespace UT4MasterServer.Services.Hosted;

public sealed class ApplicationStartupService : IHostedService
{
private readonly ILogger<ApplicationStartupService> logger;
private readonly AccountService accountService;
private readonly StatisticsService statisticsService;
private readonly CloudStorageService cloudStorageService;
private readonly ClientService clientService;
private readonly RatingsService ratingsService;

public ApplicationStartupService(
ILogger<ApplicationStartupService> logger,
ILogger<StatisticsService> statsLogger,
IOptions<ApplicationSettings> settings,
ILogger<CloudStorageService> cloudStorageLogger,
ILogger<RatingsService> ratingsLogger)
private readonly IServiceProvider serviceProvider;

public ApplicationStartupService(ILogger<ApplicationStartupService> logger, IServiceProvider serviceProvider)
{
this.logger = logger;
var db = new DatabaseContext(settings);
accountService = new AccountService(db, settings);
statisticsService = new StatisticsService(statsLogger, db);
cloudStorageService = new CloudStorageService(db, cloudStorageLogger);
clientService = new ClientService(db);
ratingsService = new RatingsService(ratingsLogger, db);
this.serviceProvider = serviceProvider;
}

public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = serviceProvider.CreateScope();

var accountService = scope.ServiceProvider.GetRequiredService<AccountService>();
var statisticsService = scope.ServiceProvider.GetRequiredService<StatisticsService>();
var ratingsService = scope.ServiceProvider.GetRequiredService<RatingsService>();
var cloudStorageService = scope.ServiceProvider.GetRequiredService<CloudStorageService>();
var clientService = scope.ServiceProvider.GetRequiredService<ClientService>();

logger.LogInformation("Configuring MongoDB indexes.");
await accountService.CreateIndexesAsync();
await statisticsService.CreateIndexesAsync();
Expand Down
7 changes: 7 additions & 0 deletions UT4MasterServer.Services/Interfaces/IEmailService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace UT4MasterServer.Services.Interfaces;

public interface IEmailService
{
Task SendTextEmailAsync(string fromAddress, List<string> toAddresses, string subject, string body);
Task SendHTMLEmailAsync(string fromAddress, List<string> toAddresses, string subject, string body);
}
Loading