/*eslint no-undef:0*/ /*eslint-env browser*/ "use strict"; var pagans = pagans || {}; /** * pagans.generateKey(params) create a public/private key compatible with apXtrib backend and store it in apx.data * pagans.detachedSignature(params) generate a detachedSignature for a Message that backend can check with the publicKey of the alias * pagans.checkdetachedSignature(params) check a detachedSignature for a Message (used on the backend as well) * * */ pagans.loadtpldata = () => { // adapte tpldata to template tpl // get list of tribes from nationchains/towns/idx/townId_all.json const datacreatepagan = { tribes: [] }; apx.data.towns.idxtownId_all[apx.data.tpldata.setup.townId].tribes.forEach( (t) => { if (t == apx.data.tpldata.setup.tribeId) { datacreatepagan.tribes.push({ selected: true, tribeId: t }); } else { datacreatepagan.tribes.push({ tribeId: t }); } } ); return datacreatepagan; }; pagans.generateKey = async (alias, passphrase) => { /** * @param {string} alias a unique alias that identify an identity * @param {string} passphrase a string to cipher the publicKey (can be empty, less secure but simpler) * @return {publicKey,privateKey} with userIds = [{alias}] */ const pgpparam = { type: "ecc", // Type of the key, defaults to ECC curve: "curve25519", // ECC curve name, defaults to curve25519 userIDs: [{ alias: alias }], // you can pass multiple user IDs passphrase: passphrase, // protects the private key format: "armored", // output key format, defaults to 'armored' (other options: 'binary' or 'object') }; const { privateKey, publicKey } = await openpgp.generateKey(pgpparam); // key start by '-----BEGIN PGP PRIVATE KEY BLOCK ... ' // get liste of alias:pubklickey await axios.get('api/v0/pagans') // check alias does not exist return { alias, privateKey, publicKey }; }; pagans.detachedSignature = async (pubK, privK, passphrase, message) => { /** * @pubK {string} a text public key * @privK {string} a test priv key * @passphrase {string} used to read privK * @message {string} message to sign * @Return a detached Signature of the message */ const publicKey = await openpgp.readKey({ armoredKey: pubK }); let privateKey; if (passphrase == "") { privateKey = await openpgp.readPrivateKey({ armoredKey: privK }); } else { privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readPrivateKey({ armoredKey: privK }), passphrase, }); } console.log(message); const msg = await openpgp.createMessage({ text: message }); console.log(msg); const sig = await openpgp.sign({ message: msg, signingKeys: privateKey, detached: true, }); return btoa(sig); }; pagans.authenticatedetachedSignature = async ( alias, pubK, detachedSignature, message ) => { /** * Check that alias (pubkey) signe a message * @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: atob(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; } }; pagans.createIdentity = async (alias, passphrase = "") => { console.log(Object.keys(apx.data.pagans["idxalias_all"])); if ( alias.length < 3 || Object.keys(apx.data.pagans["idxalias_all"]).includes(alias) ) { alert("Please chose another alias"); return; } const keys = await pagans.generateKey(alias, passphrase); for (let tag of ["inputalias", "inputpassphrase"]) { document.getElementById(tag).classList.add("disabled"); } console.log(keys); document.getElementById("privatekey").setAttribute("key", keys.privateKey); document.getElementById("publickey").setAttribute("key", keys.publicKey); apx.data.tmp = keys; // to make it available for btn download document.getElementById("generatekeys").classList.add("d-none"); document.getElementById("trustintribe").classList.remove("d-none"); //document.getElementById("downloadkeys").classList.remove("d-none"); document.getElementById("createId").classList.remove("d-none"); }; pagans.registerIdentity = async () => { const emailregex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const data = {}; data.alias = document.getElementById("inputalias").value; data.publickey = document.getElementById("publickey").getAttribute("key"); if (document.getElementById("inputemailrecovery").value != "") { data.email = document.getElementById("inputemailrecovery").value; } if (data.email && !emailregex.test(data.email)) { alert("Check your email"); return false; } var select = document.getElementById("trustedtribe"); if (document.getElementById("trustedcheck").checked) { data.trustedtribe = select.options[select.selectedIndex].value; data.privatekey = document.getElementById("privatekey").getAttribute("key"); data.passphrase = document.getElementById("inputpassphrase").value; } if (document.getElementById("trustedcheck").checked && !data.email) { alert("Please provide a valid email"); return false; } console.log(data); //store and create authentification by signing 'alias_timestamp' /* const passp = data.passphrase ? data.passphrase : ""; apx.data.auth = { alias: data.alias, publickey: data.publickey, privatekey: document.getElementById("privatekey").getAttribute("key"), passphrase: passp, }; apx.data.headers.xalias = data.alias; apx.data.headers.xdays = dayjs().valueOf(); apx.save(); const msg = `${data.alias}_${apx.data.headers.xdays}`; apx.data.headers.xhash = await pagans.detachedSignature( apx.data.auth.publickey, apx.data.auth.privatekey, passp, msg ); apx.save();*/ await pagans.authentifyme( data.alias, data.passphrase, document.getElementById("privatekey").getAttribute("key"), document.getElementById("publickey").getAttribute("key") ); console.log("header", apx.data.headers); axios .post("api/pagans", data, { headers: apx.data.headers }) .then((reppagan) => { console.log(reppagan); if (reppagan.status==200) { document.getElementById('downloadkeys').classList.remove('d-none'); alert("Your identity is created, don't forget to download your key") }else{ alert('Check the console an error appear'); } }) .catch((err) => { console.log("sorry", err); }); }; pagans.authentifyme = async ( alias, passphrase, privatekey, publickeycreate ) => { /** * Set apx.data.auth with pub, priv, passphrase alias that allow authentification * set headers with xdays (timestamp) and xhash of message: {alias}_{timestamp} generate with pub & priv key * * @Param {key} publickeycreate optional when alias does not exist */ console.log(alias, passphrase); console.log(privatekey); const passp = passphrase ? passphrase : ""; const publickey = publickeycreate ? publickeycreate : apx.data.pagans.idxalias_all[alias].publicKey; apx.data.auth = { alias: alias, publickey: publickey, privatekey: privatekey, passphrase: passp, }; apx.data.headers.xalias = alias; apx.data.headers.xdays = dayjs().valueOf(); apx.save(); const msg = `${alias}_${apx.data.headers.xdays}`; apx.data.headers.xhash = await pagans.detachedSignature( apx.data.auth.publickey, apx.data.auth.privatekey, passp, msg ); apx.save(); }; pagans.logout=()=>{ delete apx.data.auth; delete apx.data.headers; apx.data.headers = apxlocal.headers; apx.save(); alert('delete apx.data.auth and reinit apx.data.header'); }