Something went wrong. Try again.
a tool for shared writing and social publishing
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142"use server";
import { randomBytes } from "crypto";import { drizzle } from "drizzle-orm/node-postgres";import postgres from "postgres";import { email_auth_tokens, identities } from "drizzle/schema";import { and, eq } from "drizzle-orm";import { cookies } from "next/headers";import { createIdentity } from "./createIdentity";import { setAuthToken } from "src/auth";import { pool } from "supabase/pool";
async function sendAuthCode(email: string, code: string) { if (process.env.NODE_ENV === "development") { console.log("Auth code:", code); return; }
let res = await fetch("https://api.postmarkapp.com/email", { method: "POST", headers: { "Content-Type": "application/json", "X-Postmark-Server-Token": process.env.POSTMARK_API_KEY!, }, body: JSON.stringify({ From: "Leaflet <accounts@leaflet.pub>", Subject: `Your authentication code for Leaflet is ${code}`, To: email, TextBody: `Paste this code to login to Leaflet:
${code} `, HtmlBody: ` <html> <body> <p>Paste this code to login to Leaflet: <strong>${code}</strong></p> </body> </html> `, }), });}
export async function requestAuthEmailToken(emailNonNormalized: string) { let email = emailNonNormalized.toLowerCase(); const client = await pool.connect(); const db = drizzle(client);
const code = randomBytes(3).toString("hex").toUpperCase();
const [token] = await db .insert(email_auth_tokens) .values({ email, confirmation_code: code, confirmed: false, }) .returning({ id: email_auth_tokens.id, });
await sendAuthCode(email, code);
client.release(); return token.id;}
export async function confirmEmailAuthToken(tokenId: string, code: string) { const client = await pool.connect(); const db = drizzle(client);
const [token] = await db .select() .from(email_auth_tokens) .where(eq(email_auth_tokens.id, tokenId));
if (!token || !token.email) { client.release(); return null; }
if (token.confirmation_code !== code) { client.release(); return null; }
if (token.confirmed) { client.release(); return null; } let authToken = (await cookies()).get("auth_token"); if (authToken) { let [existingToken] = await db .select() .from(email_auth_tokens) .rightJoin(identities, eq(identities.id, email_auth_tokens.identity)) .where(eq(email_auth_tokens.id, authToken.value));
if (existingToken) { if (existingToken.identities?.email) { } await db .update(identities) .set({ email: token.email }) .where(eq(identities.id, existingToken.identities.id)); client.release(); return existingToken; } }
let identityID; let [identity] = await db .select() .from(identities) .where(eq(identities.email, token.email)); if (!identity) { let newIdentity = await createIdentity(db, { email: token.email }); identityID = newIdentity.id; } else { identityID = identity.id; }
const [confirmedToken] = await db .update(email_auth_tokens) .set({ confirmed: true, identity: identityID, }) .where( and( eq(email_auth_tokens.id, tokenId), eq(email_auth_tokens.confirmation_code, code), ), ) .returning();
await setAuthToken(confirmedToken.id);
client.release(); return confirmedToken;}