@paroicms/server
Version:
The ParoiCMS server
93 lines • 3.39 kB
JavaScript
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