mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 15:38:45 -07:00
feat(auth): external sign-in for the website and admin panel
Players sign in to the website, and admins to the admin panel, with an OpenID Connect provider (DorkNet:SignIn:*). The first sign-in links the provider identity (issuer + subject) to a DorkNet account with that account's password; after that the provider sign-in is enough. - Cookie sessions per host, keys persisted in the database so redeploys keep people signed in; unlink, deletion or a ban ends the session. - Link attempts limited to 5 failures per 15 minutes per identity and per username. - Admin panel: "Sign in with ..." exchanges the session for the usual admin tokens via GET /api/admin/v1/sso (IsAdmin still required). - Downloads: optional DorkNet:Downloads:RequireSignIn serves the manifest and files only to signed-in players; the Downloads and Quest pages offer sign-in instead. - Website: sign-in in the header, /link and /account pages. The game client's login is unchanged.
This commit is contained in:
@@ -151,6 +151,7 @@ public static class DatabaseBootstrap
|
||||
// idempotent raw SQL that works on a fresh DB too (CREATE TABLE
|
||||
// IF NOT EXISTS no-ops when EnsureCreated already built them).
|
||||
await EnsureSignupCodeTablesAsync(db);
|
||||
await EnsureExternalSignInTablesAsync(db);
|
||||
await EnsureServerSettingsColumnsAsync(db);
|
||||
await EnsureCharadesWordListTableAsync(db);
|
||||
await EnsureInventorySchemaAsync(db);
|
||||
@@ -265,6 +266,66 @@ public static class DatabaseBootstrap
|
||||
/// tables on whichever provider is in use. Safe to run every boot:
|
||||
/// CREATE TABLE / INDEX IF NOT EXISTS no-op once they exist (whether
|
||||
/// created here or by a fresh-DB EnsureCreated).</summary>
|
||||
/// <summary>External sign-in: the identities linked to accounts
|
||||
/// (<c>ExternalLogins</c>) and the data-protection keys that encrypt the
|
||||
/// sign-in cookies (<c>DataProtectionKeys</c>). Both post-date the Initial
|
||||
/// migration, so like the signup-code tables they're created here for
|
||||
/// either provider (a no-op once EnsureCreated or an earlier boot made them).</summary>
|
||||
private static async Task EnsureExternalSignInTablesAsync(DorkNetDbContext db)
|
||||
{
|
||||
var pg = db.Database.IsNpgsql();
|
||||
var statements = pg
|
||||
? new[]
|
||||
{
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS "ExternalLogins" (
|
||||
"Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
"PlayerId" bigint NOT NULL,
|
||||
"Issuer" text NOT NULL,
|
||||
"Subject" text NOT NULL,
|
||||
"Email" text NOT NULL DEFAULT '',
|
||||
"CreatedAt" timestamp with time zone NOT NULL DEFAULT now(),
|
||||
"LastUsedAt" timestamp with time zone NOT NULL DEFAULT now()
|
||||
);
|
||||
""",
|
||||
@"CREATE UNIQUE INDEX IF NOT EXISTS ""IX_ExternalLogins_Issuer_Subject"" ON ""ExternalLogins"" (""Issuer"", ""Subject"");",
|
||||
@"CREATE INDEX IF NOT EXISTS ""IX_ExternalLogins_PlayerId"" ON ""ExternalLogins"" (""PlayerId"");",
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS "DataProtectionKeys" (
|
||||
"Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
"FriendlyName" text NULL,
|
||||
"Xml" text NULL
|
||||
);
|
||||
""",
|
||||
}
|
||||
: new[]
|
||||
{
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS "ExternalLogins" (
|
||||
"Id" INTEGER NOT NULL CONSTRAINT "PK_ExternalLogins" PRIMARY KEY AUTOINCREMENT,
|
||||
"PlayerId" INTEGER NOT NULL,
|
||||
"Issuer" TEXT NOT NULL,
|
||||
"Subject" TEXT NOT NULL,
|
||||
"Email" TEXT NOT NULL DEFAULT '',
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"LastUsedAt" TEXT NOT NULL
|
||||
);
|
||||
""",
|
||||
@"CREATE UNIQUE INDEX IF NOT EXISTS ""IX_ExternalLogins_Issuer_Subject"" ON ""ExternalLogins"" (""Issuer"", ""Subject"");",
|
||||
@"CREATE INDEX IF NOT EXISTS ""IX_ExternalLogins_PlayerId"" ON ""ExternalLogins"" (""PlayerId"");",
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS "DataProtectionKeys" (
|
||||
"Id" INTEGER NOT NULL CONSTRAINT "PK_DataProtectionKeys" PRIMARY KEY AUTOINCREMENT,
|
||||
"FriendlyName" TEXT NULL,
|
||||
"Xml" TEXT NULL
|
||||
);
|
||||
""",
|
||||
};
|
||||
|
||||
foreach (var sql in statements)
|
||||
await db.Database.ExecuteSqlRawAsync(sql);
|
||||
}
|
||||
|
||||
private static async Task EnsureSignupCodeTablesAsync(DorkNetDbContext db)
|
||||
{
|
||||
var pg = db.Database.IsNpgsql();
|
||||
|
||||
Reference in New Issue
Block a user