summaryrefslogtreecommitdiff
path: root/website/src/actions/otp/verify-otp.ts
blob: 726786eb08d9d19dca96712eca20279bfa8b256b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import { randomBytes } from "node:crypto";
import { z } from "astro/zod";
import { defineAction } from "astro:actions";
import { and, db, eq, gte, Otp, SendmailToken } from "astro:db";

export default defineAction({
  input: z.object({
    guess: z.string().length(6),
    lenient: z.boolean().default(false),
    userId: z.string().nonempty(),
  }),
  handler: verifyOtp,
});

async function verifyOtp({ guess, lenient, userId }: VerifyOtpParams) {
  const leniency = lenient ? 1000 * 60 : 0;
  const isOtpCorrect =
    (await db.$count(
      Otp,
      and(
        eq(Otp.userId, userId),
        eq(Otp.value, guess),
        gte(Otp.validUntil, Date.now() - leniency),
      ),
    )) > 0;

  if (!isOtpCorrect) {
    return false;
  }

  await db.delete(Otp).where(and(eq(Otp.userId, userId), eq(Otp.value, guess)));

  const token = randomBytes(256).toString("hex");
  await db.insert(SendmailToken).values({
    userId,
    value: token,
    createdAt: Date.now(),
    validUntil: Date.now() + 60_000,
  });

  return token;
}

type VerifyOtpParams = {
  guess: string;
  lenient: boolean;
  userId: string;
};