in progress

This commit is contained in:
2023-04-27 06:17:20 +02:00
parent 0c74da3b20
commit a1fa43e2bd
279 changed files with 1706 additions and 95255 deletions

View File

@@ -0,0 +1,157 @@
/*eslint no-undef:0*/
/*eslint-env browser*/
"use strict";
var app = app || {};
app.createIdentity=(alias,passphrase="")=>{
if (alias.length<3 || apx.data.object['index_pagans_alias_all'].includes(alias) ){
alert('Please chose another alias')
return;
}
const keys = apx.generateKey(alias,passphrase)
for(let tag of ['inputalias','inputpassphrase']){
document.getElementById(tag).classList.add('disabled')
}
document.getElementById('privatekey').setAttribute("key",keys.privateKey);
document.getElementById('publickey').setAttribute("key",keys.publicKey);
document.getElementById('generatekeys').classList.add('d-none');
document.getElementById('downloadkeys').classList.remove('d-none');
document.getElementById('createId').classList.remove('d-none');
}
app.registerIdentity=()=>{
const data={
alias:document.getElementById('inputalias').value,
privateKey:document.getElementById('privatekey').getAttribute('key'),
publicKey:document.getElementById('publickey').getAttribute('key'),
passphrase:document.getElementById('inputpassphrase').value
}
axios.post('api/pagans',data,apx.data.headers)
.then(rep=>{
// genere authentification headers.xalias, xhash store object.pagans_alias={privateKey, passphrase}; console.log(rep)})
// if check trust add data email recovery axios.post('api/persons,data, apx.data.headers)
})
.catch(err=>{
console.log('sorry',err);
})
}
app.search = (elt) => {
//@todo get search string from input then return tpldata.listofarticles={"search":[]}
console.log("A FAIRE");
};
app.downloadlink = (keys, object, prefix) => {
/**
*
* @param {string} split(.) to naviagte in object until a subobject
* @param {object} a json object
*
* Create a link that download subobject as a textfile
* example:
* const obj={pagans:{privateKey:"123", publicKey:"AZE"}}
* const prefix = "appname"
* const keys="pagans.privateKey"
*
* in <html>
* <button class="btn btn-outline-primary" onclick="app.downloadlink('pagans.privateKey',obj,prefix);" >Download PrivateKey</button>
*
*
*/
const dwn = (fn, t) => {
var element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(t)
);
element.setAttribute("download", fn);
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};
const subobj = keys.split(".").reduce((val, k) => (val = val[k]), object);
const txt = typeof subobj == "string" ? subobj : JSON.stringify(subobj);
dwn(`${prefix}_${keys.split(".").pop()}.txt`, txt);
};
app.setupdata = () => {
//todo generate tpldata.listofarticle get html from /static/html
apx.data.tpldata.listofarticle = {
mostread: [{}],
news: [{}],
search: [],
articles: "html",
};
const list = {}
document.querySelectorAll("[add2data]").forEach((e) => {
/** Collect from any tag with add2data url attribute (tpl tpldata object)
* name is the filename :
* for tpl and tpldata (relativepath/filename_xx.ext) name=filename
* For public object (pagans, towns, nations, block) not tribes object are gettable (only)
* with /nationchains/objectName/idx/existingindex.json
* or for an item /itm//primarykey_value_of_item.json
*
* For tribe object get or for modification you need to use api and to have accessright setup properly:
* for object index (/api/odmdb/objectname/idx/filename.json) name =objectname_filename
* for object item (/api/odmdb/objectname/itm/primarykey.json) name =objectname_primarykey
*/
if (e.getAttribute('object')){
const url = e.getAttribute('object')
const spliturlobj=url.split("/").slice(-3);
const objectname=spliturlobj[0];
const objecttype=spliturlobj[1];
const objectkey=spliturlobj[2].substring(0,spliturlobj[2].length-5)
if (!list[objectname]) list[objectname]={};
list[objectname][`${objecttype}${objectkey}`]= url;
};
for (let k of ["tpl", "tpldata"]) {
if (e.getAttribute(k)){
const url=e.getAttribute(k);
let localname=url.split('/').slice(-1)[0];
if (url.includes('.mustache')) localname=localname.substring(0,localname.length-12);
if (url.includes('.html') || url.includes('.html') ) localname=localname.substring(0,localname.length-6);
if (!list[k]) list[k]={};
list[k][localname]=url;
}
}
});
// load external template and data
for (let k of Object.keys(list) ) {
console.log(k, list[k]);
apx.loadfile(list[k], k);
}
//alert(apx.data.firsttimeload)
if (apx.data.firsttimeload) {
// Need to wait the first time apx.data fully load
setTimeout(() => {
app.setuppage();
}, 300);
delete apx.data.firsttimeload;
apx.save();
}else{
app.setuppage();
}
};
app.load = (idtoload, tplname, tpldata) => {
const tpl = apx.data.tpl[tplname]
? apx.data.tpl[tplname]
: `missing template ${tplname}`;
const data = typeof tpldata == "string" ? apx.data.tpldata[tpldata] : tpldata;
document.getElementById(idtoload).innerHTML = Mustache.render(tpl, data);
};
app.setuppage = () => {
// load partial template
document.querySelectorAll("[apptoload]").forEach((e) => {
console.log(e.getAttribute("apptoload"));
eval(e.getAttribute("apptoload"));
});
};
apx.ready(app.setupdata);

View File

@@ -0,0 +1,211 @@
/*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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long