const glob = require("glob"); const path = require("path"); const dayjs = require("dayjs"); const fs = require("fs-extra"); const axios = require("axios"); const openpgp = require("openpgp"); const Notifications = require("../models/Notifications.js"); const Odmdb = require("../models/Odmdb.js"); /*if (fs.existsSync("../../nationchains/tribes/conf.json")) { conf = require("../../nationchains/tribes/conf.json"); }*/ const conf = require(`${process.env.dirtown}/conf.json`); /** * Pagan Management numeric Identity and Person (Person = Pagan Id + tribe) * * * */ const Pagans = {}; /** * Remove authentification token after a logout * @param {string} alias * @param {string} tribe * @param {integer} xdays * @param {string} xhash * @returns {status:200, ref:"Pagans",msg:"logout"} * tmpfs name file has to be on line with the tmpfs create by isAuthenticated * tmpfs contain profils name for a tribe/ */ Pagans.logout = (alias, tribe, xdays, xhash) => { //console.log(alias, tribe, xdays, xhash); // inline with middleware isAuthenticated.js let tmpfs = `${process.env.dirtown}/tmp/tokens/${alias}_${tribe}_${xdays}`; //max filename in ext4: 255 characters tmpfs += `_${xhash.substring(150, 150 + tmpfs.length - 249)}.json`; fs.remove(tmpfs); return { status: 200, ref: "Pagans", msg: "logout" }; }; /** * @param {string} alias a alias that exist or not * @return {object} { status: 200, ref:"pagans",msg:"aliasexist",data: { alias, publicKey } } * { status: 404, ref:"pagans",msg:"aliasdoesnotexist",data: { alias} } * **/ Pagans.getalias = (alias) => { //bypass Odmdb cause all is public if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`)) { return { status: 200, ref: "Pagans", msg: "aliasexist", data: fs.readJSONSync( `${conf.dirapi}/nationchains/pagans/itm/${alias}.json` ), }; } else { return { status: 404, ref: "Pagans", msg: "aliasdoesnotexist", data: { alias }, }; } }; /** * @param {string} alias that exist * @param {string} tribeId that exist with a person alias * @return {object} { status: 200, ref:"pagans",msg:"personexist",data: { person } } * { status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } } * **/ Pagans.getperson = (tribeid, alias, role) => { const objlst = Odmdb.reads( `${conf.dirtown}/tribes/${tribeid}/persons`, [alias], role ); if (objlst.data[alias] == "notfound") { return { status: 404, ref: "Pagans", msg: "persondoesnotexist", data: { alias, tribeid }, }; } else { return { status: 200, ref: "Pagans", msg: "personexist", data: objlst.data[alias], }; } }; Pagans.create = (objpagan, role) => { /** * @param {object} objpagan {alias,publickey} a unique alias/publickey that identify an identity * @param {array} role {xalias,xprofils} requester and list of profil * @return {object} { status: 200, data: { alias, publicKey } } * xhash was checked by isauthenticated * @todo use Odmdb to add a pagan */ return Odmdb.cud(`${conf.dirapi}/nationchains/pagans`, "C", objpagan, role); /* let apxpagans = {}; if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`)) { apxpagans = fs.readJsonSync( `${conf.dirapi}/nationchains/pagans/idx/alias_all.json` ); } if (apxpagans[objpagan.alias]) { return { status: 409, ref: "Pagans", msg: "aliasexist", data: { alias } }; } apxpagans[objpagan.alias] = { alias, publicKey }; fs.outputJsonSync( `${conf.dirapi}/nationchains/pagans/idx/alias_all.json`, apxpagans ); fs.outputJsonSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`, { alias, publicKey, }); return { status: 200, ref: "Pagans", msg: "identitycreate", data: { alias, publicKey }, }; */ }; /** * @Param {string} alias pagan unique id * @Param {string} tribeid tribe id in this town * @Param {object} persondata that respect /nationchains/schema/person.json + nationchains/tribe/tribeid/schema/personextented.json * @return create or update a person /tribe/tribeid/person/alias.json * todo later use Odmdb ans schema person to manage this */ Pagans.personupdate = (tribeid, alias, personupdate, role) => { const personinit = { alias: alias, dt_create: dayjs(), profils: ["person"], }; const personfile = `${process.env.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`; const persondata = fs.existsSync(personfile) ? fs.readJSONSync(personfile) : personinit; persondata.dt_update = dayjs(); Object.keys(personupdate).forEach((d) => { persondata[d] = personupdate[d]; }); //const checkjson= Checkjson.schema.data = (fs.readJsonSync(`${conf.dirapi}/nationchains/schema/person.json`, person, false) // if checkjson.status==200 create /update with odmdb to update index data // see odmdb that did all and return standard message fs.outputJSONSync(personfile, persondata, { space: 2 }); return { status: 200, ref: "Pagans", msg: "successfullupdate", data: { alias: alias, tribeid: tribeid }, }; }; /** * Send email with alias's keys to email or person alias person.recovery.email * * If email or pubkey is undefined then get data from tribe/person(alias) * Send email with keys * * @param {string} alias * @param {pgpPrivate} privkey * @param {string} passphrase * @param {string} tribe * @param {pgpPublic} pubkey * @param {string} email */ Pagans.sendmailkey = ( alias, privatekey, tribeid, passphrase, publickey, email ) => { const person = { alias, privatekey, tribeid }; console.log( alias, "-", privatekey, "-", tribeid, "-", passphrase, "-", publickey, "-", email ); if (!publickey || !email || !passphrase || !privatekey) { const personfile = `${process.env.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`; const persondata = fs.existsSync(personfile) ? fs.readJsonSync(personfile) : {}; if (persondata.length == 0) { return { status: 404, ref: "Pagans", msg: "persondoesnotexist", data: { alias, tribeid }, }; } person.email = persondata.recoveryauth.email; person.publickey = persondata.recoveryauth.publickey; person.privatekey = persondata.recoveryauth.privatekey; person.passphrase = persondata.recoveryauth.passphrase; } else { person.email = email; person.passphrase = passphrase; person.publickey = publickey; } console.log("person:", person); //feedback.withemail = true; //feedback.email = email; //feedback.privatekey = privatekey; //feedback.passphrase = passphrase; const mailidentity = { subjecttpl: "Information pour l'alias: {{alias}}", htmltpl: "

Votre identité {{alias}} via {{tribeid}}

Passphrase:

{{{passphrase}}

Cle public:

{{{publickey}}

Cle privée

{{{privatekey}}

", texttpl: "Votre identité {{alias}}\nPassphrase:\n{{{passphrase}}\nCle public:\n{{{publickey}}\nCle privée\n{{{privatekey}}", filelist: [], }; const maildata = { To: person.email, subject: Mustache.render(mailidentity.subject, person), htmlpart: Mustache.render(mailidentity.htmltpl, person), textpart: Mustache.render(mailidentity.texttpl, person), filelist: [], }; fs.outputFileSync( `${conf.dirtown}/tmp/${person.alias}_privatekey.txt`, person.privatekey, "utf8" ); maildata.filelist.push({ filename: "${person.alias}_privatekey.txt", pathfile: `${conf.dirtown}/tmp/${person.alias}_privatekey.txt`, }); fs.outputFileSync( `${conf.dirtown}/tmp/${person.alias}_publickey.txt`, person.publickey, "utf8" ); maildata.filelist.push({ filename: "${person.alias}_publickey.txt", pathfile: `${conf.dirtown}/tmp/${person.alias}_publickey.txt`, }); //fs.readJSONSync('${conf.dirapi}/api/') return Notifications.sendmail(maildata, tribeid); }; Pagans.authenticatedetachedSignature = async ( alias, pubK, detachedSignature, message ) => { /** * Check that a message was signed with a privateKey from a publicKey * This is not necessary if isAuthenticated, but can be usefull to double check * @TODO finish it and implement it also in /apxpagan.js for browser * @alias {string} alias link to the publicKey * @pubK {string} publiKey text format * @detachedSignature {string} a detachedsignatured get from apx.detachedSignature * @message {string} the message signed * @return {boolean} true the message was signed by alias * false the message was not signed by alias */ const publicKey = await openpgp.readKey({ armoredKey: pubK }); const msg = await openpgp.createMessage({ text: message }); const signature = await openpgp.readSignature({ armoredSignature: detachedSignature, // parse detached signature }); const verificationResult = await openpgp.verify({ msg, // Message object signature, verificationKeys: publicKey, }); const { verified, keyID } = verificationResult.signatures[0]; try { await verified; // throws on invalid signature console.log("Signed by key id " + keyID.toHex()); return KeyId.toHex().alias == alias; } catch (e) { console.log("Signature could not be verified: " + e.message); return false; } }; /** * todo recuperer tous les tokens et les distribuer à la town * @param {string} alias */ Pagans.deletealias = (alias) => { // check if alias is used in the blockchain // if not then delete itm pagan alias => this means that alias is now available for someone else }; Pagans.deleteperson = (alias, tribeId) => {}; Pagans.keyrecovery = (tribeid, email) => { glob .GlobSync(`${conf.dirtown}/tribes/${tribeId}/Person/*.json`) .forEach((f) => { const person = fs.readJsonSync(f); if (person.recoveryauth && person.recoveryauth.email) { // send email (alias publickey privatekey ) } }); return { status: 200, ref: "Pagans", msg: "todo" }; }; module.exports = Pagans;