nip42-proxy/src/utils.ts
2025-08-10 21:13:35 +02:00

113 lines
3.4 KiB
TypeScript

import type { Event } from "nostr-tools";
export function getGitCommitHash() {
try {
const { stdout } = Bun.spawnSync({
cmd: ["git", "rev-parse", "HEAD"],
stdout: "pipe",
stderr: "pipe",
});
const out = stdout?.toString()?.trim();
return out?.split("\n")[0] || "unknown";
} catch {
return "unknown";
}
}
export async function validateAuthEvent(
event: Event,
challenge: string,
): Promise<boolean> {
if (event.kind !== 22242) return false;
const last30Seconds = Math.floor(Date.now() / 1000) - 30;
if (event.created_at < last30Seconds) return false;
const challengeTag = event.tags.find((tag) => tag[0] === "challenge")?.[1];
if (challengeTag !== challenge) return false;
if(!await isPubkeyAllowed(event))
return false;
return await isKindAllowed(event);
}
export async function isPubkeyAllowed(event: Event): Promise<boolean> {
const file = Bun.file("./allowed-pubkeys.json");
if (!(await file.exists())) return true;
try {
const allowedPubkeys = JSON.parse(await file.text());
return (
Array.isArray(allowedPubkeys) && allowedPubkeys.includes(event.pubkey)
);
} catch {
// If the file is malformed, default to deny
return false;
}
}
export async function getAllAllowedPubkeys() {
const file = Bun.file("./allowed-pubkeys.json");
try {
if (await file.exists()) return JSON.parse(await file.text());
} catch {}
return [] as string[];
}
export async function saveAllowedPubkeys(pubkeys: string[]): Promise<number> {
const file = Bun.file("./allowed-pubkeys.json");
const unique = Array.from(new Set(pubkeys));
return await file.write(JSON.stringify(unique));
}
export async function allowPubkey(pubkey: string): Promise<number> {
const pubkeys = await getAllAllowedPubkeys();
if (!pubkeys.includes(pubkey)) pubkeys.push(pubkey);
return await saveAllowedPubkeys(pubkeys);
}
export async function banPubkey(pubkey: string): Promise<number> {
const pubkeys = await getAllAllowedPubkeys();
const filtered = pubkeys.filter((p: string) => p !== pubkey);
return await saveAllowedPubkeys(filtered);
}
export async function isKindAllowed(event: Event): Promise<boolean> {
const file = Bun.file("./allowed-kinds.json");
if (!(await file.exists())) return true;
try {
const allowedKinds = JSON.parse(await file.text());
if(!Array.isArray(allowedKinds)) return true;
if(allowedKinds.length === 0) return true;
return (
Array.isArray(allowedKinds) && allowedKinds.includes(event.kind)
);
} catch {
// If the file is malformed, default to allow
return true;
}
}
export async function getAllAllowedKinds(): Promise<number[]> {
const file = Bun.file("./allowed-kinds.json");
try {
if (await file.exists()) return JSON.parse(await file.text());
} catch {}
return [] as number[];
}
export async function saveAllowedKinds(kinds: number[]): Promise<number> {
const file = Bun.file("./allowed-kinds.json");
const unique = Array.from(new Set(kinds));
return await file.write(JSON.stringify(unique));
}
export async function allowKind(kind: number): Promise<number> {
const kinds = await getAllAllowedKinds();
if (!kinds.includes(kind)) kinds.push(kind);
return await saveAllowedKinds(kinds);
}
export async function disallowKind(kind: number): Promise<number> {
const kinds = await getAllAllowedKinds();
const filtered = kinds.filter((p: number) => p !== kind);
return await saveAllowedKinds(filtered);
}