1
0
forked from apxtri/apxtri

add msg in case unconsistent key

This commit is contained in:
philc 2023-12-29 13:38:47 +01:00
parent ed8a747b0b
commit c5899f21e4
15 changed files with 6548 additions and 3483 deletions

View File

@ -8,6 +8,10 @@ const cors = require("cors");
const express = require("express");
const process = require("process");
const l=require('./tools/log.js');
l.showlog= true; // force log as well in prod and dev
l.context="apxtri";
/*******************************************
SEE https://gitea.ndda.fr/apxtri/apxtri/wiki/Devrules
@ -42,9 +46,8 @@ To share configuration :
// 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."
);
l.og(
"\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 = {};
@ -54,13 +57,7 @@ argv.slice(2).forEach((arg) => {
param[kv[0]] = kv[1];
}
});
const log=(info,mode)=>{
// with yarn dev => mode=dev show only log for dev
// to check other => node apxtrie mode:bug for example
// if mode is not define then it log it
if (!mode || param.mode==mode) console.log(info)
}
if (!fs.existsSync('..conf/townconf.json')){
if (!fs.existsSync('../conf/townconf.json')){
// This is a first install
const nam= path.resolve('..').split('/').slice(-1)[0].split('-');
const town=nam[0]
@ -159,7 +156,7 @@ Object.keys(tribelist).forEach((t) => {
});
tribeIds.push(t);
});
console.log("Allowed DOMs to access to this apxtri server: ", doms);
l.og("Allowed DOMs to access to this apxtri server:",JSON.stringify(doms));
const app = express();
// load express parameter from conf
@ -173,7 +170,7 @@ app.use(express.json());
app.use(bodyParser.json(conf.api.bodyparse.json));
app.disable('x-powered-by');// for security
app.locals.tribeids = tribeIds;
console.log("app.locals.tribeids", app.locals.tribeids);
l.og("app.locals.tribeids", app.locals.tribeids);
// Cors management
const corsOptions = {
origin: (origin, callback) => {
@ -186,16 +183,16 @@ const corsOptions = {
callback(null, true);
} else {
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 )
//l.og( 'tmp', tmp );
let dom = tmp[tmp.length - 1];
if (tmp.length > 1) {
dom = `${tmp[tmp.length - 2]}.${tmp[tmp.length - 1]}`;
}
console.log(
l.og(
`origin: ${origin}, dom:${dom}, CORS allowed? : ${doms.includes(dom)}`
);
if (doms.includes(dom)) {
@ -218,19 +215,20 @@ app.use(cors(corsOptions));
let logroute = "Routes available on this apxtri instance:\n ";
routes.forEach((r) => {
try {
logroute += r.url.padEnd(30,' ') + r.route +"\n ";
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);
l.og("raise err-:", err);
}
});
console.log(logroute);
if (param.mode && param.mode=='dev') {
console.log(logroute)
if (process.env.NODE_MODE=="dev") {
console.log(
`\x1b[42m############################################################################################\x1b[0m\n\x1b[42mThis is dev conf accessible in http://devfarm-ants 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 To work with apxweb for the front use http://defarm-ants/apxweb/www/tplname/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 `;
conf.dns.forEach((u) => {

View File

@ -1,4 +1,7 @@
const conf = require(`../../conf/townconf.json`);
const l=require('../tools/log.js');
//l.showlog= true; // force log as well in prod and dev
l.context="apxtri";
/**
* @api {get} http://header/CheckHeaders - CheckHeaders
* @apiGroup Middlewares
@ -67,13 +70,13 @@ const checkHeaders = (req, res, next) => {
// store in session the header information
req.session.header = header;
// Each header have to be declared
if (missingheader != "") {
if (missingheader.length>0) {
// bad request
return res.status(400).json({
status:400,
ref: "middlewares",
msg: "missingheader",
data: missingheader,
data: {missingheader},
});
}
//console.log( req.app.locals.tribeids )
@ -92,7 +95,9 @@ const checkHeaders = (req, res, next) => {
});
}
if (!conf.api.languages.includes(header.xlang)) {
console.log("warning language requested does not exist force to english");
const info="warning language requested does not exist force to english";
l.og(info);
l.ogprod(req.header("xtribe"),info);
header.xlang = "en";
}
//set anonymous profil

View File

@ -6,6 +6,9 @@ const glob = require("glob");
// const openpgp = require("/media/phil/usbfarm/apxtri/node_modules/openpgp/dist/node/openpgp.js");
const openpgp = require("openpgp");
const l=require('../tools/log.js');
l.showlog= false; // force log as well in prod and dev
l.context="isAuthenticated";
/**
* @api {get} http://header/istauthenticated - isAuthenticated
* @apiGroup Middlewares
@ -28,21 +31,18 @@ const openpgp = require("openpgp");
*
**/
const isAuthenticated = async (req, res, next) => {
/*console.log('PASSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS')
/*
console.log(__dirname)
console.log(path.resolve('../tmp/tokens'))
if (fs.existsSync('../tmp/tokens')) console.log('pass A')
if (fs.existsSync('../tmp/tokens')) console.log('pass B')
*/
const withlog = true;
const currentday = dayjs().date();
fs.ensureDirSync(`../tmp/tokens`);
let menagedone = fs.existsSync(
`../tmp/tokens/menagedone${currentday}`
);
if (withlog)
console.log(`menagedone${currentday} was it done today?:${menagedone}`);
l.og(`menagedone${currentday} was it done today?:${menagedone}`);
if (!menagedone) {
// clean oldest
const tsday = dayjs().valueOf(); // now in timestamp format
@ -57,13 +57,17 @@ const isAuthenticated = async (req, res, next) => {
fs.remove(f);
}
});
//clean tmp
glob.sync(`../tmp/*.txt`).forEach((f) => {
fs.remove(f);
});
fs.outputFile(
`../tmp/tokens/menagedone${currentday}`,
"done by middleware/isAUthenticated"
);
}
//Check register in tmp/tokens/
if (withlog) console.log("isAuthenticate?", req.session.header, req.body);
l.og("isAuthenticate?", req.session.header, req.body);
const resnotauth = {
ref: "middlewares",
@ -77,7 +81,7 @@ const isAuthenticated = async (req, res, next) => {
req.session.header.xalias == "anonymous" ||
req.session.header.xhash == "anonymous"
) {
if (withlog) console.log("alias anonymous means not auth");
l.og("alias anonymous means not auth");
resnotauth.status = 401;
return res.status(resnotauth.status).json(resnotauth);
}
@ -96,7 +100,7 @@ const isAuthenticated = async (req, res, next) => {
const failstamp = `../tmp/tokens/${alias}.json`;
if (action == "clean") {
//to reinit bruteforce checker
if (withlog) console.log("try to clean penalty file ", failstamp);
l.og("try to clean penalty file ", failstamp);
fs.remove(failstamp, (err) => {
if (err) console.log("Check forcebrut ", err);
});
@ -107,17 +111,17 @@ const isAuthenticated = async (req, res, next) => {
stamp.lastfail = dayjs().format();
stamp.numberfail += 1;
fs.outputJSON(failstamp, stamp);
if (withlog) console.log("penalty:", stamp);
l.og("penalty:", stamp);
await sleep(stamp.numberfail * 100); //increase of 0,1 second the answer time per fail
if (withlog) console.log("time out penalty");
l.og("time out penalty");
}
};
if (!fs.existsSync(tmpfs)) {
// need to check detached sign
let publickey = "";
console.log(process.cwd());
console.log(process.env.PWD);
console.log(__dirname);
l.og(process.cwd());
l.og(process.env.PWD);
l.og(__dirname);
const aliasinfo = `../nationchains/pagans/itm/${req.session.header.xalias}.json`;
if (fs.existsSync(aliasinfo)) {
publickey = fs.readJsonSync(aliasinfo).publickey;
@ -126,38 +130,41 @@ const isAuthenticated = async (req, res, next) => {
publickey = req.body.publickey;
}
if (publickey == "") {
if (withlog) console.log("alias unknown");
l.og("alias unknown");
resnotauth.status = 404;
resnotauth.data.xaliasexists = false;
return res.status(resnotauth.status).send(resnotauth);
}
if (withlog) console.log("publickey", publickey);
l.og("publickey", publickey);
if (publickey.substring(0, 31) !== "-----BEGIN PGP PUBLIC KEY BLOCK") {
if (withlog)
console.log("Publickey is not valid as armored key:", publickey);
l.og("Publickey is not valid as armored key:", publickey);
await bruteforcepenalty(req.session.header.xalias, "penalty");
resnotauth.status = 404;
return res.status(resnotauth.status).send(resnotauth);
}
const clearmsg = Buffer.from(req.session.header.xhash, "base64").toString();
if (clearmsg.substring(0, 10) !== "-----BEGIN") {
if (withlog)
console.log("xhash conv is not valid as armored key:", clearmsg);
l.og("xhash conv is not valid as armored key:", clearmsg);
await bruteforcepenalty(req.session.header.xalias, "penalty");
resnotauth.status = 404;
return res.status(resnotauth.status).send(resnotauth);
}
if (withlog) console.log("clearmsg", clearmsg);
l.og("clearmsg", clearmsg);
let signedMessage=""
const pubkey = await openpgp.readKey({ armoredKey: publickey });
const signedMessage = await openpgp.readCleartextMessage({
cleartextMessage: clearmsg,
});
try{
signedMessage = await openpgp.readCleartextMessage({
cleartextMessage: clearmsg,
});
}catch(err){
return res.status(422).send({status:422,ref:"Middleware",msg:"unconsistentcleartextmessage",data:{xhash:req.session.header.xhash,clearmsg}})
}
const verificationResult = await openpgp.verify({
message: signedMessage,
verificationKeys: pubkey,
});
if (withlog) console.log(verificationResult);
if (withlog) console.log(verificationResult.signatures[0].keyID.toHex());
l.og(verificationResult);
l.og(verificationResult.signatures[0].keyID.toHex());
try {
await verificationResult.signatures[0].verified;
if (
@ -165,8 +172,7 @@ const isAuthenticated = async (req, res, next) => {
`${req.session.header.xalias}_${req.session.header.xdays}`
) {
resnotauth.msg = "signaturefailled";
if (withlog)
console.log(
l.og(
`message recu:${verificationResult.data} , message attendu:${req.session.header.xalias}_${req.session.header.xdays}`
);
await bruteforcepenalty(req.session.header.xalias, "penalty");
@ -175,20 +181,18 @@ const isAuthenticated = async (req, res, next) => {
}
} catch (e) {
resnotauth.msg = "signaturefailled";
if (withlog) console.log("erreur", e);
l.og("erreur", e);
await bruteforcepenalty(req.session.header.xalias, "penalty");
resnotauth.status = 401;
return res.status(resnotauth.status).send(resnotauth);
}
// authenticated then get person profils (person = pagan for a xtrib)
const person = `${process.env.dirtown}/tribes/${req.session.header.xtribe}/objects/persons/itm/${req.session.header.xalias}.json`;
if (withlog) {
console.log("Profils tribe/app management");
console.log("person", person);
}
l.og("Profils tribe/app management");
l.og("person", person);
if (fs.existsSync(person)) {
const infoperson = fs.readJSONSync(person);
console.log(infoperson);
l.og(infoperson);
infoperson.profils.forEach((p) => {
if (!req.session.header.xprofils.includes(p)) req.session.header.xprofils.push(p);
})
@ -201,7 +205,7 @@ const isAuthenticated = async (req, res, next) => {
req.session.header.xprofils = fs.readJSONSync(tmpfs);
}
bruteforcepenalty(req.session.header.xalias, "clean");
console.log(`${req.session.header.xalias} Authenticated`);
l.og(`${req.session.header.xalias} Authenticated`);
next();
};
module.exports = isAuthenticated;

View File

@ -24,6 +24,48 @@ Notifications.get = (alias, tribeId) => {
};
};
/**
* Register an typekey(email) or (phone) key into mailinglist for a tribe
*
*/
Notifications.registertolist = (key, typekey, tribe, mlist, srckey, uuid) => {
key = key.toLowerCase();
if (!Checkjson.testformat(key, typekey))
return {
status: 400,
ref: "Notifications",
msg: "formaterreur",
data: { fielderr: typekey, format: typekey },
};
const destin = `../../../nationchains/tribes/${tribe}/contacts/${typecontact}_${mlist}.json`;
const filestorage = fs.existsSync(destin) ? fs.readJsonSync(destin) : {};
if (filestorage[key]) {
filestorage[key].dt_update = dayjs().toISOString();
if (!filestorage[key].srckeys.includes(srckey))
filestorage[key].srckeys.push(srckey);
if (!filestorage[key].uuids.includes(uuid))
filestorage[key].uuids.push(uuid);
}else{
filestorage[key].dt_create=dayjs().toISOString();
filestorage[key].srckeys=[srckey];
filestorage[key].uuids=[uuid]
}
fs.outputJSONSync(destin, filestorage);
return {status:200,ref:"Notifications",msg:"register",data:{key, typekey, tribe, mlist, srckey, uuid}}
}
/**
* Unsubscribe an eamil or phone from a mailinglist for a tribe
*/
Notifications.unsubscribefromlist = (body, header) => {
}
/**
* Message to send to an alias from an anonymous or not
*/
Notifications.sendcontact = (body, header) => {
}
Notifications.sendsms = async (data, tribeId) => {
/**
* Never use need wallet in mailjet to test
@ -172,7 +214,7 @@ Notifications.sendmail = async (data, tribe) => {
let confsmtp = conf.smtp;
const conftribfile = `../nationchains/tribes/itm/${tribe}.json`;
if (fs.existsSync(conftribfile)) {
const conftrib = fs.readJSONSync(conftribfile);
const conftrib = fs.readJSONSync(conftribfile);
confsmtp = conftrib.smtp;
if (!data.from) data.from = conftrib.emailcontact;
}
@ -181,12 +223,12 @@ Notifications.sendmail = async (data, tribe) => {
const transporter = await nodemailer.createTransport(confsmtp);
//@todo add attachments management
if (data.filelist) {
data.attachments=[];
data.attachments = [];
let missingfile = [];
data.filelist.forEach((fo) => {
if (fs.existsSync(fo.pathfile)){
}else{ missingfile.push(fo.pathfile);}
if (fs.existsSync(fo.pathfile)) {
} else { missingfile.push(fo.pathfile); }
});
if (missingfile.lenght > 0)
return {

View File

@ -299,15 +299,15 @@ Odmdb.r = (objectPathname, apxid, role) => {
return {
status: 403,
ref: "Odmdb",
msg: "forbidden",
data: { person: apxid },
msg: "profilnotallow",
data: { person: apxid, },
};
}
const data = {};
accessright.R.forEach((p) => {
data[p] = itm[p];
});
return { status: 200, ref: "Odmdb", msg: "found", data };
return { status: 200, ref: "Odmdb", msg: "profilallow", data };
};
/**
@ -336,7 +336,7 @@ Odmdb.ASUPreads = (objectPathname, apxidlist, role, propertiesfilter) => {
return {
status: 403,
ref: "Odmdb",
msg: "accessforbidden",
msg: "profilnotallow",
data: { crud: "R", accessright },
};
}
@ -492,7 +492,7 @@ Odmdb.cud = (objectPathname, crud, itm, role, runindex = true) => {
return {
status: 403,
ref: "Odmdb",
msg: "accessforbidden",
msg: "profilnotallow",
data: { crud, accessright },
};
}

View File

@ -1,5 +1,20 @@
{
"schemanotfound":"Schema not found in {{{fullpath}}}",
"pathnamedoesnotexist":"ObjectPath or objectName does not exist {{{indexpath}}}",
"objectfiledoesnotexist":"Requested index does not exist here: {{{objectpath}}}"
}
"alreadyexist": "An {{objectname}} object with the {{key}} key already exists with {{val}}",
"doesnotexist": "The {{objectname}} object does not exist with {{key}}:{{val}}",
"getschema": "Schema {{{conf.name}}}",
"schemanotfound": "Schema not found in {{{schemaPath}}}",
"pathnamedoesnotexist": "The directory does not exist {{{indexpath}}}",
"objectfiledoesnotexist": "The file does not exist {{{objectpath}}}",
"cudsuccessfull": "Update successful",
"successfulcreatewithoutemail":"Create without sending an email",
"successfulcreatewitemail":"Create you will receive an email",
"missingprimarykey": "Missing a primary key apxid to store and identify objects",
"unconsistencyapxidx": "The index {{name}} must contain at least {{apxid}} in objkey because keyval is not unique",
"profilnotallow": "As {{person}} your profiles are not allow, this action is not authorized",
"profilallow": "You are allowed for this action",
"successreindex": "Object reindexed from items, your indexes are up to date",
"indexexist":"The index exists",
"typenotavailable":"The type: {{type}} for the propertie: {{propertie}} of the object:{{objectPathname}} is not taken into account for indexing",
"objectslist":"List of objects from apxtri and {{tribe}}",
"errordelete":"Sorry, unable to delete this account"
}

View File

@ -10,7 +10,8 @@
"successfulcreatewitemail":"Créer vous allez recevoir un email",
"missingprimarykey": "Il manque une clé primaire apxid pour stocker et identifier les objects",
"unconsistencyapxidx": "L'index {{name}} doit contenir en objkey au moins {{apxid}} car keyval n'est pas unique",
"profilnotallow": "Vous n'avez pas le profil de {{profils}}, cette action n'est pas authorisée",
"profilnotallow": "Vous n'avez pas le profil pour faire cette action.",
"profilallow": "Vous avez été authorisé à faire cette action",
"successreindex": "Objet reindexé à partir des items, vos index sont à jour",
"indexexist":"L'indexe existe",
"typenotavailable":"Le type: {{type}} pour la propertie : {{propertie}} de l'object :{{objectPathname}} n'est pas pris en compte pour l'indexation",

View File

@ -1,8 +1,10 @@
{
"errrequest": "Backend seems not available",
"missingheader": "Some header miss to have a valid request: {{#data}} {{.}} {{/data}}",
"tribeiddoesnotexist": "Header xtribe: {{data.xtribe}} does not exist in this town you cannot access",
"authenticated": "Your alias{{{data.xalias}}} is authenticated",
"notauthenticated": "Your alias: {{data.xalias}} is not authenticated {{^data.aliasexists}} and this alias does not exist !{{/data.aliasexists}}",
"forbiddenAccessright": "Alias {{data.xalias}} has not access right to act {{data.action}} onto object {{data.object}} for tribe {{mor.xworkon}}"
"unconsistentpgp": "Your keys are not consistent {{err}}",
"missingheader": "Some header miss to have a valid request: {{#missinghearder}} {{.}} {{/missingheader}}",
"tribeiddoesnotexist": "Header xtribe: {{xtribe}} does not exist in this town you cannot access",
"unconsistentcleartextmessage":"Your xhash: {{xhash}} is not consistent as a clear msg {{{clearmsg}}}",
"authenticated": "Your alias: {{{xalias}}} is authenticated",
"notauthenticated": "Your alias: {{xalias}} is not authenticated {{^xaliasexists}} and this alias does not exist !{{/xaliasexists}}",
"signaturefailled": "Your signature is not valid for your alias."
}

View File

@ -1,10 +1,10 @@
{
"errrequest": "Le serveur ne semble pas répondre",
"unconsistentpgp": "Vos clés ne sont pas conforme {{err}}",
"missingheader": "Certains en-têtes manquent pour avoir une requête valide : {{#data}} {{.}} {{/data}}",
"tribeiddoesnotexist": "L'en-tête xtribe : {{data.xtribe}} n'existe pas dans cette ville, vous ne pouvez pas y accéder",
"authenticated": "Votre alias {{{data.xalias}}} est authentifié",
"notauthenticated": "Votre alias : {{data.xalias}} n'est pas authentifié {{^data.aliasexists}} et cet alias n'existe pas !{{/data.aliasexists}}",
"forbiddenAccessright": "L'alias {{data.xalias}} n'a pas le droit d'agir {{data.action}} sur l'objet {{data.object}} pour la tribu {{mor.xworkon}}",
"missingheader": "Certains en-têtes manquent pour avoir une requête valide : {{#missinghearder}} {{.}} {{/missingheader}}",
"tribeiddoesnotexist": "L'en-tête xtribe : {{xtribe}} n'existe pas dans cette ville, vous ne pouvez pas y accéder",
"unconsistentcleartextmessage":"Votre xhash: {{xhash}} n'est pas lisible par openpgp.js avec le clearmsg: {{{clearmsg}}}",
"authenticated": "Votre alias {{{xalias}}} est authentifié",
"notauthenticated": "Votre alias : {{xalias}} n'est pas authentifié {{^xaliasexists}} et cet alias n'existe pas !{{/xaliasexists}}",
"signaturefailled": "Desolé votre signature n'est pas valide pour cet alias."
}

6240
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,43 +12,19 @@
},
"scripts": {
"stoppm2": "pm2 stop apxtri.js",
"startpm2": "pm2 start apxtri.js --log-date-format 'DD-MM HH:mm:ss.SSS'",
"startpm2": "pm2 start apxtri.js mode:prod --log-date-format 'DD-MM HH:mm:ss.SSS'",
"deletepm2": "pm2 delete apxtri",
"restartpm2": "pm2 restart apxtri.js --log-date-format 'DD-MM HH:mm:ss.SSS'",
"startblockchain": "pm2 start models/Blockchains.js --log-date-format 'DD-MM HH:mm:ss:SSS'",
"logpm2": "pm2 logs apxtri.js --lines 200",
"dev": "node apxtri.js mode:dev",
"dev": "NODE_MODE=dev node apxtri.js",
"unittest": "node unittest.js",
"apidoc": "apidoc -i middlewares routes -o ../nationchains/tribes/adminapi/www/cdn/apidoc",
"apidocsmatchit": "apidoc -i ../nationchains/tribes/smatchit/api/middlewares ../nationchains/tribes/smatchit/api/routes -o ../nationchains/tribes/smatchit/www/apidoc"
},
"apidoc": {
"name": "apxtri",
"version": "1.0.0",
"title": "apiDoc for apxtri",
"description": "Core api documentation",
"url": "https://town.dns/api",
"order": [
"Middlewares",
"Odmdb",
"Nationchains"
],
"template": {
"forceLanguage": "en",
"showRequiredLabels": true,
"withCompare": true,
"withGenerator": true,
"aloneDisplay": false
},
"header": {
"title": "Introduction",
"filename": "header.md"
},
"footer": {
"title": "Best practices",
"filename": "footer.md"
}
"apidoc": "apidoc -c ../conf/apidoc/apidoc_$tribe.json -o ../nationchains/tribes/$tribe/www/cdn/apidoc/",
"publishtestwall": "scp -r /media/phil/usbfarm/apxtowns/dev-ants/nationchains/tribes/$space phil@wall-ants://home/phil/apxtowns/testwall-ants/nationchains/tribes/$space/..",
"publishwall": "scp -r /media/phil/usbfarm/apxtowns/dev-ants/nationchains/tribes/$space phil@wall-ants://home/phil/apxtowns/wall-ants/nationchains/tribes/$space/..",
"publishhome": "scp -r /media/phil/usbfarm/apxtowns/dev-ants/nationchains/tribes/$space phil@wall-ants://home/phil/apxtowns/wall-ants/nationchains/tribes/$space/.."
},
"commentscript": " tribe=tribeid yarn apidoc to build apidoc // space=adminapi/www/cdn/apidoc yarn publishtestwall ",
"maintainers": [
{
"name": "Philippe Colzy",
@ -83,7 +59,7 @@
"@editorjs/editorjs": "^2.26.5",
"apidoc": "^0.54.0",
"async": "^3.2.0",
"axios": "^0.21.1",
"axios": "^1.6.2",
"baunsu": "^0.2.3",
"bcrypt": "^5.0.0",
"cors": "^2.8.4",
@ -102,11 +78,11 @@
"nodemailer": "^6.9.7",
"openpgp": "^5.10.1",
"path": "^0.12.7",
"pm2": "^5.3.0 ",
"pm2": "^2.10.4",
"readline-sync": "^1.4.10",
"smtp-client": "^0.4.0",
"stripe": "^14.4.0",
"uuid": "^9.0.0"
},
"devDependencies": {}
"uuid": "^9.0.0",
"yarn": "^1.22.21"
}
}

View File

@ -8,11 +8,28 @@ const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* wait Sagar feedback for language and label description
* @ api {post} /api/notifications/backend - Notification Backend post
* @apiName notifBackend
* @apiDescription Send an api result {status,ref,msg,data} to get personnalize notification by header.xlang abd by data
* @apiGroup Notification
*
* @apiBody {integer} status an http status
* @apiBody {string} ref an existing model name
* @apiBody {string} msg a key word existing in referentiual
* */
router.post("/backend", (req, res) => {
})
/**
* @api {get} /notifications/:alias/:tribeId
* @apiName notiflist
* @apiDescription Get list of notifications for an alias and a tribe
* @apiGroup Notification
* @apiGroup Notifications
*
* @apiParam {string} alias
* @apiParam {string} tribeId
@ -20,11 +37,73 @@ const router = express.Router();
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {status:200,ref:"Notification",msg:"Messagelist",data:{notif:[{tribeId,msg:{from(email or uuid or alias):[{dt,msg}]}}]}
*
* bouture
**/
router.get("/:alias/:tribeId", (req, res) => {
const getnot = Notification.get(req.params.alias,req.params.tribeId);
const getnot = Notification.get(req.params.alias, req.params.tribeId);
res.status(getalias.status).send(getalias);
});
module.exports=router;
router.post("/registeranonymous", checkHeaders, (req, res) => {
['uuid','srckey','mlist'].forEach(k=>{
if (!req.body[k]){}
});
res.status().json({status:410, ref:"", msg:""})
let result;
if (req.body.email) {
result= Notifications.registertolist(
req.body.email,
"email",
req.session.header.xtribe,
req.body.mlist,
req.body.srckey,
req.body.uuid);
}
res(200).json({status:200})
})
/**
* @api {POST} /actions/contactanonymous -Contact anonymous
* @apiName contactanonymous
* @apiGroup Notifications
* @apiDescription Run action store in body.order and update mailinglist or create contact message
*
* @apiBody {string} order name of function for action in Actions.js example:registercontact ,
* @apiBody {string} srckey: where it come from and eventualy email template name to use to send email ,
* @apiBody {string} email to use
* @apiBody {string} route /actions/contactanonymous
* @apiBody {string} [mlist] filename to store email registration /contacts/mlist.json if not => filename is quest_/contacts/email.json with {email:{dt_create,dt_update, src:[list of source]}} or add message in /contacts/quest_{email}.json {timestamp:{message,name,email,dt_create,emailcontact}}
* @apiBody {string} others any other usefull key:value relevant for order action
*
* @apiSuccess {object} update/contacts/{mlist}.json successfull
* @apiSuccessExample {json} successfullmessage
* HTTP/1.1 200 OK
* {"status":200, "ref":"Contact", "msg":"success", "data":{"indexlist":[]}}
*
*/
router.post("/contactanonymous", checkHeaders, async (req, res) => {
const done = Actions[req.body.order]
? await Actions[req.body.order](req.body, req.session.header)
: { status: 406, ref: "Actions", msg: "bodyerror", data: req.body };
//console.log('routes contactanonymous ', req.body);
res.status(done.status).json(done);
});
/**
* Same as /copntactanonymous but for authenticated user => data are updated in persons/itm/alias.json
*/
router.post("/contact", checkHeaders, isAuthenticated, (req, res) => {
const done = Actions[req.body.order]
? Actions[req.body.order](req.body, req.session.header)
: { status: 406, ref: "Actions", msg: "bodyerror", data: req.body };
console.log(req.body);
res.status(done.status).json(done);
});
router.get("/contact", checkHeaders, isAuthenticated, (req, res) => {
res.status(200).json({ data: {} });
});
module.exports = router;

View File

@ -1,5 +1,6 @@
const express = require("express");
const fs = require("fs-extra");
const dayjs=require('dayjs');
const path = require("path");
// Classes
const Pagans = require("../models/Pagans.js");
@ -41,11 +42,10 @@ router.get("/alias/:alias", (req, res) => {
res.status(getalias.status).send(getalias);
});
/**
* Remove serveur token
* @api {get} /pagans/logout - pagan Logout
* @apiName Removetoken
* @apiGroup Pagans
* @apiDescription Remove token
* @apiDescription Remove server's token only the owner of the token (no one else can delete a token )
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
@ -97,7 +97,8 @@ router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
* @apiGroup Pagans
* @apiDescription
* Create a pagan account from alias, publickey, if trusted recovery =>
* Create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}
* If trustedtribe is true then create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}.
*
* Middleware isAuthenticated check that:
* - xhash is well signed from private key linked to the publickey of alias
* - check that alias does not already exist (if yes then verifiedsigne would be false)
@ -107,7 +108,8 @@ router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
* @apiBody {string} [email] if specified then an email is sent to it with public and privatekey
* @apiBody {string} [privatekey]
* @apiBody {string} [passphrase] if not specidied => passphrase=""
* @apiBody {string} [trustedtribe] the tribename if not specified then the process will only create a pagan identity, else an item person is create for trustedtribe (that must exist with profil 'person'). To create a person with an existing pagan identity use put /api/person/:alias after authenticated you (headers). In case a person is created then we use all valid other apiBody respecting rules https://smatchit.io/api/odmdb/schema/persons.json
* @apiBody {string} [trustedtribe] the tribename if not specified then the process will only create a pagan identity, else an item person is create for trustedtribe (that must exist with profil 'person'). To create a person with an existing pagan identity use put /api/person/:alias after authenticated you (headers). In case a person is created then we use all valid other apiBody respecting the persons schema (see put persons)
* @apiBody {object} schema:pagans <a href='https://wall-ants.ndda.fr/nationchains/schema/pagans.json' target='_blank'>https://wall-ants.ndda.fr/nationchains/schema/pagans.json</a>
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
@ -121,7 +123,7 @@ router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
*
*/
router.post("/", checkHeaders, isAuthenticated, async (req, res) => {
console.log("pass ici", req.body);
log('dev',`passici ${req.body}`);
const role = {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
@ -191,22 +193,37 @@ router.post("/", checkHeaders, isAuthenticated, async (req, res) => {
* @apiName deletepagan
* @apiGroup Pagans
* @apiDescription
* Delete an alias and his publickey, this mean that publickey disapear as well as alias. All tribe will be inform and will delete person of this alias if they have. This alias will be availlable after 1 year.
* Delete an alias and his publickey, this mean that publickey disapear as well as alias. We set dt_delete
* */
router.delete("/alias/:alias", checkHeaders, isAuthenticated, (req, res) => {
const personpath=`../nationchains/pagans`;
const role = {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
};
req.session.header.role
const delperson = Odmdb.cud(personpath,"U",{alias:req.params.alias,dt_delete:dayjs().toISOString()},role,true);
console.log(`DELETE person ${personpath}/${req.params.alias}.json `);
console.log(delperson)
res.status(delperson.status).json(delperson);
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
const result = Pagans.deletealias(req.params.id, req.session.header);
const result = Pagans.delete(req.params.alias, req.session.header);
res.status(result.status).send(result);
});
/**
* @api {delete} /pagans/person/:alias - person Delete
* @api {delete} /pagans/person/:tribe/:alias - person Delete
* @apiName deleteperson
* @apiGroup Pagans
* @apiDescription
* Unsubscribe a person to a tribe => remove a person item and all data link to this alias
* @apiHeader {array} xprofils list of profil of authenticated user
* @apiHeader {string} xalias current user
* @apiParam {string} tribe where person alias exist
* @apiParam {string} alias to delete as person
* */
router.delete("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
const personpath=`../nationchains/tribes/${req.session.header.xtribe}/objects/persons`;
router.delete("/person/:tribe/:alias", checkHeaders, isAuthenticated, (req, res) => {
const personpath=`../nationchains/tribes/${req.params.tribe}/objects/persons`;
const role = {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
@ -244,17 +261,19 @@ router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
});
/**
* @api {put} /pagans/person - person Put
* @api {put} /pagans/person/:tribe - person Put
* @apiName updateperson
* @apiGroup Pagans
* @apiDescription add or update a person = alias in a tribe. alias authenticated must have a profil with accessright into schema person.
* @apiHeader {string} xalias
* @apiParam {object} in line with schema in https://smatchit.io/api/odmdb/schema/persons
* @apiDescription add or update a person = alias in tribe. xalias authenticated (in header) must have a profil with accessright into schema person to create a person.
* @apiHeader {string} xhash authenthicate hash with current user keys
* @apiHeader {string} xalias current user
* @apiHeader {string} xprofils profil list
* @apiParam {object} schema:persons <a href='https://smatchit.io/smatchit/schema/persons.json' target='_blank'>https://dnstribe/tribe/schema/persons.json</a>
*
*/
router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
router.put("/person/:tribe", checkHeaders, isAuthenticated, (req, res) => {
//console.log(req.body);
const pathobj=`../nationchains/tribes/${req.session.header.xtribe}/objects/persons`;
const pathobj=`../nationchains/tribes/${req.params.tribe}/objects/persons`;
const action = (fs.existsSync(`${pathobj}/itm/${req.body.alias}.json`))? "U":"C";
//set req.body to be in line with schema
if (!req.body.profils){
@ -266,7 +285,7 @@ router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
});
/**
* @api {get} /pagans/keyrecovery/tribe/email - recovery keys by email
* @api {get} /pagans/keyrecovery/:tribe/:email - recovery keys by email
* @apiName recoveryKey
* @apiGroup Pagans
* @apiDescription Send mails with all registers identities (one per alias where recoveryauth.email is register)

29
tools/log.js Normal file
View File

@ -0,0 +1,29 @@
const fs = require("fs-extra");
const dayjs = require("dayjs");
const l = {};
l.context="";
l.showlog=(process.env.NODE_MODE=="dev");
l.og = (...infos) => {
// by default if NODE_MODE is dev => l.showlog at true
// if l.showlog is set to false then it does not output log
// l.context is a prefixe to help understanding
// usage:
// const l=require('./tools/log.js');
// l.showlog= true; // force log as well in prod and dev
// l.context="apxtri";
// l.og(stringify)
if (l.showlog) {
console.log(l.context,'-', infos);
}
};
l.ogprod = (tribe,info) => {
//store log in file /nationchains/tribes/{tribe}/logs/apxtri/apxtri_{tribe}.log
const logf = `../../nationchains/tribes/${tribe}/logs/apxtri/apxtri_${tribe}.log`;
const msg = `${days.js().toISOString()}###${tribe}###${info}`;
fs.appendFileSync(logf, msg);
console.log(msg)
};
module.exports = l;

3345
yarn.lock

File diff suppressed because it is too large Load Diff