362 lines
13 KiB
JavaScript
Executable File
362 lines
13 KiB
JavaScript
Executable File
//const { argv } = require("process");
|
|
const fs = require("fs-extra");
|
|
const bodyParser = require("body-parser");
|
|
const glob = require("glob");
|
|
const path = require("path");
|
|
const Mustache = require("mustache");
|
|
const cors = require("cors");
|
|
const express = require("express");
|
|
const process = require("process");
|
|
|
|
/*******************************************
|
|
SEE README.md to start
|
|
********************************************/
|
|
const apxtri = {};
|
|
|
|
apxtri.main = async () => {
|
|
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(0);
|
|
}
|
|
//Check prerequest data
|
|
if (
|
|
fs.existsSync("../adminapi/objects/tribes/idx/tribes_dns.json") &&
|
|
fs.existsSync("../adminapi/objects/tribes/itm/adminapi.json")
|
|
) {
|
|
// check all tribes are in tribes_dns.json
|
|
const conf = fs.readJSONSync(
|
|
"../adminapi/objects/tribes/itm/adminapi.json"
|
|
);
|
|
const tribesdns = fs.readJsonSync(
|
|
`../adminapi/objects/tribes/idx/tribes_dns.json`
|
|
);
|
|
//check if new tribe was add
|
|
glob
|
|
.sync("../*")
|
|
.filter((f) => fs.lstatSync(f).isDirectory())
|
|
.forEach(async (t) => {
|
|
const tribe = path.basename(t);
|
|
//console.log(tribe);
|
|
if (![".", ".."].includes(tribe) && !tribesdns[tribe]) {
|
|
await apxtri.setuptribe(tribe, conf);
|
|
}
|
|
});
|
|
} else {
|
|
const initconf = fs.readJsonSync(
|
|
"../adminapi/apxtri/setup/initadminapi.json"
|
|
);
|
|
await apxtri.setuptribe("adminapi", initconf);
|
|
}
|
|
// run api with update conf
|
|
apxtri.runexpress(
|
|
fs.readJsonSync(`../adminapi/objects/tribes/idx/tribes_dns.json`),
|
|
fs.readJSONSync("../adminapi/objects/tribes/itm/adminapi.json")
|
|
);
|
|
};
|
|
apxtri.getip = async () => {
|
|
/**
|
|
* Return json with public IP and network interfaces with their local IP
|
|
* {WANIP:"public IP","eth0":"localIPoneth0",...}
|
|
*/
|
|
const network = {};
|
|
const urlgetip = `https://api.ipify.org?format=json`;
|
|
const getdata = await fetch(urlgetip);
|
|
if (getdata.ok) {
|
|
const data = await getdata.json();
|
|
network.WANIP = data.ip;
|
|
}
|
|
const os = await import("os");
|
|
const interfaces = os.networkInterfaces();
|
|
for (const name in interfaces) {
|
|
for (const iface of interfaces[name]) {
|
|
// Check for IPv4 and make sure it's not an internal (loopback) address
|
|
if (iface.family === "IPv4" && !iface.internal) {
|
|
network[name] = iface.address;
|
|
//localIP = iface.address;
|
|
//console.log(`Local network IP (${name}): ${localIP}`);
|
|
}
|
|
}
|
|
}
|
|
return network;
|
|
};
|
|
apxtri.setuptribe = async (tribe, conf) => {
|
|
let inittribe;
|
|
if (tribe == "adminapi") {
|
|
console.log(
|
|
"Nice to meet you, this is a first install hope you'll enjoy, if any issues please request on discord https://discord.gg/jF7cAkZn"
|
|
);
|
|
try {
|
|
inittribe = conf;
|
|
inittribe.townpath = __dirname.replace("/adminapi/apxtri", "");
|
|
const townnation = inittribe.townpath.split("/").slice(-1)[0].split("-");
|
|
inittribe.townId = townnation[0];
|
|
inittribe.nationId = townnation[1];
|
|
inittribe.dns.push(
|
|
`admin.adminapi.${inittribe.townId}.${inittribe.nationId}`
|
|
);
|
|
} catch (err) {
|
|
console.log("Your town folder must be something townid-nation");
|
|
}
|
|
} else {
|
|
console.log(`a new tribe called ${tribe} was detected`);
|
|
const adminapiconf = fs.readJSONSync(
|
|
"../adminapi/objects/tribes/itm/adminapi.json"
|
|
);
|
|
inittribe = {
|
|
tribeId: tribe,
|
|
townpath: __dirname.replace("/adminapi/apxtri", ""),
|
|
dns: [`admin.${tribe}.${conf.townId}.${conf.nationId}`],
|
|
status: "unchain",
|
|
nationId: conf.nationId,
|
|
townId: conf.townId,
|
|
activelog: [],
|
|
api: { port: adminapiconf.api.port },
|
|
socket: { port: adminapiconf.socket.port },
|
|
};
|
|
}
|
|
inittribe.sudoUser = process.env.USER;
|
|
//check nation exist and town does not exist
|
|
if (
|
|
!fs.existsSync("../adminapi/objects/nations/idx/lst_nationId.json") ||
|
|
!fs.existsSync("../adminapi/objects/towns/idx/lst_townId.json")
|
|
) {
|
|
console.log(
|
|
`Sorry, check setup.sh process that was not able to init your adminapi/objects `
|
|
);
|
|
process.exit(0);
|
|
}
|
|
fs.outputJSONSync(`../adminapi/objects/tribes/itm/${tribe}.json`, inittribe, {
|
|
space: 2,
|
|
});
|
|
if (!fs.existsSync("../adminapi/objects/tribes/conf.json")) {
|
|
fs.outputJSONSync("../adminapi/objects/tribes/conf.json", {
|
|
name: "tribes",
|
|
schema: "adminapi/schema/tribes.json",
|
|
lastupdate: 0,
|
|
});
|
|
}
|
|
const lst_tribeIdpath = "../adminapi/objects/tribes/idx/lst_tribeId.json";
|
|
let lsttribe = fs.existsSync(lst_tribeIdpath)
|
|
? fs.readJsonSync(lst_tribeIdpath)
|
|
: [];
|
|
lsttribe.push(tribe);
|
|
fs.outputJSONSync(lst_tribeIdpath, lsttribe);
|
|
const tribes_dnspath = "../adminapi/objects/tribes/idx/tribes_dns.json";
|
|
const tribedns = fs.existsSync(tribes_dnspath)
|
|
? fs.readJsonSync(tribes_dnspath)
|
|
: {};
|
|
tribedns[tribe] = inittribe.dns;
|
|
fs.outputJSONSync(tribes_dnspath, tribedns);
|
|
const tribespath = "../adminapi/objects/tribes/idx/tribes.json";
|
|
const tribes = fs.existsSync(tribespath) ? fs.readJSONSync(tribespath) : {};
|
|
tribes[tribe] = inittribe;
|
|
fs.outputJSONSync(tribespath, tribes, { space: 2 });
|
|
|
|
// check nginx conf and eventually change if not starting by user "current user";
|
|
let etcnginx = fs.readFileSync("/etc/nginx/nginx.conf", "utf8");
|
|
if (etcnginx.split("\n")[0] !== `user ${inittribe.sudoUser};`) {
|
|
inittribe.mainpath = inittribe.townpath.replace(
|
|
`/${inittribe.townId}-${inittribe.nationId}`,
|
|
""
|
|
);
|
|
const nginxmain = fs.readFileSync(
|
|
"../adminapi/apxtri/setup/nginx.maincf",
|
|
"utf8"
|
|
);
|
|
console.log("Modify /etc/nginx/nginx.conf");
|
|
fs.outputFileSync(
|
|
"/etc/nginx/nginx.conf",
|
|
Mustache.render(nginxmain, inittribe),
|
|
{ asAdmin: true }
|
|
);
|
|
}
|
|
// add conf for http://adminapx.adminapi
|
|
const nginxapx = fs.readFileSync(
|
|
"../adminapi/apxtri/setup/nginx.wwwscf",
|
|
"utf8"
|
|
);
|
|
inittribe.website = "admin";
|
|
fs.outputFileSync(
|
|
`../${tribe}/nginx/${inittribe.website}.${tribe}.${inittribe.townId}.${inittribe.nationId}.conf`,
|
|
Mustache.render(nginxapx, inittribe)
|
|
);
|
|
fs.outputFileSync(
|
|
`../${tribe}/objects/wwws/admin/dist/index_en.html`,
|
|
`<h1>Wellcome in ${tribe}</h1>`,
|
|
"utF8"
|
|
);
|
|
// add hosts entry for local access
|
|
// this command is ran by the setup.sh
|
|
// grep -q '^127.0.0.1 adminapx.adminapi' /etc/hosts || echo '127.0.0.1 adminapx.adminapi' | sudo tee -a /etc/hosts > /dev/null
|
|
const ips = await apxtri.getip();
|
|
const nginxrestart =
|
|
inittribe.nginx && inittribe.nginx.restart
|
|
? inittribe.nginx.restart
|
|
: fs.readJSONSync("../adminapi/apxtri/setup/initadminapi.json").nginx
|
|
.restart;
|
|
const { exec } = require("child_process");
|
|
exec(nginxrestart, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
|
|
process.exit(0);
|
|
} else {
|
|
const etchosts = Object.values(ips)
|
|
.map((ip) => `${ip} ${inittribe.dns.join(" ")}`)
|
|
.join("\n ");
|
|
console.log(
|
|
`\x1b[42m###############################################################################################################\x1b[0m\n\x1b[42mWellcome into this fresh apxtri install, currently running as "$ yarn dev".\n To access and set up a public domain name, add lines in file /etc/hosts into the machine you want to use to access:\n\x1b[0m\x1b[32m ${etchosts} \x1b[0m \x1b[42m\n Then open in your local browser \x1b[0m\x1b[32m http:// ${inittribe.dns.join(
|
|
" "
|
|
)} \x1b[0m \x1b[42m \nFor local dev continue with 'yarn dev'\nTo run as a production run 'yarn startapx' or 'yarn restartapx' then pm2 monitor your production process.\n\x1b[0m\n\x1b[42m###############################################################################################################\x1b[0m`
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
apxtri.runexpress = async (tribesdns, conf) => {
|
|
const Odmdb = require(path.resolve("./apxtri/models/Odmdb.js"));
|
|
let tribeIds = Object.keys(tribesdns);
|
|
// context is store in /itm/tribename.json ={contexte:{routes:[],models:[{model:,tplstringslg:[]}]}
|
|
// 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)
|
|
let routes = [];
|
|
let doms = [];
|
|
tribeIds.forEach((t) => {
|
|
tribesdns[t].forEach((d) => {
|
|
const dm = d.split(".").slice(-2).join(".");
|
|
if (!doms.includes(dm)) doms.push(dm);
|
|
//reindex database attention check dev-ants/.. a bug was fixed
|
|
glob.sync(`../${t}/objects/*`).forEach((o) => {
|
|
//console.log("reindex: ", o);
|
|
Odmdb.runidx(o);
|
|
});
|
|
});
|
|
const context = {};
|
|
const pathtr = path.resolve(`../${t}`);
|
|
context.routes = [];
|
|
tribroutes = glob.sync(`${pathtr}/apxtri/routes/*.js`).map((f) => {
|
|
const rt = `/${t}/${path.basename(f, ".js")}`;
|
|
context.routes.push(rt);
|
|
return { url: rt, route: f };
|
|
});
|
|
context.models = glob.sync(`${pathtr}/apxtri/models/*.js`).map((f) => {
|
|
const modname = `${path.basename(f, ".js")}`;
|
|
return {
|
|
model: modname,
|
|
tplstrings: glob
|
|
.sync(`${pathtr}/objects/tplstrings/${modname}_*.json`)
|
|
.map((l) => path.basename(l, ".json").split("_")[1]),
|
|
};
|
|
});
|
|
//console.log(context.routes);
|
|
//console.log(context.models);
|
|
//const conft = `../itm/${t}.json`;
|
|
//const ctx = fs.readJsonSync(conft);
|
|
//ctx.context = context;
|
|
//fs.outputJSONSync(conft, ctx, { spaces: 2 });
|
|
routes = routes.concat(tribroutes);
|
|
});
|
|
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
|
|
tribeIds.forEach((t) => {
|
|
app.use(`/${t}`, bodyParser.urlencoded(conf.api.bodyparse.urlencoded));
|
|
app.use(`/${t}`, bodyParser.json(conf.api.bodyparse.json));
|
|
// To set depending of post put json data size to send
|
|
app.use(`/${t}`, express.json(conf.api.json));
|
|
});
|
|
app.disable("x-powered-by"); // for security
|
|
app.locals.tribeids = tribeIds;
|
|
const currentmod = "apxtri";
|
|
const log = conf.api.activelog
|
|
? conf.api.activelog.includes(currentmod)
|
|
: false;
|
|
console.log(
|
|
currentmod,
|
|
" Allowed DOMs to access to this apxtri server:",
|
|
JSON.stringify(doms)
|
|
);
|
|
console.log(currentmod, " app.locals.tribeids", app.locals.tribeids);
|
|
|
|
// Cors management
|
|
let regtxt = "(test";
|
|
doms.forEach((d) => {
|
|
regtxt += `|${d.replace(/\./g, "\\.")}`;
|
|
});
|
|
regtxt += ")$";
|
|
// let cor = false;whatwg-url
|
|
const regorigin = new RegExp(regtxt);
|
|
app.use((req, res, next) => {
|
|
let cor = false;
|
|
//console.log(req.headers)
|
|
if (req.headers.origin == undefined) {
|
|
//used for mobile access
|
|
cor = true;
|
|
} else {
|
|
cor = regorigin.test(req.headers.origin);
|
|
}
|
|
if (!cor)
|
|
console.log(
|
|
`The domain name ${req.headers.origin} is not allow to access for CORS settings, add it in itm/tribename.json in dns current origin allow are filter by ${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);
|
|
console.log(currentmod, conf.api);
|
|
}
|
|
//Listen event file for each tribe
|
|
// @TODO à ajouter ici
|
|
const ips = await apxtri.getip();
|
|
app.listen(conf.api.port, () => {
|
|
let webaccess = `/api/ waits request on port:${conf.api.port} `;
|
|
let localnet = "/etc/hosts for your local network:\n";
|
|
let publicnet = "/etc/hosts for internet network:\n";
|
|
conf.dns.forEach((u) => {
|
|
//webaccess += `http://${u}/api/ `;
|
|
Object.keys(ips).forEach((ik) => {
|
|
if (ik == "WANIP") {
|
|
publicnet += `${ips.WANIP} ${u} \n`;
|
|
} else {
|
|
localnet += `${ips[ik]} ${u} \n`;
|
|
}
|
|
});
|
|
});
|
|
console.log(
|
|
`\x1b[42m\x1b[37m${webaccess} \nOpen in your browser http(s):// ${conf.dns.join(
|
|
" "
|
|
)} to manage this apXtri town. \nCheck your network conf \n${localnet} ${publicnet}\nMore in README's project.\nTo get support ask \x1b[0m\x1b[32m in discord https://discord.gg/jF7cAkZn `
|
|
);
|
|
console.log(
|
|
"\x1b[42m\x1b[37m \n",
|
|
" Made with love for people's freedom, enjoy !!! ",
|
|
"\x1b[0m"
|
|
);
|
|
});
|
|
};
|
|
apxtri.main();
|