UNPKG

@paroicms/server

Version:
93 lines 3.39 kB
import { parseSqliteDateTime, sqliteDateTime } from "@paroicms/internal-server-lib"; import { type } from "arktype"; import { createHash, randomBytes } from "node:crypto"; export function generatePat() { const randomPart = randomBytes(32).toString("base64url"); const token = `pa_${randomPart}`; const tokenHash = hashToken(token); const tokenPreview = `${token.slice(0, 9)}...${token.slice(-4)}`; return { token, tokenHash, tokenPreview }; } export function hashToken(token) { return createHash("sha256").update(token).digest("hex"); } const PatRowAT = type({ id: "number", accountId: "number", tokenPreview: "string", description: "string|null", createdAt: "string|number|Date|null", lastUsedAt: "string|number|Date|null", expiresAt: "string|number|Date|null", active: "number", "+": "reject", }).pipe((r) => ({ id: String(r.id), accountId: String(r.accountId), tokenPreview: r.tokenPreview, description: r.description ?? undefined, createdAt: parseSqliteDateTime(r.createdAt) ?? new Date(), lastUsedAt: parseSqliteDateTime(r.lastUsedAt), expiresAt: parseSqliteDateTime(r.expiresAt), active: Boolean(r.active), })); export async function createPat(siteContext, options) { const { accountId, description, expiresAt } = options; const { token, tokenHash, tokenPreview } = generatePat(); const [id] = await siteContext.cn("PaPersonalAccessToken").insert({ accountId, tokenHash, tokenPreview, description: description ?? null, expiresAt: expiresAt ? sqliteDateTime(expiresAt) : null, }); const pat = { id: String(id), accountId, tokenPreview, description, createdAt: new Date(), expiresAt, active: true, }; return { token, pat }; } export async function listPatsByAccount(siteContext, accountId) { const rows = await siteContext .cn("PaPersonalAccessToken") .select("id", "accountId", "tokenPreview", "description", "createdAt", "lastUsedAt", "expiresAt", "active") .where({ accountId }) .orderBy("createdAt", "desc"); return rows.map((row) => PatRowAT.assert(row)); } export async function getPat(siteContext, patId) { const row = await siteContext .cn("PaPersonalAccessToken") .select("id", "accountId", "tokenPreview", "description", "createdAt", "lastUsedAt", "expiresAt", "active") .where({ id: patId }) .first(); if (!row) return; return PatRowAT.assert(row); } export async function updatePat(siteContext, patId, options) { const updates = {}; if (options.description !== undefined) { updates.description = options.description || null; } if (options.active !== undefined) { updates.active = options.active ? 1 : 0; } if (Object.keys(updates).length === 0) return; await siteContext.cn("PaPersonalAccessToken").update(updates).where({ id: patId }); } export async function deletePat(siteContext, patId) { await siteContext.cn("PaPersonalAccessToken").delete().where({ id: patId }); } export async function updateLastUsedAt(cn, tokenHash, timestamp) { await cn("PaPersonalAccessToken") .update({ lastUsedAt: sqliteDateTime(timestamp) }) .where({ tokenHash }); } //# sourceMappingURL=pat.service.js.map