const { argv } = require("process"); const fs = require("fs-extra"); const mustache = require("mustache"); const bodyParser = require("body-parser"); const glob = require("glob"); const path = require("path"); const cors = require("cors"); const express = require("express"); const process = require("process"); /******************************************* SEE https://gitea.ndda.fr/apxtri/apxtri/wiki/Devrules To have a quick understanding and convention before doing deeply in source code To share configuration : process.env.dirtown is folder where town folder name /townId-nationId is accessible const conf = require(`../../conf/townconf.json`); app.locals.tribeids is defined later in apixtrib.js and allow express app to always have in memory a dynamic of tribeId available in req.app.locals.tribeids */ /** * 1st install for dev * run $ node apxtri.js nationId:ants townId:devfarm dns:devfarm-ants * then just yarn dev * it create a folder outside ../townId-nationId/ * To convert a dev into a chain town run again with relevant param: * run $ node apxtri.js nationId:ants townId:devfarm dns:devfarm-ants * check the web interface http://dns * then just yarn startpm2 your town is under PM2 control * * * @param {args} args key:value example node apxtri nationId:ants townId:devfarm dns:devfarm-ants * if no parameter from adminapi/www/adminapx/conf/setup_xx.json * * Keyword townId = "devfarm" then this is unchain town to dev * else this is a production town ready to chain to the nationId * * @returns listen onto http:/dns (80 and 443) for admin webapp and http://localhost:initconf.api.port * by setting the nginx parameter * A folder for town data is created at the same level than apxtri as /townId-nationId/conf.json ... */ // check nginx exist if (!fs.existsSync("/etc/nginx/nginx.conf")) { console.log( "\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available, install then rerun yarn command." ); process.exit(); } const param = {}; argv.slice(2).forEach((arg) => { const kv = arg.split(":"); if (kv.length == 2) { param[kv[0]] = kv[1]; } }); if (!fs.existsSync("../conf/townconf.json")) { // This is a first install const nam = path.resolve("..").split("/").slice(-1)[0].split("-"); const town = nam[0]; const nation = nam[1]; // doit exister param.dns pour mettre à jour le conf.json pour la conf adminapi //run setup process } // setup_xx.json is gitignore so at first install we are in dev configuration /* let infotown = { nationId: "ants", townId: "devfarm", dns: "devfarm-ants", comment: "Auto generate setup from apxtri after node apxtri nationId:value townId:value dns:domaine_to_access", }; if (fs.existsSync(`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`)) { infotown = fs.readJsonSync( `${__dirname}/adminapi/www/adminapx/conf/setup_xx.json` ); } if ( Object.keys(param).length > 0 && param.nationId && param.townId && param.dns ) { infotown.nationId = param.nationId; infotown.townId = param.townId; infotown.dns = param.dns; } fs.outputJsonSync( `${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`, infotown ); infotown.dirapi = __dirname; infotown.dirtown = path.resolve( `${__dirname}/../${infotown.townId}-${infotown.nationId}` ); process.env.dirtown = infotown.dirtown; infotown.dirapxwebapp = path.resolve(`${infotown.dirapi}/..`); //same level as apxtri if ( !fs.existsSync(`${infotown.dirtown}/conf.json`) || !fs.existsSync(`${__dirname}/adminapi/www/nginx_adminapx.conf`) ) { // Case of new town or request a reset of dns to access adminapx // genere a minimum conf with nationId, townId, dns, dirapi, dirtown fs.outputJsonSync(`${infotown.dirtown}/conf.json`, infotown, { space: 2 }); const Towns = require("./api/models/Towns"); const rescreate = Towns.create(); if (rescreate.status != 200) { console.log("Sorry error "); process.exit(); } } */ const conf = require(path.resolve(`../conf/townconf.json`)); const currentmod = "apxtri"; const log = conf.api.activelog.includes(currentmod); // Create and update ./nationchains plutot que cette fonction // A creuser et voir comment synchro /*const { updateobjectsfromfreshesttown } = require("./models/Nations.js"); updateobjectsfromfreshesttown(conf.towns, { pagans: "alias_all.json", towns: "townId_all.json", nations: "nationId_all.json", }); */ // Run main express process for a /towId-nationId/tribes let tribelist = {}; if (fs.existsSync(`../nationchains/tribes/idx/tribeId_all.json`)) { tribelist = fs.readJsonSync(`../nationchains/tribes/idx/tribeId_all.json`); } let doms = conf.dns; // only dns of town during the init process let tribeIds = []; let routes = glob.sync(`./routes/*.js`).map((f) => { return { url: `/${path.basename(f, ".js")}`, route: f }; }); glob.sync(`../nationchains/tribes/*/api/routes/*.js`).forEach((f) => { const ids = f.indexOf(`../nationchains/tribes/`); const trib = f.slice( ids + `../nationchains/tribes/`.length, f.lastIndexOf("/api/routes") ); routes.push({ url: `/${trib}/${path.basename(f, ".js")}`, route: f }); }); //routes={url,route} check how to add plugin tribe route later // keep only the 2 last part (.) of domain name to validate cors with it (generic domain) Object.keys(tribelist).forEach((t) => { tribelist[t].dns.forEach((d) => { const dm = d.split(".").slice(-2).join("."); if (!doms.includes(dm)) doms.push(dm); }); tribeIds.push(t); }); if (log) console.log( currentmod, " Allowed DOMs to access to this apxtri server:", JSON.stringify(doms) ); const app = express(); // load express parameter from conf Object.keys(conf.api.appset).forEach((p) => { app.set(p, conf.api.appset[p]); }); // To set depending of data form or get size to send app.use(bodyParser.urlencoded(conf.api.bodyparse.urlencoded)); // To set depending of post put json data size to send app.use(express.json()); app.use(bodyParser.json(conf.api.bodyparse.json)); app.disable("x-powered-by"); // for security app.locals.tribeids = tribeIds; if (log) console.log(currentmod, " app.locals.tribeids", app.locals.tribeids); // Cors management let originlst = "test"; doms.forEach((d) => { originlst += `|${d.replace(/\./g, "\\.")}`; }); const regtxt = `^http.?:\/\/(${originlst})`; let cor = false; const regorigin = new RegExp(regtxt); app.use((req, res, next) => { if (req.headers.origin == undefined) { cor = true; } else { cor = regorigin.test(req.headers.origin); } if (log) console.log( currentmod, "request origin:", req.headers.origin, "testcors:", cor, "headers allowed: [", conf.api.exposedHeaders.join(','),"] match with reg:", regtxt ); cors({ origin: cor, allowedHeaders: conf.api.exposedHeaders, exposedHeaders: conf.api.exposedHeaders, credentials: true, preflightContinue: false, optionsSuccessStatus: 204 }); next(); }); // Routers add any routes from /routes and /plugins let logroute = "Routes available on this apxtri instance: \n"; routes.forEach((r) => { try { logroute += r.url.padEnd(30, " ") + r.route + "\n"; app.use(r.url, require(r.route)); } catch (err) { logroute += " (err check it module.exports=router;? or ...)\n======\n "; console.log("raise err-:", err); } }); if (log) { console.log(currentmod, logroute); if (process.env.NODE_MODE == "dev") console.log( `\x1b[42m############################################################################################\x1b[0m\n\x1b[42mThis is dev conf accessible in http://dev-ants to switch this as production, you must run:\n 1 - 'yarn dev nationId:ants townId:dev dns:dev-ants' to conf your town and check it.\n 2 - 'yarn startpm2'\n Where:\n\x1b[42m * nationId have to exist in the nationchains\n * townId new or if exist must have the same current dns,\n * dns domaine that has to redirect 80/443 into this server.\n Check README's project to learn more.\x1b[0m\n To work with apxweb for the front use http://dev-ants/apxwebapp/www/websitename/src/index.html to use the api during dev process\n\x1b[42m############################################################################################\x1b[0m` ); } app.listen(conf.api.port, () => { let webaccess = `api waits request on port:${conf.api.port} for`; conf.dns.forEach((u) => { webaccess += `${u}/api/ `; }); if (log) console.log(currentmod, webaccess); }); console.log( "\x1b[42m\x1b[37m", "Made with love for people's freedom, enjoy !!!", "\x1b[0m" );