const crypt = require("../crypt"); // methods const isAuthed = require("./is-authed"); const logIn = require("./log-in"); const setupToken = require("./setup-token"); // authed sessions global.authed = new WeakMap(); global.authed.tokens = new Object(); function parseRq (bytes) { try { return JSON.parse(bytes.toString()); } catch (e) { return undefined; } } class APIMethods { constructor (parentObj) { this.parentObj = parentObj; this.info.cache = new Object(); // Clear method cache on update config global.server.on("config.update", () => { this.info.cache = new Object(); }); } info (con, req, cb) { if (!req.fields) req.fields = "*"; if (!req.fieldsExtSource) req.fieldsExtSource = "*"; const cache = this.info.cache[ JSON.stringify({ f: req.fields, e: req.fieldsExtSource }) ]; if (cache) { console.debug("CACHE!"); return cb({ result: cache, trace_id: req.trace_id, ended: true }); } const serverInfo = require("./server-info")(); if (req.fields !== "*") { const fields = Object.fromEntries(req.fields.split(/\s*,\s*/g).map(x => [x.trim(), true])); Object.keys(serverInfo).forEach(k => { if (!fields[k]) serverInfo[k] = undefined; }); } if (req.fieldsExtSource !== "*" && req.fields.extSource !== undefined) { const fields = Object.fromEntries(req.fieldsExtSource.split(/\s*,\s*/g).map(x => [x.trim(), true])); Object.keys(serverInfo).forEach(k => { if (!fields[k]) serverInfo.extSource[k] = undefined; }); } this.info.cache[ JSON.stringify({ f: req.fields, e: req.fieldsExtSource }) ] = serverInfo; cb({ result: serverInfo, trace_id: req.trace_id, ended: true }); } authed (con, req, cb) { isAuthed(con, req, cb); } async token (con, req, cb) { const authedMethod = this.authed; const isAuthed = await (new Promise((rs, rj) => { authedMethod(con, req, ({ result, ended }) => { if (ended) return rs(result); }); })); if (!isAuthed) { return setupToken(con, req, cb); } cb({ error: "already logged-in", trace_id: req.trace_id, ended: true }); } async login (con, req, cb) { const authedMethod = this.authed; const isAuthed = await (new Promise((rs, rj) => { authedMethod(con, req, ({ result, ended }) => { if (ended) return rs(result); }); })); if (!isAuthed) { return logIn(con, req, cb); } cb({ error: "already logged-in", trace_id: req.trace_id, ended: true }); } /*setSession (isEncrypted, address, { key, counter }, cb) { if (!global.config.server.secureMode) return cb({ error: "Encryption is off by configuration file into server" }); if (!isEncrypted) return cb({ error: "Encryption required" }); try { this.parent.sessions[address] = new crypt.AES(key, counter); return cb({ result: "Session key installed" }); } catch (err) { return cb({ error: "Invalid params. Must be key and counter" }); } }*/ } class API { constructor () { this.methods = new APIMethods(this); this.sessions = global.authed; } decrypt (address, bytes) { throw new Error("Deprecated. Use TLS. If you see this error, please, create issue into: https://git.fullgream.tech/fullgream/ai-adventure-labs/issues"); } async exec (connection, bytes, cb) { const request = parseRq(bytes); if (request === undefined) return cb({ error: "required JSON object request" }); if (typeof request === "object" && request !== null) { const { method, trace_id } = request; if (!method) return cb({ error: "method missed", trace_id: trace_id ?? null, ended: true }); if (!trace_id) return cb({ error: "trace_id missed", trace_id: null, ended: true }); if (this.methods[method] === undefined) return cb({ error: "unknown method: " + method, trace_id, ended: true }); return this.methods[method](connection, request, cb); } else { return cb({ error: "required JSON-object based request", trace_id: null, ended: true }); } } } module.exports = { API };