118 lines
3.1 KiB
TypeScript
118 lines
3.1 KiB
TypeScript
import { getRequestEvent } from '$app/server';
|
|
import { m } from '$lib/paraglide/messages';
|
|
import { getConfig } from '$lib/server/config';
|
|
import { db } from '$lib/server/db';
|
|
import * as schema from '$lib/server/db/schema';
|
|
import { emailer } from '$lib/server/emails';
|
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
|
import { betterAuth } from 'better-auth/minimal';
|
|
import { admin, twoFactor, username } from 'better-auth/plugins';
|
|
import { genericOAuth, type GenericOAuthConfig } from 'better-auth/plugins/generic-oauth';
|
|
import { sveltekitCookies } from 'better-auth/svelte-kit';
|
|
import path from 'node:path';
|
|
import { cwd } from 'node:process';
|
|
|
|
export const oauthConfig = (await Bun.file(
|
|
path.join(cwd(), 'config/oauth.json')
|
|
).json()) as GenericOAuthConfig[];
|
|
|
|
function build() {
|
|
const cfg = getConfig();
|
|
return betterAuth({
|
|
basePath: '/api/auth',
|
|
baseURL: cfg.ORIGIN,
|
|
database: drizzleAdapter(db, {
|
|
provider: 'sqlite',
|
|
schema
|
|
}),
|
|
emailAndPassword: {
|
|
autoSignIn: false,
|
|
customSyntheticUser: ({ additionalFields, coreFields, id }) => ({
|
|
...coreFields,
|
|
banExpires: null,
|
|
banned: false,
|
|
banReason: null,
|
|
displayUsername: null,
|
|
role: 'user',
|
|
twoFactorEnabled: false,
|
|
username: null,
|
|
...additionalFields,
|
|
id
|
|
}),
|
|
disableSignUp: cfg.DISABLE_SIGNUP || false,
|
|
enabled: cfg.ENABLE_EMAIL_AND_PASSWORD || true,
|
|
requireEmailVerification: true,
|
|
sendResetPassword: async ({ token, url, user }) => {
|
|
if (url.endsWith('reset-password')) await emailer.sendResetPassword({ token, url, user });
|
|
|
|
if (url.endsWith('complete-registration'))
|
|
await emailer.sendCompleteRegistration({ token, url, user });
|
|
}
|
|
},
|
|
emailVerification: {
|
|
autoSignInAfterVerification: true,
|
|
sendOnSignIn: true,
|
|
sendOnSignUp: true,
|
|
sendVerificationEmail: async ({ url, user }) => {
|
|
await emailer.sendVerificationEmail({ url, user });
|
|
}
|
|
},
|
|
plugins: [
|
|
admin(),
|
|
genericOAuth({ config: oauthConfig }),
|
|
twoFactor({
|
|
issuer: m.appname(),
|
|
otpOptions: {
|
|
sendOTP: async ({ otp, user }) => {
|
|
await emailer.sendOtp({ otp, user });
|
|
}
|
|
},
|
|
totpOptions: {
|
|
period: 30
|
|
}
|
|
}),
|
|
username(),
|
|
sveltekitCookies(getRequestEvent)
|
|
],
|
|
rateLimit: { enabled: true },
|
|
socialProviders: {
|
|
facebook:
|
|
(cfg.FACEBOOK_CLIENT_ID && {
|
|
clientId: cfg.FACEBOOK_CLIENT_ID,
|
|
clientSecret: cfg.FACEBOOK_CLIENT_SECRET ?? ''
|
|
}) ||
|
|
undefined,
|
|
github:
|
|
(cfg.GITHUB_CLIENT_ID && {
|
|
clientId: cfg.GITHUB_CLIENT_ID,
|
|
clientSecret: cfg.GITHUB_CLIENT_SECRET ?? ''
|
|
}) ||
|
|
undefined,
|
|
google:
|
|
(cfg.GOOGLE_CLIENT_ID && {
|
|
clientId: cfg.GOOGLE_CLIENT_ID,
|
|
clientSecret: cfg.GOOGLE_CLIENT_SECRET ?? ''
|
|
}) ||
|
|
undefined
|
|
},
|
|
telemetry: { enabled: false },
|
|
user: {
|
|
deleteUser: {
|
|
enabled: true
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
let cached: null | ReturnType<typeof build> = null;
|
|
|
|
export type Auth = ReturnType<typeof build>;
|
|
|
|
export function getAuth(): ReturnType<typeof build> {
|
|
return (cached ??= build());
|
|
}
|
|
|
|
export function invalidateAuth(): void {
|
|
cached = null;
|
|
}
|