diff --git a/src/Nullinside.Api.Model/Shared/UserHelpers.cs b/src/Nullinside.Api.Model/Shared/UserHelpers.cs
new file mode 100644
index 0000000..c67c72f
--- /dev/null
+++ b/src/Nullinside.Api.Model/Shared/UserHelpers.cs
@@ -0,0 +1,85 @@
+using System.Security.Cryptography;
+
+using Microsoft.EntityFrameworkCore;
+
+using Nullinside.Api.Common;
+using Nullinside.Api.Model.Ddl;
+
+namespace Nullinside.Api.Model.Shared;
+
+///
+/// Helper methods for user functions in the database.
+///
+public static class UserHelpers {
+ ///
+ /// Generates a new bearer token, saves it to the database, and returns it.
+ ///
+ /// The database context.
+ /// The email address of the user, user will be created if they don't already exist.
+ /// The cancellation token.
+ /// The authorization token for twitch, if applicable.
+ /// The refresh token for twitch, if applicable.
+ /// The expiration date of the token for twitch, if applicable.
+ /// The bearer token if successful, null otherwise.
+ public static async Task GetTokenAndSaveToDatabase(NullinsideContext dbContext, string email, CancellationToken token = new(), string? authToken = null, string? refreshToken = null, DateTime? expires = null) {
+ string bearerToken = GenerateBearerToken();
+ try {
+ User? existing = await dbContext.Users.FirstOrDefaultAsync(u => u.Email == email, token);
+ if (null == existing) {
+ dbContext.Users.Add(new User {
+ Email = email,
+ Token = bearerToken,
+ TwitchToken = authToken,
+ TwitchRefreshToken = refreshToken,
+ TwitchTokenExpiration = expires,
+ UpdatedOn = DateTime.UtcNow,
+ CreatedOn = DateTime.UtcNow
+ });
+
+ await dbContext.SaveChangesAsync(token);
+
+ existing = await dbContext.Users.FirstOrDefaultAsync(u => u.Email == email, token);
+ if (null == existing) {
+ return null;
+ }
+
+ dbContext.UserRoles.Add(new UserRole {
+ Role = UserRoles.User,
+ UserId = existing.Id,
+ RoleAdded = DateTime.UtcNow
+ });
+ }
+ else {
+ existing.Token = bearerToken;
+ existing.TwitchToken = authToken;
+ existing.TwitchRefreshToken = refreshToken;
+ existing.TwitchTokenExpiration = expires;
+ existing.UpdatedOn = DateTime.UtcNow;
+ }
+
+ await dbContext.SaveChangesAsync(token);
+ return bearerToken;
+ }
+ catch {
+ return null;
+ }
+ }
+
+ ///
+ /// Generates a new unique bearer token.
+ ///
+ /// A bearer token.
+ public static string GenerateBearerToken() {
+ // This method is trash but it doesn't matter. We should be doing real OAuth tokens with expirations and
+ // renewals. Right now nothing that exists on the site requires this level of sophistication.
+ string allowed = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789";
+ int strlen = 255; // Or whatever
+ char[] randomChars = new char[strlen];
+
+ for (int i = 0; i < strlen; i++) {
+ randomChars[i] = allowed[RandomNumberGenerator.GetInt32(0, allowed.Length)];
+ }
+
+ return new string(randomChars);
+ }
+}
\ No newline at end of file
diff --git a/src/Nullinside.Api/Controllers/UserController.cs b/src/Nullinside.Api/Controllers/UserController.cs
index e723153..bf6480b 100644
--- a/src/Nullinside.Api/Controllers/UserController.cs
+++ b/src/Nullinside.Api/Controllers/UserController.cs
@@ -1,5 +1,4 @@
using System.Security.Claims;
-using System.Security.Cryptography;
using Google.Apis.Auth;
@@ -7,9 +6,9 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
-using Nullinside.Api.Common;
using Nullinside.Api.Model;
using Nullinside.Api.Model.Ddl;
+using Nullinside.Api.Model.Shared;
using Nullinside.Api.Shared;
using Nullinside.Api.Shared.Json;
@@ -66,7 +65,7 @@ public async Task Login([FromForm] GoogleOpenIdToken creds, Cance
return Redirect($"{siteUrl}/user/login?error=1");
}
- string? bearerToken = await GetTokenAndSaveToDatabase(credentials.Email, token);
+ string? bearerToken = await UserHelpers.GetTokenAndSaveToDatabase(_dbContext, credentials.Email, token);
if (string.IsNullOrWhiteSpace(bearerToken)) {
return Redirect($"{siteUrl}/user/login?error=2");
}
@@ -107,7 +106,7 @@ public async Task TwitchLogin([FromQuery] string code, Cancellati
return Redirect($"{siteUrl}/user/login?error=4");
}
- string? bearerToken = await GetTokenAndSaveToDatabase(email, token);
+ string? bearerToken = await UserHelpers.GetTokenAndSaveToDatabase(_dbContext, email, token);
if (string.IsNullOrWhiteSpace(bearerToken)) {
return Redirect($"{siteUrl}/user/login?error=2");
}
@@ -115,59 +114,6 @@ public async Task TwitchLogin([FromQuery] string code, Cancellati
return Redirect($"{siteUrl}/user/login?token={bearerToken}");
}
- ///
- /// Generates a new bearer token, saves it to the database, and returns it.
- ///
- /// The email address of the user, user will be created if they don't already exist.
- /// The cancellation token.
- /// The authorization token for twitch, if applicable.
- /// The refresh token for twitch, if applicable.
- /// The expiration date of the token for twitch, if applicable.
- /// The bearer token if successful, null otherwise.
- private async Task GetTokenAndSaveToDatabase(string email, CancellationToken token = new(), string? authToken = null, string? refreshToken = null, DateTime? expires = null) {
- string bearerToken = GenerateBearerToken();
- try {
- User? existing = await _dbContext.Users.FirstOrDefaultAsync(u => u.Email == email, token);
- if (null == existing) {
- _dbContext.Users.Add(new User {
- Email = email,
- Token = bearerToken,
- TwitchToken = authToken,
- TwitchRefreshToken = refreshToken,
- TwitchTokenExpiration = expires,
- UpdatedOn = DateTime.UtcNow,
- CreatedOn = DateTime.UtcNow
- });
-
- await _dbContext.SaveChangesAsync(token);
-
- existing = await _dbContext.Users.FirstOrDefaultAsync(u => u.Email == email, token);
- if (null == existing) {
- return null;
- }
-
- _dbContext.UserRoles.Add(new UserRole {
- Role = UserRoles.User,
- UserId = existing.Id,
- RoleAdded = DateTime.UtcNow
- });
- }
- else {
- existing.Token = bearerToken;
- existing.TwitchToken = authToken;
- existing.TwitchRefreshToken = refreshToken;
- existing.TwitchTokenExpiration = expires;
- existing.UpdatedOn = DateTime.UtcNow;
- }
-
- await _dbContext.SaveChangesAsync(token);
- return bearerToken;
- }
- catch {
- return null;
- }
- }
-
///
/// Gets the roles of the current user.
///
@@ -209,22 +155,4 @@ public async Task Validate(AuthToken token) {
return StatusCode(500);
}
}
-
- ///
- /// Generates a new unique bearer token.
- ///
- /// A bearer token.
- private static string GenerateBearerToken() {
- // This method is trash but it doesn't matter. We should be doing real OAuth tokens with expirations and
- // renewals. Right now nothing that exists on the site requires this level of sophistication.
- string allowed = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789";
- int strlen = 255; // Or whatever
- char[] randomChars = new char[strlen];
-
- for (int i = 0; i < strlen; i++) {
- randomChars[i] = allowed[RandomNumberGenerator.GetInt32(0, allowed.Length)];
- }
-
- return new string(randomChars);
- }
}
\ No newline at end of file