132 lines · 5.2 KB
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { createSession } from "~/server/auth";
import { enforceHourlyLimit, enforceRateLimit, HOURLY, requestIp } from "~/server/limits";
import { badRequest, unauthorized } from "~/server/errors";
import {
  completePasswordReset,
  confirmEmailVerification,
  notifySecurityEvent,
  requestPasswordReset,
} from "~/server/account-security";
import {
  attemptPendingLogin,
  clearPendingLogin,
  clearTotpFailures,
  peekPendingLogin,
  requiresSecondFactor,
  secondFactorMethods,
  useRecoveryCode,
  verifyUserTotp,
} from "~/server/two-factor";
import { passkeyRequestOptions, verifyPasskeyAssertion } from "~/server/passkeys";
import { email, password } from "~/lib/validation";

const encoded = z.string().min(1).max(16384);
const assertion = z.object({
  challenge: z.string().min(1).max(128),
  credentialId: z.string().min(1).max(1400),
  clientDataJSON: encoded,
  authenticatorData: encoded,
  signature: encoded,
});

async function requirePending(): Promise<string> {
  const userId = await attemptPendingLogin();
  if (!userId) throw unauthorized("Your sign-in expired; enter your password again");
  return userId;
}

export const getTwoFactorChallenge = createServerFn({ method: "GET" }).handler(async () => {