forked from collabvm/CollabVMAuthServer
Compare commits
No commits in common. "master" and "master" have entirely different histories.
12 changed files with 6 additions and 302 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -398,4 +398,3 @@ FodyWeavers.xsd
|
||||||
*.sln.iml
|
*.sln.iml
|
||||||
.idea/
|
.idea/
|
||||||
config.toml
|
config.toml
|
||||||
CollabVMAuthServer/rockyou.txt
|
|
||||||
|
|
|
@ -5,6 +5,4 @@ public class LoginPayload
|
||||||
public string username { get; set; }
|
public string username { get; set; }
|
||||||
public string password { get; set; }
|
public string password { get; set; }
|
||||||
public string? captchaToken { get; set; }
|
public string? captchaToken { get; set; }
|
||||||
public string? turnstileToken { get; set; }
|
|
||||||
public string? recaptchaToken { get; set; }
|
|
||||||
}
|
}
|
|
@ -6,7 +6,5 @@ public class RegisterPayload
|
||||||
public string password { get; set; }
|
public string password { get; set; }
|
||||||
public string email { get; set; }
|
public string email { get; set; }
|
||||||
public string? captchaToken { get; set; }
|
public string? captchaToken { get; set; }
|
||||||
public string? turnstileToken { get; set; }
|
|
||||||
public string? recaptchaToken { get; set; }
|
|
||||||
public string dateOfBirth { get; set; }
|
public string dateOfBirth { get; set; }
|
||||||
}
|
}
|
|
@ -5,6 +5,4 @@ public class SendResetEmailPayload
|
||||||
public string email { get; set; }
|
public string email { get; set; }
|
||||||
public string username { get; set; }
|
public string username { get; set; }
|
||||||
public string? captchaToken { get; set; }
|
public string? captchaToken { get; set; }
|
||||||
public string? turnstileToken { get; set; }
|
|
||||||
public string? recaptchaToken { get; set; }
|
|
||||||
}
|
}
|
|
@ -4,24 +4,9 @@ public class AuthServerInformation
|
||||||
{
|
{
|
||||||
public bool registrationOpen { get; set; }
|
public bool registrationOpen { get; set; }
|
||||||
public AuthServerInformationCaptcha hcaptcha { get; set; }
|
public AuthServerInformationCaptcha hcaptcha { get; set; }
|
||||||
public AuthServerInformationTurnstile turnstile { get; set; }
|
|
||||||
public AuthServerInformationReCAPTCHA recaptcha { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthServerInformationCaptcha
|
public class AuthServerInformationCaptcha
|
||||||
{
|
|
||||||
public bool required { get; set; }
|
|
||||||
public string? siteKey { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AuthServerInformationTurnstile
|
|
||||||
{
|
|
||||||
public bool required { get; set; }
|
|
||||||
public string? siteKey { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AuthServerInformationReCAPTCHA
|
|
||||||
{
|
{
|
||||||
public bool required { get; set; }
|
public bool required { get; set; }
|
||||||
public string? siteKey { get; set; }
|
public string? siteKey { get; set; }
|
||||||
|
|
|
@ -99,55 +99,6 @@ public static class Routes
|
||||||
}, Utilities.JsonSerializerOptions);
|
}, Utilities.JsonSerializerOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Turnstile response
|
|
||||||
if (Program.Config.Turnstile.Enabled)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(payload.turnstileToken))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new SendResetEmailResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Missing Turnstile token"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
var result = await Program.Turnstile!.Verify(payload.turnstileToken, ip.ToString());
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new SendResetEmailResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Invalid Turnstile response"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check reCAPTCHA response
|
|
||||||
if (Program.Config.ReCAPTCHA.Enabled)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(payload.recaptchaToken))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new SendResetEmailResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Missing reCAPTCHA token"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
var result = await Program.ReCAPTCHA!.Verify(payload.recaptchaToken, ip.ToString());
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new SendResetEmailResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Invalid reCAPTCHA response"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check username and E-Mail
|
// Check username and E-Mail
|
||||||
var user = await Program.Database.GetUser(payload.username);
|
var user = await Program.Database.GetUser(payload.username);
|
||||||
if (user == null || user.Email != payload.email)
|
if (user == null || user.Email != payload.email)
|
||||||
|
@ -765,56 +716,6 @@ public static class Routes
|
||||||
}, Utilities.JsonSerializerOptions);
|
}, Utilities.JsonSerializerOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check Turnstile response
|
|
||||||
if (Program.Config.Turnstile.Enabled)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(payload.turnstileToken))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new LoginResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Missing Turnstile token"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
var result = await Program.Turnstile!.Verify(payload.turnstileToken, ip.ToString());
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new LoginResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Invalid Turnstile response"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check reCAPTCHA response
|
|
||||||
if (Program.Config.ReCAPTCHA.Enabled)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(payload.recaptchaToken))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new LoginResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Missing reCAPTCHA token"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
var result = await Program.ReCAPTCHA!.Verify(payload.recaptchaToken, ip.ToString());
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new LoginResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Invalid reCAPTCHA response"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate username and password
|
// Validate username and password
|
||||||
var user = await Program.Database.GetUser(payload.username);
|
var user = await Program.Database.GetUser(payload.username);
|
||||||
if (user == null || !Argon2.Verify(user.Password, payload.password))
|
if (user == null || !Argon2.Verify(user.Password, payload.password))
|
||||||
|
@ -1035,56 +936,6 @@ public static class Routes
|
||||||
}, Utilities.JsonSerializerOptions);
|
}, Utilities.JsonSerializerOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check Turnstile response
|
|
||||||
if (Program.Config.Turnstile.Enabled)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(payload.turnstileToken))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new RegisterResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Missing Turnstile token"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
var result = await Program.Turnstile!.Verify(payload.turnstileToken, ip.ToString());
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new RegisterResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Invalid Turnstile response"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check reCAPTCHA response
|
|
||||||
if (Program.Config.ReCAPTCHA.Enabled)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(payload.recaptchaToken))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new RegisterResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Missing reCAPTCHA token"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
var result = await Program.ReCAPTCHA!.Verify(payload.recaptchaToken, ip.ToString());
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 400;
|
|
||||||
return Results.Json(new RegisterResponse
|
|
||||||
{
|
|
||||||
success = false,
|
|
||||||
error = "Invalid reCAPTCHA response"
|
|
||||||
}, Utilities.JsonSerializerOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure username isn't taken
|
// Make sure username isn't taken
|
||||||
var user = await Program.Database.GetUser(payload.username);
|
var user = await Program.Database.GetUser(payload.username);
|
||||||
if (user != null || await Program.Database.GetBot(payload.username) != null)
|
if (user != null || await Program.Database.GetBot(payload.username) != null)
|
||||||
|
@ -1223,21 +1074,7 @@ public static class Routes
|
||||||
new() {
|
new() {
|
||||||
required = Program.Config.hCaptcha.Enabled,
|
required = Program.Config.hCaptcha.Enabled,
|
||||||
siteKey = Program.Config.hCaptcha.Enabled ? Program.Config.hCaptcha.SiteKey : null
|
siteKey = Program.Config.hCaptcha.Enabled ? Program.Config.hCaptcha.SiteKey : null
|
||||||
},
|
}
|
||||||
|
|
||||||
turnstile =
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
required = Program.Config.Turnstile.Enabled,
|
|
||||||
siteKey = Program.Config.Turnstile.Enabled ? Program.Config.Turnstile.SiteKey : null
|
|
||||||
},
|
|
||||||
|
|
||||||
recaptcha =
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
required = Program.Config.ReCAPTCHA.Enabled,
|
|
||||||
siteKey = Program.Config.ReCAPTCHA.Enabled ? Program.Config.ReCAPTCHA.SiteKey : null
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,8 +9,7 @@ public class IConfig
|
||||||
public MySQLConfig MySQL { get; set; }
|
public MySQLConfig MySQL { get; set; }
|
||||||
public SMTPConfig SMTP { get; set; }
|
public SMTPConfig SMTP { get; set; }
|
||||||
public hCaptchaConfig hCaptcha { get; set; }
|
public hCaptchaConfig hCaptcha { get; set; }
|
||||||
public TurnstileConfig Turnstile { get; set; }
|
|
||||||
public ReCAPTCHAConfig ReCAPTCHA { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RegistrationConfig
|
public class RegistrationConfig
|
||||||
|
@ -62,20 +61,6 @@ public class SMTPConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
public class hCaptchaConfig
|
public class hCaptchaConfig
|
||||||
{
|
|
||||||
public bool Enabled { get; set; }
|
|
||||||
public string? Secret { get; set; }
|
|
||||||
public string? SiteKey { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TurnstileConfig
|
|
||||||
{
|
|
||||||
public bool Enabled { get; set; }
|
|
||||||
public string? Secret { get; set; }
|
|
||||||
public string? SiteKey { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ReCAPTCHAConfig
|
|
||||||
{
|
{
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
public string? Secret { get; set; }
|
public string? Secret { get; set; }
|
||||||
|
|
|
@ -10,8 +10,6 @@ public class Program
|
||||||
public static IConfig Config { get; private set; }
|
public static IConfig Config { get; private set; }
|
||||||
public static Database Database { get; private set; }
|
public static Database Database { get; private set; }
|
||||||
public static hCaptchaClient? hCaptcha { get; private set; }
|
public static hCaptchaClient? hCaptcha { get; private set; }
|
||||||
public static TurnstileClient? Turnstile { get; private set; }
|
|
||||||
public static ReCAPTCHAClient? ReCAPTCHA { get; private set; }
|
|
||||||
public static Mailer? Mailer { get; private set; }
|
public static Mailer? Mailer { get; private set; }
|
||||||
public static string[] BannedPasswords { get; set; }
|
public static string[] BannedPasswords { get; set; }
|
||||||
public static readonly Random Random = new Random();
|
public static readonly Random Random = new Random();
|
||||||
|
@ -77,28 +75,6 @@ public class Program
|
||||||
{
|
{
|
||||||
Utilities.Log(LogLevel.INFO, "hCaptcha disabled");
|
Utilities.Log(LogLevel.INFO, "hCaptcha disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Turnstile client
|
|
||||||
if (Config.Turnstile.Enabled)
|
|
||||||
{
|
|
||||||
Turnstile = new TurnstileClient(Config.Turnstile.Secret!);
|
|
||||||
Utilities.Log(LogLevel.INFO, "Turnstile enabled");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utilities.Log(LogLevel.INFO, "Turnstile disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create reCAPTCHA client
|
|
||||||
if (Config.ReCAPTCHA.Enabled)
|
|
||||||
{
|
|
||||||
ReCAPTCHA = new ReCAPTCHAClient(Config.ReCAPTCHA.Secret!);
|
|
||||||
Utilities.Log(LogLevel.INFO, "reCAPTCHA enabled");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utilities.Log(LogLevel.INFO, "reCAPTCHA disabled");
|
|
||||||
}
|
|
||||||
// load password list
|
// load password list
|
||||||
BannedPasswords = await File.ReadAllLinesAsync("rockyou.txt");
|
BannedPasswords = await File.ReadAllLinesAsync("rockyou.txt");
|
||||||
// Configure web server
|
// Configure web server
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Computernewb.CollabVMAuthServer;
|
|
||||||
|
|
||||||
public class ReCAPTCHAClient(string secret)
|
|
||||||
{
|
|
||||||
private string secret = secret;
|
|
||||||
private HttpClient http = new HttpClient();
|
|
||||||
|
|
||||||
public async Task<ReCAPTCHAResponse> Verify(string token, string ip)
|
|
||||||
{
|
|
||||||
var response = await http.PostAsync("https://www.google.com/recaptcha/api/siteverify", new FormUrlEncodedContent(new []
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>("secret", secret),
|
|
||||||
new KeyValuePair<string, string>("response", token),
|
|
||||||
new KeyValuePair<string, string>("remoteip", ip),
|
|
||||||
}));
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return await response.Content.ReadFromJsonAsync<ReCAPTCHAResponse>() ?? throw new Exception("Failed to parse reCAPTCHA response");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ReCAPTCHAResponse
|
|
||||||
{
|
|
||||||
public bool success { get; set; }
|
|
||||||
public string challenge_ts { get; set; }
|
|
||||||
public string hostname { get; set; }
|
|
||||||
[JsonPropertyName("error-codes")]
|
|
||||||
public string[]? error_codes { get; set; }
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Computernewb.CollabVMAuthServer;
|
|
||||||
|
|
||||||
public class TurnstileClient(string secret)
|
|
||||||
{
|
|
||||||
private string secret = secret;
|
|
||||||
private HttpClient http = new HttpClient();
|
|
||||||
|
|
||||||
public async Task<TurnstileResponse> Verify(string token, string ip)
|
|
||||||
{
|
|
||||||
var response = await http.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify", new FormUrlEncodedContent(new []
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>("secret", secret),
|
|
||||||
new KeyValuePair<string, string>("response", token),
|
|
||||||
new KeyValuePair<string, string>("remoteip", ip),
|
|
||||||
}));
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return await response.Content.ReadFromJsonAsync<TurnstileResponse>() ?? throw new Exception("Failed to parse Turnstile response");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TurnstileResponse
|
|
||||||
{
|
|
||||||
public bool success { get; set; }
|
|
||||||
public string challenge_ts { get; set; }
|
|
||||||
public string hostname { get; set; }
|
|
||||||
[JsonPropertyName("error-codes")]
|
|
||||||
public string[]? error_codes { get; set; }
|
|
||||||
}
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
|
||||||
namespace Computernewb.CollabVMAuthServer;
|
namespace Computernewb.CollabVMAuthServer;
|
||||||
|
|
||||||
|
|
|
@ -54,20 +54,18 @@ FromEmail = "noreply@example.com"
|
||||||
# The subject and body of the E-Mail sent to users when they need to verify their E-Mail address.
|
# The subject and body of the E-Mail sent to users when they need to verify their E-Mail address.
|
||||||
VerificationCodeSubject = "CollabVM Account Verification"
|
VerificationCodeSubject = "CollabVM Account Verification"
|
||||||
VerificationCodeBody = """
|
VerificationCodeBody = """
|
||||||
Hello! Someone (probably you) has tried to create a CollabVM account with this E-Mail. If this was you, your verification code is: $CODE
|
Howdy! Someone (probably you) has tried to create a CollabVM account with this E-Mail. If this was you, your verification code is: $CODE
|
||||||
|
|
||||||
If this was not you, someone probably entered your e-mail by mistake. If this is the case, you can safely ignore this e-mail.
|
If this was not you, someone probably entered your e-mail by mistake. If this is the case, you can safely ignore this e-mail.
|
||||||
"""
|
"""
|
||||||
# The subject and body of the E-Mail sent to users when they need to reset their password.
|
# The subject and body of the E-Mail sent to users when they need to reset their password.
|
||||||
ResetPasswordSubject = "CollabVM Password Reset"
|
ResetPasswordSubject = "CollabVM Password Reset"
|
||||||
ResetPasswordBody = """
|
ResetPasswordBody = """
|
||||||
Hello, $USERNAME! Someone (probably you) has sent a request to reset the password to your CollabVM account with this E-Mail. If this was you, your verification code is: $CODE
|
Howdy, $USERNAME! Someone (probably you) has sent a request to reset the password to your CollabVM account with this E-Mail. If this was you, your verification code is: $CODE
|
||||||
|
|
||||||
If this was not you, disregard this E-Mail and your password will remain unchanged. Do not share this code with anyone.
|
If this was not you, disregard this E-Mail and your password will remain unchanged. Do not share this code with anyone.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Note: You can have multiple CAPTCHA providers enabled at the same time.
|
|
||||||
|
|
||||||
[hCaptcha]
|
[hCaptcha]
|
||||||
# If true, hCaptcha will be used for the registration, login, and password reset forms.
|
# If true, hCaptcha will be used for the registration, login, and password reset forms.
|
||||||
Enabled = false
|
Enabled = false
|
||||||
|
@ -75,16 +73,4 @@ Enabled = false
|
||||||
Secret = ""
|
Secret = ""
|
||||||
SiteKey = ""
|
SiteKey = ""
|
||||||
|
|
||||||
[Turnstile]
|
|
||||||
# If true, Turnstile will be used for the registration, login, and password reset forms.
|
|
||||||
Enabled = false
|
|
||||||
# The Turnstile site key and secret key.
|
|
||||||
Secret = ""
|
|
||||||
SiteKey = ""
|
|
||||||
|
|
||||||
[ReCAPTCHA]
|
|
||||||
# If true, reCAPTCHA will be used for the registration, login, and password reset forms.
|
|
||||||
Enabled = false
|
|
||||||
# The reCAPTCHA site key and secret key.
|
|
||||||
Secret = ""
|
|
||||||
SiteKey = ""
|
|
Loading…
Reference in a new issue