Revert "merge: sync GitHub staging to Gitea"
Deploy staging to test server / deploy (push) Failing after 14m49s

This reverts commit a55c69115d, reversing
changes made to 02c9c9f3d6.
This commit is contained in:
linmeng
2026-07-30 14:38:17 +08:00
parent a55c69115d
commit f4e35974c6
106 changed files with 3228 additions and 1213 deletions
+7 -38
View File
@@ -1,20 +1,18 @@
import { createHmac } from "node:crypto";
import type { Pool } from "pg";
import { APIError, type BetterAuthOptions } from "better-auth";
import type { BetterAuthOptions } from "better-auth";
import { admin, emailOTP, type EmailOTPOptions } from "better-auth/plugins";
import type { SelfHostedIdentityConfig } from "./config.ts";
import type { EmailOtpSender, IdentitySurface } from "./contracts.ts";
import type { EmailOtpSender } from "./contracts.ts";
import { identityModelMapping } from "./model.ts";
export type AdminUserAuthorizer = (userId: string) => Promise<boolean>;
interface BuildAuthOptionsInput {
surface: IdentitySurface;
config: SelfHostedIdentityConfig;
database: Pool;
emailSender: EmailOtpSender;
authorizeAdminUser?: AdminUserAuthorizer;
}
function otpIdempotencyKey(
@@ -58,26 +56,17 @@ export function createEmailOtpOptions(
}
export function buildAuthOptions({
surface,
config,
database,
emailSender,
authorizeAdminUser,
}: BuildAuthOptionsInput): BetterAuthOptions {
if (surface === "admin" && !authorizeAdminUser) {
throw new Error("admin user authorizer is required");
}
const origin = surface === "user" ? config.userOrigin : config.adminOrigin;
const secret = surface === "user" ? config.userSecret : config.adminSecret;
return {
appName: "Jyotisha",
baseURL: origin,
baseURL: config.userOrigin,
basePath: "/api/auth",
secret,
secret: config.userSecret,
database,
trustedOrigins: [origin],
trustedOrigins: [config.userOrigin],
telemetry: { enabled: false },
user: identityModelMapping.user,
session: identityModelMapping.session,
@@ -91,8 +80,7 @@ export function buildAuthOptions({
},
advanced: {
database: { generateId: "uuid" },
cookiePrefix:
surface === "user" ? "jyotisha-user" : "jyotisha-admin",
cookiePrefix: "jyotisha-user",
defaultCookieAttributes: {
secure: true,
httpOnly: true,
@@ -108,31 +96,12 @@ export function buildAuthOptions({
revokeSessionsOnPasswordReset: true,
},
plugins: [
...(surface === "user"
? [emailOTP(createEmailOtpOptions(emailSender, secret, false))]
: []),
emailOTP(createEmailOtpOptions(emailSender, config.userSecret, false)),
admin({
defaultRole: "user",
adminRoles: ["admin"],
schema: identityModelMapping.admin,
}),
],
...(surface === "admin"
? {
databaseHooks: {
session: {
create: {
async before(session: { userId: string }) {
if (!(await authorizeAdminUser!(session.userId))) {
throw new APIError("FORBIDDEN", {
message: "Administrator access required",
});
}
},
},
},
},
}
: {}),
};
}
+2 -17
View File
@@ -16,7 +16,7 @@ interface AdminRoleRow {
ban_expires: Date | null;
}
export type IdentityAdminSurfaceRole = "admin" | "viewer";
export type IdentityAdminSurfaceRole = "admin";
export function createIdentityPool(databaseUrl: string): Pool {
return new Pool({
@@ -68,19 +68,17 @@ export function createDatabaseAdminAuthorizer(
export function createDatabaseAdminSurfaceAuthorizer(
pool: Pool,
): AdminUserAuthorizer {
return createDatabaseRoleAuthorizer(pool, new Set(["admin", "viewer"]));
return createDatabaseAdminAuthorizer(pool);
}
export interface IdentityAuthServices {
pool: Pool;
user: ReturnType<typeof betterAuth>;
admin: ReturnType<typeof betterAuth>;
}
interface IdentityAuthDependencies {
pool?: Pool;
emailSender?: EmailOtpSender;
authorizeAdminUser?: AdminUserAuthorizer;
}
export function createIdentityAuthServices(
@@ -94,28 +92,15 @@ export function createIdentityAuthServices(
apiKey: config.resendApiKey,
from: config.resendFrom,
});
const authorizeAdminUser =
dependencies.authorizeAdminUser ?? createDatabaseAdminSurfaceAuthorizer(pool);
return {
pool,
user: betterAuth(
buildAuthOptions({
surface: "user",
config,
database: pool,
emailSender,
}),
),
admin: betterAuth(
buildAuthOptions({
surface: "admin",
config,
database: pool,
emailSender,
authorizeAdminUser,
}),
),
};
}
-13
View File
@@ -8,9 +8,7 @@ export interface SelfHostedIdentityConfig {
provider: "self-hosted";
databaseUrl: string;
userOrigin: string;
adminOrigin: string;
userSecret: string;
adminSecret: string;
resendApiKey: string;
resendFrom: string;
}
@@ -95,24 +93,13 @@ export function readSelfHostedIdentityConfig(
env: IdentityEnvironment,
): SelfHostedIdentityConfig {
const userOrigin = readOrigin(env, "AUTH_USER_ORIGIN");
const adminOrigin = readOrigin(env, "AUTH_ADMIN_ORIGIN");
if (userOrigin === adminOrigin) {
throw new Error("user and admin origins must be different");
}
const userSecret = readSecret(env, "BETTER_AUTH_USER_SECRET");
const adminSecret = readSecret(env, "BETTER_AUTH_ADMIN_SECRET");
if (userSecret === adminSecret) {
throw new Error("user and admin secrets must be different");
}
return {
provider: "self-hosted",
databaseUrl: readPostgresUrl(env),
userOrigin,
adminOrigin,
userSecret,
adminSecret,
resendApiKey: required(env, "RESEND_API_KEY"),
resendFrom: readSender(env),
};
@@ -1,5 +1,3 @@
export type IdentitySurface = "user" | "admin";
export type EmailOtpType =
| "sign-in"
| "email-verification"
+5 -10
View File
@@ -1,5 +1,4 @@
import type { SelfHostedIdentityConfig } from "./config.ts";
import type { IdentitySurface } from "./contracts.ts";
export type IdentityRequestHandler = (
request: Request,
@@ -33,15 +32,11 @@ function normalizeHost(value: string | null): string | null {
export function resolveIdentitySurface(
hostHeader: string | null,
config: SelfHostedIdentityConfig,
): IdentitySurface | null {
): "user" | null {
const host = normalizeHost(hostHeader);
if (!host) return null;
const userHost = new URL(config.userOrigin).host.toLowerCase();
const adminHost = new URL(config.adminOrigin).host.toLowerCase();
if (host === userHost) return "user";
if (host === adminHost) return "admin";
return null;
return host === new URL(config.userOrigin).host.toLowerCase() ? "user" : null;
}
function isAdminEndpoint(request: Request): boolean {
@@ -55,7 +50,7 @@ function isAdminEndpoint(request: Request): boolean {
export function createHostIsolatedAuthHandlers(
config: SelfHostedIdentityConfig,
handlers: Record<IdentitySurface, IdentityAuthHandlers>,
handlers: { user: IdentityAuthHandlers },
): IdentityAuthHandlers {
const dispatch =
(method: keyof IdentityAuthHandlers): IdentityRequestHandler =>
@@ -64,10 +59,10 @@ export function createHostIsolatedAuthHandlers(
if (!surface) {
return new Response("Unrecognized identity host", { status: 421 });
}
if (surface === "user" && isAdminEndpoint(request)) {
if (isAdminEndpoint(request)) {
return new Response("Not found", { status: 404 });
}
return handlers[surface][method](request);
return handlers.user[method](request);
};
return { GET: dispatch("GET"), POST: dispatch("POST") };