forked from apxtri/apxtrib
316 lines
11 KiB
JavaScript
Executable File
316 lines
11 KiB
JavaScript
Executable File
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/apxtrib/apxtrib/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(`${process.env.dirtown}/conf.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 apxtrib.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 apxtrib.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 apxtrib nationId:ants townId:devfarm dns:devfarm-ants
|
|
* if no parammeter 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 apxtrib as /townId-nationId/conf.json ...
|
|
*/
|
|
|
|
const setconf = (param) => {
|
|
// set conf from argv = param={nationId,townId,dns}
|
|
console.log(
|
|
`RUNNING A NEW SETUP with nation ${param.nationId} and town ${param.townId} to be accessible in dns http://${param.dns}`
|
|
);
|
|
fs.outputJsonSync(
|
|
`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`,
|
|
{
|
|
nationId: param.nationId,
|
|
townId: param.townId,
|
|
dns: [param.dns],
|
|
comment:
|
|
"Auto generate setup from apxtrib after node apxtrib nationId:value townId:value dns:domaine_to_access",
|
|
},
|
|
{ space: 2 }
|
|
);
|
|
// Add this town localy
|
|
const townid = {
|
|
townId: param.townId,
|
|
nationId: param.nationId,
|
|
dns: param.dns,
|
|
IP: "127.0.0.1",
|
|
status: "unchain",
|
|
tribes: [],
|
|
};
|
|
const townidkey = {};
|
|
townidkey[param.townId] = townid;
|
|
fs.outputJsonSync(`./nationchains/towns/idx/townId_all.json`, townidkey);
|
|
fs.outputJsonSync(`./nationchains/towns/itm/${param.townId}.json`, townid);
|
|
initconf = fs.readJsonSync("./adminapi/www/adminapx/conf/initconf.json");
|
|
initconf.dirapi = __dirname;
|
|
initconf.dirtown = path.resolve(
|
|
`${__dirname}/../${param.townId}-${param.nationId}`
|
|
);
|
|
initconf.nationId = param.nationId;
|
|
initconf.townId = param.townId;
|
|
initconf.sudoerUser = process.env.USER;
|
|
if (!initconf.dns.includes(param.dns)) {
|
|
initconf.dns.push(param.dns);
|
|
}
|
|
initconf.nginx.include.push(`${initconf.dirapi}/adminapi/www/nginx_*.conf`);
|
|
initconf.nginx.include.push(
|
|
path.resolve(
|
|
`../${param.townId}-${param.nationId}/tribes/**/www/nginx_*.conf`
|
|
)
|
|
);
|
|
initconf.nginx.logs = `${initconf.dirtown}/logs/nginx/adminapx`;
|
|
initconf.nginx.website = "adminapx";
|
|
initconf.nginx.fswww = `${__dirname}/adminapi/www`;
|
|
initconf.nginx.pageindex = "index_en.html";
|
|
const { exec } = require("child_process");
|
|
exec(
|
|
`sudo chown -R ${process.env.USER}:${process.env.USER} /etc/nginx`,
|
|
(error, stdout, stderr) => {
|
|
if (error) {
|
|
console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
|
|
console.log("impossible to change owner of /etc/nginx by phil:phil");
|
|
process.exit();
|
|
} else {
|
|
console.log(
|
|
`successfull sudo chown -R ${process.env.USER}:${process.env.USER} /etc/nginx`
|
|
);
|
|
}
|
|
}
|
|
);
|
|
fs.outputJsonSync(
|
|
`../${param.townId}-${param.nationId}/conf.json`,
|
|
initconf,
|
|
{ space: 2 }
|
|
);
|
|
fs.ensureDirSync(`../${param.townId}-${param.nationId}/logs/nginx`);
|
|
const nginxconf = fs.readFileSync(
|
|
"./adminapi/www/adminapx/conf/nginx.conf.mustache",
|
|
"utf8"
|
|
);
|
|
const proxyparams = fs.readFileSync(
|
|
"./adminapi/www/adminapx/conf/nginxproxyparams.mustache",
|
|
"utf8"
|
|
);
|
|
const websiteconf = fs.readFileSync(
|
|
"./adminapi/www/adminapx/conf/nginxmodelwebsite.conf.mustache",
|
|
"utf8"
|
|
);
|
|
|
|
// saved and change nginx conf
|
|
if (!fs.existsSync("/etc/nginx/nginxconf.saved")) {
|
|
fs.moveSync("/etc/nginx/nginx.conf", "/etc/nginx/nginxconf.saved");
|
|
console.log(
|
|
"your previous /etc/nginx/nginx.conf was backup in /etc/nginx/nginxconf.saved"
|
|
);
|
|
}
|
|
fs.outputFileSync(
|
|
"/etc/nginx/nginx.conf",
|
|
mustache.render(nginxconf, initconf),
|
|
"utf8"
|
|
);
|
|
fs.outputFileSync(
|
|
"/etc/nginx/proxy_params",
|
|
mustache.render(proxyparams, initconf),
|
|
"utf8"
|
|
);
|
|
fs.outputFileSync(
|
|
`${__dirname}/adminapi/www/nginx_adminapx.conf`,
|
|
mustache.render(websiteconf, initconf),
|
|
"utf8"
|
|
);
|
|
exec(initconf.nginx.restart, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
|
|
//@todo supprimer la derniere config nginx et relancer
|
|
fs.moveSync("/etc/nginx/nginxconf.saved", "/etc/nginx/nginx.conf");
|
|
console.log("Restart yarn dev");
|
|
} else {
|
|
console.log(`ready to use http://${param.dns}`);
|
|
}
|
|
});
|
|
};
|
|
// 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 (
|
|
Object.keys(param).length > 0 &&
|
|
param.nationId &&
|
|
param.townId &&
|
|
param.dns
|
|
) {
|
|
setconf(param);
|
|
}
|
|
// From git setup-xx is set to nationId:ant townId:farmdev (keyword for dev)
|
|
const infotown = fs.readJsonSync(
|
|
`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`
|
|
);
|
|
|
|
if (
|
|
!fs.existsSync(
|
|
path.resolve(
|
|
`${__dirname}/../${infotown.townId}-${infotown.nationId}/conf.json`
|
|
)
|
|
) ||
|
|
!fs.existsSync(`${__dirname}/adminapi/www/nginx_adminapx.conf`)
|
|
) {
|
|
// Run setup with information setup_xx.json
|
|
setconf(infotown);
|
|
}
|
|
const conf = require(path.resolve(
|
|
`${__dirname}/../${infotown.townId}-${infotown.nationId}/conf.json`
|
|
));
|
|
|
|
process.env.dirtown = conf.dirtown;
|
|
|
|
// Create and update ./nationchains
|
|
|
|
const { updateobjectsfromfreshesttown } = require("./api/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(`${conf.dirtown}/tribes/idx/tribeId_all.json`)) {
|
|
tribelist = fs.readJsonSync(`${conf.dirtown}/tribes/idx/tribeId_all.json`);
|
|
}
|
|
let doms = conf.dns; // only dns of town during the init process
|
|
let tribeIds = [];
|
|
let routes = glob.sync(`${conf.dirapi}/api/routes/*.js`).map((f) => {
|
|
return { url: `/${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);
|
|
});
|
|
console.log("Allowed DOMs to access to this apxtrib server: ", 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.locals.tribeids = tribeIds;
|
|
console.log("app.locals.tribeids", app.locals.tribeids);
|
|
// Cors management
|
|
const corsOptions = {
|
|
origin: (origin, callback) => {
|
|
if (origin === undefined) {
|
|
callback(null, true);
|
|
} else if (origin.indexOf("chrome-extension") > -1) {
|
|
callback(null, true);
|
|
} else {
|
|
//console.log( 'origin', origin )
|
|
//marchais avant modif eslint const rematch = ( /^https?\:\/\/(.*)\:.*/g ).exec( origin )
|
|
const rematch = /^https?:\/\/(.*):.*/g.exec(origin);
|
|
//console.log( rematch )
|
|
let tmp = origin.replace(/http.?:\/\//g, "").split(".");
|
|
|
|
if (rematch && rematch.length > 1) tmp = rematch[1].split(".");
|
|
//console.log( 'tmp', tmp )
|
|
let dom = tmp[tmp.length - 1];
|
|
if (tmp.length > 1) {
|
|
dom = `${tmp[tmp.length - 2]}.${tmp[tmp.length - 1]}`;
|
|
}
|
|
console.log(
|
|
`origin: ${origin}, dom:${dom}, CORS allowed? : ${doms.includes(dom)}`
|
|
);
|
|
if (doms.includes(dom)) {
|
|
callback(null, true);
|
|
} else {
|
|
console.log(`Origin is not allowed by CORS`);
|
|
callback(new Error("Not allowed by CORS"));
|
|
}
|
|
}
|
|
},
|
|
exposedHeaders: Object.keys(conf.api.exposedHeaders),
|
|
};
|
|
// CORS
|
|
app.use(cors(corsOptions));
|
|
// Static Routes // try to use nginx route instead in comments
|
|
/*app.use( express.static( `${__dirname}/nationchains/tribes/${conf.mayorId}/www/cdn/public`, {
|
|
dotfiles: 'allow'
|
|
} ) );
|
|
*/
|
|
// Routers add any routes from /routes and /plugins
|
|
let logroute = "Routes available on this apxtrib instance: ";
|
|
|
|
routes.forEach((r) => {
|
|
try {
|
|
logroute += r.url + "|" + r.route;
|
|
app.use(r.url, require(r.route));
|
|
} catch (err) {
|
|
logroute += " (err check it)";
|
|
console.log("raise err-:", err);
|
|
}
|
|
});
|
|
console.log(logroute);
|
|
if (infotown.townId == "devfarm") {
|
|
console.log(
|
|
`\x1b[42m############################################################################################\x1b[0m\n\x1b[42mThis is dev conf to switch this as production, you must run:\n 1 - 'yarn dev nationId:ants townId:usbfarm dns:usbfarm-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 smae current dns,\n * dns domaine that has to redirect 80/443 into this server (example wall-ants.ndda.fr redirect to 213.32.65.213 ).\n Check README's project to learn more.\x1b[0m\n\x1b[42m############################################################################################\x1b[0m`
|
|
);
|
|
}
|
|
app.listen(conf.api.port, () => {
|
|
let webaccess = `check in your browser that api works`;
|
|
conf.dns.forEach((u) => {
|
|
webaccess += `http://${u}:${conf.api.port}`;
|
|
});
|
|
console.log(webaccess);
|
|
});
|
|
console.log(
|
|
"\x1b[42m\x1b[37m",
|
|
"Made with love for people's freedom, enjoy !!!",
|
|
"\x1b[0m"
|
|
);
|