Introduce token-based author authentication (register/verify API), skill forking with EditGate protection, tag metadata on skills, and download/push stats. Enhanced push scripts with token auth and per-skill filtering. Updated UI with stats, tags, and author info on skill cards.
56 lines
1.6 KiB
JavaScript
56 lines
1.6 KiB
JavaScript
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import crypto from 'node:crypto';
|
|
|
|
const TOKENS_FILE = path.resolve(process.env.TOKENS_FILE || "data/tokens.json");
|
|
async function readStore() {
|
|
try {
|
|
const raw = await fs.readFile(TOKENS_FILE, "utf-8");
|
|
return JSON.parse(raw);
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
async function writeStore(store) {
|
|
const dir = path.dirname(TOKENS_FILE);
|
|
await fs.mkdir(dir, { recursive: true });
|
|
const tmp = TOKENS_FILE + ".tmp";
|
|
await fs.writeFile(tmp, JSON.stringify(store, null, 2), "utf-8");
|
|
await fs.rename(tmp, TOKENS_FILE);
|
|
}
|
|
function hashToken(token) {
|
|
return crypto.createHash("sha256").update(token).digest("hex");
|
|
}
|
|
async function generateToken(email, name) {
|
|
const store = await readStore();
|
|
if (store[email]) {
|
|
throw new Error("Email already registered");
|
|
}
|
|
const token = crypto.randomBytes(32).toString("hex");
|
|
store[email] = {
|
|
hash: hashToken(token),
|
|
name,
|
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
};
|
|
await writeStore(store);
|
|
return token;
|
|
}
|
|
async function verifyToken(email, token) {
|
|
if (!email || !token) return false;
|
|
const store = await readStore();
|
|
const entry = store[email];
|
|
if (!entry) return false;
|
|
return entry.hash === hashToken(token);
|
|
}
|
|
async function hasToken(email) {
|
|
const store = await readStore();
|
|
return Boolean(store[email]);
|
|
}
|
|
function extractBearerToken(request) {
|
|
const auth = request.headers.get("Authorization") || "";
|
|
const match = auth.match(/^Bearer\s+(\S+)$/i);
|
|
return match ? match[1] : "";
|
|
}
|
|
|
|
export { extractBearerToken as e, generateToken as g, hasToken as h, verifyToken as v };
|