godprotocol
Version:
A distributed computing environment for Web 4.0 — integrating AI, decentralisation, and virtual computation.
265 lines (215 loc) • 6.07 kB
JavaScript
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 };