2023-04-27 04:17:20 +00:00
|
|
|
const glob = require("glob");
|
|
|
|
const path = require("path");
|
2023-05-12 05:59:32 +00:00
|
|
|
const dayjs = require("dayjs");
|
2023-04-27 04:17:20 +00:00
|
|
|
const fs = require("fs-extra");
|
2023-05-12 05:59:32 +00:00
|
|
|
const axios = require("axios");
|
|
|
|
const openpgp = require("openpgp");
|
2023-11-05 11:03:25 +00:00
|
|
|
const Notifications = require("../models/Notifications.js");
|
|
|
|
const Odmdb = require("../models/Odmdb.js");
|
2023-05-16 08:31:27 +00:00
|
|
|
|
|
|
|
/*if (fs.existsSync("../../nationchains/tribes/conf.json")) {
|
2023-05-12 05:59:32 +00:00
|
|
|
conf = require("../../nationchains/tribes/conf.json");
|
2023-05-16 08:31:27 +00:00
|
|
|
}*/
|
|
|
|
const conf = require(`${process.env.dirtown}/conf.json`);
|
2023-05-31 13:19:21 +00:00
|
|
|
|
2023-04-27 04:17:20 +00:00
|
|
|
/**
|
2023-05-12 05:59:32 +00:00
|
|
|
* Pagan Management numeric Identity and Person (Person = Pagan Id + tribe)
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
2023-04-27 04:17:20 +00:00
|
|
|
*/
|
2023-05-12 05:59:32 +00:00
|
|
|
const Pagans = {};
|
2023-04-27 04:17:20 +00:00
|
|
|
|
2023-11-05 11:03:25 +00:00
|
|
|
/**
|
|
|
|
* 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} }
|
|
|
|
*
|
|
|
|
**/
|
2023-06-07 05:32:23 +00:00
|
|
|
Pagans.getalias = (alias) => {
|
2023-11-05 11:03:25 +00:00
|
|
|
//bypass Odmdb cause all is public
|
2023-06-07 05:32:23 +00:00
|
|
|
if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`)) {
|
|
|
|
return {
|
|
|
|
status: 200,
|
|
|
|
ref: "Pagans",
|
|
|
|
msg: "aliasexist",
|
2023-11-05 11:03:25 +00:00
|
|
|
data: fs.readJSONSync(
|
2023-06-07 05:32:23 +00:00
|
|
|
`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`
|
|
|
|
),
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return {
|
|
|
|
status: 404,
|
|
|
|
ref: "Pagans",
|
|
|
|
msg: "aliasdoesnotexist",
|
|
|
|
data: { alias },
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-11-05 11:03:25 +00:00
|
|
|
/**
|
|
|
|
* @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") {
|
2023-06-07 05:32:23 +00:00
|
|
|
return {
|
2023-11-05 11:03:25 +00:00
|
|
|
status: 404,
|
2023-06-07 05:32:23 +00:00
|
|
|
ref: "Pagans",
|
2023-11-05 11:03:25 +00:00
|
|
|
msg: "persondoesnotexist",
|
|
|
|
data: { alias, tribeid },
|
2023-06-07 05:32:23 +00:00
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return {
|
2023-11-05 11:03:25 +00:00
|
|
|
status: 200,
|
2023-06-07 05:32:23 +00:00
|
|
|
ref: "Pagans",
|
2023-11-05 11:03:25 +00:00
|
|
|
msg: "personexist",
|
|
|
|
data: objlst.data[alias],
|
2023-06-07 05:32:23 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-11-05 11:03:25 +00:00
|
|
|
Pagans.create = (objpagan, role) => {
|
2023-05-12 05:59:32 +00:00
|
|
|
/**
|
2023-11-05 11:03:25 +00:00
|
|
|
* @param {object} objpagan {alias,publickey} a unique alias/publickey that identify an identity
|
|
|
|
* @param {array} role {xalias,xprofils} requester and list of profil
|
2023-05-12 05:59:32 +00:00
|
|
|
* @return {object} { status: 200, data: { alias, publicKey } }
|
|
|
|
* xhash was checked by isauthenticated
|
|
|
|
* @todo use Odmdb to add a pagan
|
|
|
|
*/
|
2023-11-05 11:03:25 +00:00
|
|
|
return Odmdb.cud(`${conf.dirapi}/nationchains/pagans`, "C", objpagan, role);
|
|
|
|
/*
|
2023-05-12 05:59:32 +00:00
|
|
|
let apxpagans = {};
|
2023-06-28 13:23:17 +00:00
|
|
|
if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`)) {
|
2023-05-12 05:59:32 +00:00
|
|
|
apxpagans = fs.readJsonSync(
|
2023-06-28 13:23:17 +00:00
|
|
|
`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`
|
2023-05-12 05:59:32 +00:00
|
|
|
);
|
|
|
|
}
|
2023-11-05 11:03:25 +00:00
|
|
|
if (apxpagans[objpagan.alias]) {
|
|
|
|
return { status: 409, ref: "Pagans", msg: "aliasexist", data: { alias } };
|
|
|
|
}
|
|
|
|
apxpagans[objpagan.alias] = { alias, publicKey };
|
2023-05-12 05:59:32 +00:00
|
|
|
fs.outputJsonSync(
|
2023-05-16 08:31:27 +00:00
|
|
|
`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`,
|
2023-05-12 05:59:32 +00:00
|
|
|
apxpagans
|
|
|
|
);
|
2023-05-16 08:31:27 +00:00
|
|
|
fs.outputJsonSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`, {
|
2023-05-12 05:59:32 +00:00
|
|
|
alias,
|
|
|
|
publicKey,
|
|
|
|
});
|
2023-11-05 11:03:25 +00:00
|
|
|
return {
|
|
|
|
status: 200,
|
|
|
|
ref: "Pagans",
|
|
|
|
msg: "identitycreate",
|
|
|
|
data: { alias, publicKey },
|
|
|
|
};
|
|
|
|
*/
|
2023-05-12 05:59:32 +00:00
|
|
|
};
|
2023-04-27 04:17:20 +00:00
|
|
|
|
2023-11-05 11:03:25 +00:00
|
|
|
/**
|
|
|
|
* @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 = {
|
2023-05-12 05:59:32 +00:00
|
|
|
alias: alias,
|
|
|
|
dt_create: dayjs(),
|
2023-11-05 11:03:25 +00:00
|
|
|
profils: ["person"],
|
2023-04-27 04:17:20 +00:00
|
|
|
};
|
2023-11-05 11:03:25 +00:00
|
|
|
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];
|
2023-05-12 05:59:32 +00:00
|
|
|
});
|
2023-05-16 08:31:27 +00:00
|
|
|
//const checkjson= Checkjson.schema.data = (fs.readJsonSync(`${conf.dirapi}/nationchains/schema/person.json`, person, false)
|
2023-05-12 05:59:32 +00:00
|
|
|
// if checkjson.status==200 create /update with odmdb to update index data
|
|
|
|
// see odmdb that did all and return standard message
|
2023-11-05 11:03:25 +00:00
|
|
|
fs.outputJSONSync(personfile, persondata, { space: 2 });
|
2023-05-12 05:59:32 +00:00
|
|
|
return {
|
|
|
|
status: 200,
|
|
|
|
ref: "Pagans",
|
|
|
|
msg: "successfullupdate",
|
2023-11-05 11:03:25 +00:00
|
|
|
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:
|
|
|
|
"<h1>Votre identité {{alias}} via {{tribeid}}</h1><p>Passphrase:</p></p><p>{{{passphrase}}</p><p>Cle public:</p><p>{{{publickey}}</p><p>Cle privée</p><p>{{{privatekey}}</p>",
|
|
|
|
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: [],
|
2023-04-27 04:17:20 +00:00
|
|
|
};
|
2023-11-05 11:03:25 +00:00
|
|
|
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);
|
2023-05-12 05:59:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-11-05 11:03:25 +00:00
|
|
|
/**
|
|
|
|
* 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) => {};
|
2023-06-12 05:27:34 +00:00
|
|
|
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" };
|
|
|
|
};
|
2023-05-12 05:59:32 +00:00
|
|
|
module.exports = Pagans;
|