UNPKG

godprotocol

Version:

A distributed computing environment for Web 4.0 — integrating AI, decentralisation, and virtual computation.

265 lines (215 loc) 6.07 kB
import { Mongo } from "@godprotocol/repositories"; import Services, { gp_services } from "./Services.js"; class DB { constructor(config, router) { this.router = router; let conf = { db_url: config.db_url, db_name: config.db_name || router?.gp?.platform_uri.replace(/\./g, "-"), }; this.db = new Mongo(conf); this.folders = {}; } read_cache = async (query, category) => { let coll = await this.folder(`$CACHE-${category}`); // await coll.deleteMany() const doc = await coll.findOne(query); if (!doc) return null; if (doc.expiry && new Date(doc.expiry) < new Date()) { await coll.deleteOne({ _id: doc._id }); return null; } return JSON.parse(doc?.payload); }; save_cache = async ( query, payload, category, ttlMs = 7 * 24 * 60 * 60 * 1000, ) => { let coll = await this.folder(`$CACHE-${category}`); const now = new Date(); const toSet = { payload: JSON.stringify(payload), }; // 🔥 set expiry if TTL provided if (ttlMs) { toSet.expiry = new Date(now.getTime() + ttlMs); } // OR use payload expiry if present else if (payload?.expiry) { toSet.expiry = new Date(payload.expiry); } const res = await coll.updateOne( query, { $set: toSet, $setOnInsert: { _id: crypto.randomUUID(), created: now, }, }, { upsert: true }, ); return res; }; folder = async (name) => { let folder = this.folders[name]; if (folder) return folder; folder = await this.db.collection(name); this.folders[name] = folder; return folder; }; } class Headers extends Services { constructor() { super(); } validate_api_key = async (api_key, authorization) => { const db = await this.platform_db(); const query = { type: "api_key", api_key, authorization: authorization || null, platform: process.env.PLATFORM_URI, }; // 🔹 1. Try cache const cached = await db.read_cache(query, "auth"); if (cached?.payload) { try { return { ok: true, data: JSON.parse(cached.payload), }; } catch { // corrupted cache → ignore } } // 🔹 2. Call remote const headers = { "x-api-version": "v2", "x-api-key": api_key, }; if (authorization) { headers["authorization"] = `Bearer ${authorization}`; } let res = await fetch(`${gp_services.profile}/validate`, { method: "post", headers: { "Content-Type": "application/json", Accept: "application/json", "x-api-version": "v2", ...headers, }, body: JSON.stringify({}), }); res = await res.json(); // 🔹 3. Save cache if valid if (res.ok && res.data) { await db.save_cache(query, res.data, "auth"); } return res; }; validate_third_party = async (xplatform, authorization) => { const db = await this.platform_db(); const query = { type: "third_party", xplatform, authorization: authorization || null, platform: this.platform_uri, }; // 🔹 1. Try cache const cached = await db.read_cache(query, "auth"); if (cached?.payload) { try { return { ok: true, data: JSON.parse(cached.payload), }; } catch { // corrupted cache → ignore } } // 🔹 2. Call remote const headers = { "x-api-version": "v3", "x-platform": this.platform_uri, "x-api-key": this.api_key, }; if (authorization) { headers["authorization"] = `Bearer ${authorization}`; } let res = await fetch( `${gp_services.profile}/${xplatform === this.platform_uri ? "me" : "third_party_me"}`, { method: "post", headers: { "Content-Type": "application/json", Accept: "application/json", "x-api-version": "v3", ...headers, }, body: JSON.stringify({ from: xplatform }), }, ); res = await res.json(); // 🔹 3. Save cache if (res.ok && res.data) { await db.save_cache(query, res.data, "auth"); } return res; }; check_security = (requirements, payload) => { if (!requirements?.length) return true; let headers = payload.headers || {}; let checks = { api_key: () => !!headers["x-api-key"], auth_token: () => !!headers["authorization"], xplatform: () => !!headers["x-platform"], }; return requirements.every((r) => checks[r]?.()); }; handle_security = async (name, request) => { let route = await this.get_route(name); console.log(route?.config?.security, "SECURITY FOR ROUTE"); if (!route?.config?.security?.length) return true; if (!this.check_security(route.config.security, request)) { // debug("Unauthorized access attempt to route:", name); return { ok: false, status: 401, message: "Unauthorized", }; } let xplatform = request.headers["x-platform"], api_key = request.headers["x-api-key"], authorisation = request.headers["authorization"]; if (authorisation) authorisation = authorisation.replace("Bearer ", ""); let val; if (xplatform) { val = await this.validate_third_party(xplatform, authorisation); } else { val = await this.validate_api_key(api_key, authorisation); } // debug(val); if (!val?.ok) { return val; } else { val = val.data; if (!val) { return { ok: false, message: "malformed header validation", status: 403, }; } request.headers.profile = val.profile; request.headers.platform = val.platform; if (val.xplatform) request.headers.xplatform = val.xplatform; if (val.third_party) request.headers.third_party = val.third_party; } return true; }; } export default Headers; export { DB };