80 lines · 3.5 KB
import { createServerFn } from "@tanstack/react-start";
import { unreadNotifications } from "~/server/user-inbox";
import { enforceRateLimit, requestIp } from "~/server/limits";
import { z } from "zod";
import { viewerMiddleware } from "./middleware";
import { createSession, destroySession, loadUserByLogin } from "~/server/auth";
import { verifyPassword, verifyPasswordAgainstNobody } from "~/server/crypto";
import { createUser, githubOAuthEnabled, signupsEnabled } from "~/server/accounts";
import { badRequest } from "~/server/errors";
import { rehashIfStale, sendEmailVerification } from "~/server/account-security";
import { requiresSecondFactor, startPendingLogin } from "~/server/two-factor";
import { accountName, email, password } from "~/lib/validation";
import { requireTurnstile, turnstileSiteKey } from "~/server/turnstile";
import { clientAnalyticsConfig } from "~/server/analytics";

const turnstileToken = z.string().max(2048).optional();

export const getSession = createServerFn({ method: "GET" })
  .middleware([viewerMiddleware])
  .handler(async ({ context }) => {
    const unread = context.viewer ? await unreadNotifications(context.viewer.id) : 0;
    return { viewer: context.viewer, unreadNotifications: unread, analytics: clientAnalyticsConfig() };
  });

export const getAuthOptions = createServerFn({ method: "GET" }).handler(async () => {
  return {
    signupsEnabled: signupsEnabled(),
    githubEnabled: githubOAuthEnabled(),
    turnstileSiteKey: turnstileSiteKey(),
  };
});

export const signUp = createServerFn({ method: "POST" })
  .validator(z.object({ username: accountName, email, password, turnstileToken }))
  .handler(async ({ data }) => {
    await enforceRateLimit("AUTH_LIMITER", `signup:${requestIp()}`);
    await requireTurnstile(data.turnstileToken, "signup");
    const id = await createUser({
      name: data.username,
      email: data.email,