212 lines
7.4 KiB
JavaScript
212 lines
7.4 KiB
JavaScript
|
/*eslint no-undef:0*/
|
||
|
/*eslint-env browser*/
|
||
|
|
||
|
"use strict";
|
||
|
var apx = apx || {};
|
||
|
|
||
|
/**
|
||
|
* Js lib to interact with apxtrib backend
|
||
|
*
|
||
|
* html page must have apxlocal with at least headers key
|
||
|
* <script>
|
||
|
const apxlocal={
|
||
|
headers:{xalias:"",xhash:"",xtribe:"smatchit", xapp:"smatchapp", xlang:"en" },
|
||
|
firstimeload:true,
|
||
|
forceload:true,
|
||
|
tpl:{
|
||
|
footer:"{{{msg}}}"
|
||
|
},
|
||
|
tpldata:{
|
||
|
footer:{msg:"<p>Made with love for people freedom, enjoy!</p>"}
|
||
|
},
|
||
|
objects:{}
|
||
|
};
|
||
|
* apx.generateKey(params) create a public/private key compatible with apXtrib backend and store it in apx.data
|
||
|
* apx.detachedSignature(params) generate a detachedSignature for a Message that backend can check with the publicKey of the alias
|
||
|
* apx.checkdetachedSignature(params) check a detachedSignature for a Message (used on the backend as well)
|
||
|
|
||
|
* apx.ready(callback) equivalent of jquery Document.ready()
|
||
|
* apx.save() save apx.data as xapp value in localStorage
|
||
|
* apx.update() get localStorage up to date
|
||
|
* apx.loadfile({url:name},dest,axiosoptions) async that wait to load a list of relativ url and store it in a apx.data[dest]
|
||
|
*/
|
||
|
|
||
|
apx.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 { privateKey, publicKey } = await openpgp.generateKey({
|
||
|
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')
|
||
|
});
|
||
|
// 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 };
|
||
|
/* document.getElementById('privatekey').innerHTML=privateKey;
|
||
|
document.getElementById('publickey').innerHTML=publicKey;
|
||
|
apx.data.pagans={}
|
||
|
apx.data.pagans.privateKey=privateKey;
|
||
|
apx.data.pagans.publicKey=publicKey;
|
||
|
apx.save();
|
||
|
console.log(apx.data)
|
||
|
*/
|
||
|
};
|
||
|
apx.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 });
|
||
|
const privateKey = await openpgp.decryptKey({
|
||
|
privateKey: await openpgp.readPrivateKey({ armoredKey: privK }),
|
||
|
passphrase,
|
||
|
});
|
||
|
const msg = await openpgp.createMessage({ text: message });
|
||
|
return await openpgp.sign({ msg, signinKeys: privK, detached: true });
|
||
|
};
|
||
|
apx.checkdetachedSignature = async (
|
||
|
alias,
|
||
|
pubK,
|
||
|
detachedSignature,
|
||
|
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: 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;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
apx.ready = (callback) => {
|
||
|
/**
|
||
|
* Wait loading DOM, when ready run callback function
|
||
|
*/
|
||
|
if (!callback) {
|
||
|
alert(
|
||
|
"You have an unknown callback pwa.state.ready(callback), you need to order your code callback = ()=>{} then pwa.state.ready(callback), boring but js rules ;-)"
|
||
|
);
|
||
|
}
|
||
|
if (document.readyState != "loading") callback();
|
||
|
// modern browsers
|
||
|
else if (document.addEventListener)
|
||
|
document.addEventListener("DOMContentLoaded", callback);
|
||
|
// IE <= 8
|
||
|
else
|
||
|
document.attachEvent("onreadystatechange", function () {
|
||
|
if (document.readyState == "complete") callback();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
apx.loadfile = async (list, dest, axiosoptions) => {
|
||
|
/**
|
||
|
* Load external file as tpl, tpldata (temmplate and data), objects index of object
|
||
|
* @param {object} list {name:url} it will run as promise all the requested url
|
||
|
* @param {string} dest where to store it in apx.data (tpl, tpldata, objectname,...)
|
||
|
* @param {object} axiosoptions alow to add headers any option to axios
|
||
|
* @return {object} load into apx.data[dest]={name:{object}} and localStorage.xapp[dest]={name:{object}}
|
||
|
*
|
||
|
* @example <caption>Load into apx.data.tpl.blocncol ="string"</caption>
|
||
|
* apx.loadfile({blocncol:"static/tpl/blocncol.mustache"},"tpl",{headers:apx.data.header})
|
||
|
*
|
||
|
*/
|
||
|
const invertlist = {};
|
||
|
Object.keys(list).forEach((n) => {
|
||
|
invertlist[list[n]] = n;
|
||
|
});
|
||
|
//console.log( 'invertlist', invertlist )
|
||
|
if (
|
||
|
apx.data.forcereload ||
|
||
|
!apx.data[dest] ||
|
||
|
Object.keys(apx.data[dest]).length == 0
|
||
|
) {
|
||
|
if (!apx.data[dest]) apx.data[dest] = {};
|
||
|
const fetchURL = (r, options) => {
|
||
|
return axios.get(r, options);
|
||
|
};
|
||
|
const urls = Object.keys(invertlist);
|
||
|
if (!axiosoptions) {
|
||
|
axiosoptions = { headers: apx.data.headers };
|
||
|
}
|
||
|
console.log('axiosiptions',axiosoptions)
|
||
|
const promiseArray = urls.map((r) => fetchURL(r, axiosoptions));
|
||
|
await Promise.all(promiseArray)
|
||
|
.then((data) => {
|
||
|
console.log(data)
|
||
|
for (let pos = 0; pos < urls.length; pos++) {
|
||
|
//console.log( 'url', urls[ pos ] )
|
||
|
//console.log( data[ pos ] );
|
||
|
apx.data[dest][invertlist[urls[pos]]] = data[pos].data;
|
||
|
console.log(
|
||
|
`store apx.data[ ${dest} ][ invertlist[ ${urls[pos]} ] ]`
|
||
|
);
|
||
|
apx.save();
|
||
|
}
|
||
|
})
|
||
|
.catch((err) => {
|
||
|
console.log("erreur de loading", err);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
apx.save = () => {
|
||
|
localStorage.setItem(apx.data.headers.xapp, JSON.stringify(apx.data));
|
||
|
};
|
||
|
apx.update = async () => {
|
||
|
if (!apxlocal) {
|
||
|
console.log(
|
||
|
'Please add to the html page header, this line <script> const apxlocal={headers:{xalias:"",xhash:"",xtribe:"smatchit", xapp:"smatchapp", xlang:"en" }};</script> '
|
||
|
);
|
||
|
return;
|
||
|
}
|
||
|
if (document.querySelector("html").getAttribute("lang")) {
|
||
|
apxlocal.headers.xlang = document
|
||
|
.querySelector("html")
|
||
|
.getAttribute("lang");
|
||
|
}
|
||
|
if (localStorage.getItem(apxlocal.headers.xapp)) {
|
||
|
apx.data = JSON.parse(localStorage.getItem(apxlocal.headers.xapp));
|
||
|
if (apx.data.headers.xtribe != apxlocal.headers.xtribe) {
|
||
|
// if an app change of tribe
|
||
|
localStorage.removeItem(apxlocal.headers.xapp);
|
||
|
delete apx.data;
|
||
|
}
|
||
|
}
|
||
|
if (!apx.data) {
|
||
|
apx.data = apxlocal;
|
||
|
}
|
||
|
console.log("apx.data", apx.data);
|
||
|
apx.save();
|
||
|
};
|
||
|
apx.ready(apx.update);
|