import { exists } from "jsr:@std/fs"; import * as nostrTools from "@nostr/tools"; import * as nip06 from "@nostr/tools/nip06"; import { decodeBase64, encodeBase64 } from "jsr:@std/encoding@0.224/base64"; import { getEveFilePath } from "./utils/files.ts"; import { decryptUint8Array, encryptionKey, encryptUint8Array, } from "./utils/encryption.ts"; export function isLocalhost(req: Request): boolean { const url = new URL(req.url); const hostname = url.hostname; return ( hostname === "127.0.0.1" || hostname === "::1" || hostname === "localhost" ); } export function isValidJSON(str: string) { try { JSON.parse(str); } catch { return false; } return true; } export function isArray(obj: unknown): obj is T[] { return Array.isArray(obj); } export function randomTimeUpTo2DaysInThePast() { const now = Date.now(); const twoDaysAgo = now - 2 * 24 * 60 * 60 * 1000 - 3600 * 1000; // 1 hour buffer in case of clock skew return Math.floor( (Math.floor(Math.random() * (now - twoDaysAgo)) + twoDaysAgo) / 1000, ); } export async function getCCNPubkey(): Promise { const ccnPubPath = await getEveFilePath("ccn.pub"); const seedPath = await getEveFilePath("ccn.seed"); const doWeHaveKey = await exists(ccnPubPath); if (doWeHaveKey) return Deno.readTextFileSync(ccnPubPath); const ccnSeed = Deno.env.get("CCN_SEED") || ((await exists(seedPath)) ? Deno.readTextFileSync(seedPath) : nip06.generateSeedWords()); const ccnPrivateKey = nip06.privateKeyFromSeedWords(ccnSeed); const ccnPublicKey = nostrTools.getPublicKey(ccnPrivateKey); const encryptedPrivateKey = encryptUint8Array(ccnPrivateKey, encryptionKey); Deno.writeTextFileSync(ccnPubPath, ccnPublicKey); Deno.writeTextFileSync( await getEveFilePath("ccn.priv"), encodeBase64(encryptedPrivateKey), ); Deno.writeTextFileSync(seedPath, ccnSeed); return ccnPublicKey; } export async function getCCNPrivateKey(): Promise { const encryptedPrivateKey = Deno.readTextFileSync( await getEveFilePath("ccn.priv"), ); return decryptUint8Array(decodeBase64(encryptedPrivateKey), encryptionKey); }