in progress
This commit is contained in:
@@ -1,88 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>setup apXtrib</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<style>
|
||||
.fakeimg {
|
||||
height: 200px;
|
||||
background: #aaa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="p-5 bg-primary text-white text-center">
|
||||
<h1>apXtrib setup a new Towns</h1>
|
||||
<p>Resize this responsive page to see the effect!</p>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">Active</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" href="#">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<h2>About Me</h2>
|
||||
<h5>Photo of me:</h5>
|
||||
<div class="fakeimg">Fake Image</div>
|
||||
<p>Some text about me in culpa qui officia deserunt mollit anim..</p>
|
||||
<h3 class="mt-4">Some Links</h3>
|
||||
<p>Lorem ipsum dolor sit ame.</p>
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">Active</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" href="#">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
<hr class="d-sm-none">
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<h2>TITLE HEADING</h2>
|
||||
<h5>Title description, Dec 7, 2020</h5>
|
||||
<div class="fakeimg">Fake Image</div>
|
||||
<p>Some text..</p>
|
||||
<p>Sunt in culpa qui officia deserunt mollit anim id est laborum consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
|
||||
|
||||
<h2 class="mt-5">TITLE HEADING</h2>
|
||||
<h5>Title description, Sep 2, 2020</h5>
|
||||
<div class="fakeimg">Fake Image</div>
|
||||
<p>Some text..</p>
|
||||
<p>Sunt in culpa qui officia deserunt mollit anim id est laborum consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 p-4 bg-dark text-white text-center">
|
||||
<p>Footer</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
98
nationchains/www/adminapx/index_en.html
Normal file
98
nationchains/www/adminapx/index_en.html
Normal file
@@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>setup apXtrib</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- fontawesome icon cdn -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.1/css/all.css">
|
||||
<script>
|
||||
const apxlocal={
|
||||
headers:{xalias:"anonymous",xhash:"anonymous",xtribe:"devenv", xapp:"smatchapp", xlang:"en" },
|
||||
firsttimeload:true,
|
||||
forcereload:true,
|
||||
tpl:{
|
||||
footer:"{{{msg}}}"
|
||||
},
|
||||
tpldata:{
|
||||
footer:{msg:"<p>apXtrib, made with love for people freedom, enjoy!</p>"}
|
||||
},
|
||||
object:{}
|
||||
};
|
||||
// @todo check version control to force a reload with forceload
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="static/js/openpgp.min.js"></script>
|
||||
<script src="static/js/mustache.min.js"></script>
|
||||
<script src="static/js/axios.min.js"></script>
|
||||
<script src="static/js/apxtribcli.js"></script>
|
||||
<script src="static/js/apxapp.js"></script>
|
||||
<style>
|
||||
.fakeimg {
|
||||
height: 200px;
|
||||
background: #aaa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="p-5 bg-primary text-white text-center">
|
||||
<h1>apXtrib & Frontend</h1>
|
||||
<p> How to build a quick web app with bootstrap V5 framework and apXtrib back-end</p>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" add2data tpl="static/tpl/listofarticle_en.mustache" onclick="app.load('apxmain','listofarticle','listofarticle')" >Home</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Pagans</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" add2data tpl="static/tpl/pagancreate_en.mustache" object="nationchains/pagans/idx/alias_all.json" onclick="app.load('apxmain','pagancreate',{})">Create</a></li>
|
||||
<li><a class="dropdown-item" add2data tpl="static/tpl/loginout_en.mustache" tpldata="static/tpldata/loginout_en.json" onclick="app.load('apxmain','loginout',{})">Login/Logout</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="#">Cipher</a></li>
|
||||
<li><a class="dropdown-item" href="#">AccessRights</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">0dmdb</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#">Schema Checkjson.js</a></li>
|
||||
<li><a class="dropdown-item" href="#">Object CRUD with schema</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">nationChains</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#">Wallet management</a></li>
|
||||
<li><a class="dropdown-item" href="#">Signed Contracts</a></li>
|
||||
<li><a class="dropdown-item" href="#">NFT generator</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Utils</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" href="#">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="apxmain" apptoload="app.load('apxmain','listofarticle','listofarticle')" class="container mt-5">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="apxfooter" apptoload="app.load('apxfooter','footer','footer')" class="mt-5 p-4 bg-dark text-white text-center">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -1,6 +1,11 @@
|
||||
server {
|
||||
server_name {{#dns}} {{.}} {{/dns}};
|
||||
access_log {{{dirname}}}/{{{nginx.fswww}}}logs/nginx/{{{nginx.website}}}.{{{nginx.tribeid}}}.access.log main;
|
||||
|
||||
location ~* /nationchains/(schema|blocks|pagans|towns|nations)/ {
|
||||
# Warning: never add tribes for keeping it private
|
||||
root {{{dirname}}}/;
|
||||
}
|
||||
# /plugins/pluginame/components/xxx?plugin=pluginname&pluginkey=key
|
||||
# acess if exist pluginkey
|
||||
location /plugins/ {
|
||||
@@ -14,33 +19,24 @@ server {
|
||||
|
||||
location /cdn/ {
|
||||
rewrite /cdn/(.*$) /$1 break;
|
||||
root {{{dirname}}}/{{{nginx.fswww}}}/www/cdn/;
|
||||
root {{{dirname}}}/{{{nginx.fswww}}}www/cdn/;
|
||||
}
|
||||
|
||||
location /spacedev/ {
|
||||
rewrite /spacedev/(.*$) /$1 break;
|
||||
root {{{dirname}}}/{{{nginx.fswww}}}/spacedev/{{{website}}}/dist/;
|
||||
root {{{dirname}}}/{{{nginx.fswww}}}spacedev/{{{nginx.website}}}/dist/;
|
||||
}
|
||||
|
||||
location /app/ {
|
||||
rewrite /app/(.*$) /$1 break;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
client_max_body_size 10m;
|
||||
client_body_buffer_size 128k;
|
||||
proxy_connect_timeout 90;
|
||||
proxy_send_timeout 90;
|
||||
proxy_read_timeout 90;
|
||||
proxy_buffers 32 4k;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_pass http://localhost:{{{apiport}}};
|
||||
|
||||
location /api/ {
|
||||
rewrite /api/(.*$) /$1 break;
|
||||
proxy_pass http://localhost:{{{api.port}}};
|
||||
proxy_redirect off;
|
||||
include proxy_params;
|
||||
}
|
||||
|
||||
|
||||
location / {
|
||||
root {{{dirname}}}/{{{nginx.fswww}}}/www/app/{{{website}}};
|
||||
index index.html {{{pageindex}}};
|
||||
root {{{dirname}}}/{{{nginx.fswww}}}www/{{{nginx.website}}};
|
||||
index index.html {{{nginx.pageindex}}};
|
||||
}
|
||||
error_page 404 /404.html;
|
||||
# redirect server error pages to the static page /50x.html
|
||||
|
11
nationchains/www/adminapx/nginx/proxy_params.mustache
Normal file
11
nationchains/www/adminapx/nginx/proxy_params.mustache
Normal file
@@ -0,0 +1,11 @@
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
client_max_body_size 10m;
|
||||
client_body_buffer_size 128k;
|
||||
proxy_connect_timeout 90;
|
||||
proxy_send_timeout 90;
|
||||
proxy_read_timeout 90;
|
||||
proxy_buffers 32 4k;
|
||||
proxy_set_header X-NginX-Proxy true;
|
157
nationchains/www/adminapx/static/js/apxapp.js
Normal file
157
nationchains/www/adminapx/static/js/apxapp.js
Normal 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);
|
211
nationchains/www/adminapx/static/js/apxtribcli.js
Normal file
211
nationchains/www/adminapx/static/js/apxtribcli.js
Normal 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);
|
3
nationchains/www/adminapx/static/js/axios.min.js
vendored
Normal file
3
nationchains/www/adminapx/static/js/axios.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
nationchains/www/adminapx/static/js/axios.min.map
Normal file
1
nationchains/www/adminapx/static/js/axios.min.map
Normal file
File diff suppressed because one or more lines are too long
1
nationchains/www/adminapx/static/js/mustache.min.js
vendored
Normal file
1
nationchains/www/adminapx/static/js/mustache.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
17
nationchains/www/adminapx/static/js/openpgp.min.js
vendored
Normal file
17
nationchains/www/adminapx/static/js/openpgp.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
nationchains/www/adminapx/static/js/openpgp.min.js.map
Normal file
1
nationchains/www/adminapx/static/js/openpgp.min.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<h3>webapp creation</h3>
|
||||
<p>Step by step </p>
|
||||
<div class="input-group mb-3">
|
||||
<input class="form-control me-1" type="search" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-outline-primary" onclick="app.search(this)">
|
||||
<i class="fa-solid fa-magnifying-glass"></i>
|
||||
</button>
|
||||
</div>
|
||||
<h4 class="mt-4">Articles</h4>
|
||||
<p>Most read</p>
|
||||
<ul class="nav nav-pills flex-column">
|
||||
{{#mostread}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" onclick="app.load('apxmain','{{tplname}}','{{tpldata}}')">{{{title}}}</a>
|
||||
</li>
|
||||
{{/mostread}}
|
||||
</ul>
|
||||
<hr class="d-sm-none">
|
||||
<p>News</p>
|
||||
<ul class="nav nav-pills flex-column">
|
||||
{{#news}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" onclick="app.load('apxmain','{{tplname}}','{{tpldata}}')">{{{title}}}</a>
|
||||
</li>
|
||||
{{/news}}
|
||||
</ul>
|
||||
<hr class="d-sm-none">
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
{{#articles}}
|
||||
<h2>{{{heading}}</h2>
|
||||
<h5>{{{shortdescdate}}}</h5>
|
||||
<div class="fakeimg">Fake Image</div>
|
||||
{{{htmlcontent}}}
|
||||
{{/articles}}
|
||||
</div>
|
||||
</div>
|
23
nationchains/www/adminapx/static/tpl/loginout_en.mustache
Normal file
23
nationchains/www/adminapx/static/tpl/loginout_en.mustache
Normal file
@@ -0,0 +1,23 @@
|
||||
<div class="container">
|
||||
<h5>How to identify ourself</h5>
|
||||
<p>You need to know your alias and to have your privateKey file</p>
|
||||
<div class="mb-3">
|
||||
<label for="youralias" class="form-label">Your alias</label>
|
||||
<input type="email" class="form-control" id="youralias" aria-describedby="aliasHelp">
|
||||
<div id="aliasHelp" class="form-text">Your unique alias when you create your account</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="inputprivateKey" class="form-label">Copy & paste or load your private Key</label>
|
||||
<textarea type="password" class="form-control" id="inputprivateKey" rows="6"></textarea>
|
||||
<div id="inputprivateKey" class="form-text">I forgot my keys, <a onclick="">click to request it with my email recovery</a> or <a onclick="">Click to receive it from my alias</a> </div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="emailrecovery" class="form-label">Your email recovery</label>
|
||||
<input type="email" class="form-control" id="emailrecovery" placeholder="name@example.com">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="file" class="form-control" id="inputGroupFile04" aria-describedby="inputGroupFileAddon04" aria-label="Upload">
|
||||
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04">Button</button>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary d-none">Identify you</button>
|
||||
</div>
|
54
nationchains/www/adminapx/static/tpl/pagancreate_en.mustache
Normal file
54
nationchains/www/adminapx/static/tpl/pagancreate_en.mustache
Normal file
@@ -0,0 +1,54 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-6" data-spacename="explain">
|
||||
<h2>How it works</h2>
|
||||
<p> Alias is a unique string that humainly help to match a PublicKey to check existing alias</p>
|
||||
<code>
|
||||
GET /api/odmdb/idx/pagans/pagans_alias_all.json with a correct headers
|
||||
RESULT
|
||||
data:{alias:publicKey}
|
||||
</code>
|
||||
<p>
|
||||
Run
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-sm-6" data-spacename="userinterface">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="inputalias" class="form-label">Your alias</label>
|
||||
<input type="text" class="form-control" id="inputalias" placeholder="A public alias that any one see">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="inputemailrecovery" class="form-label">Email Recovery</label>
|
||||
<input type="email" class="form-control" id="inputemailrecovery" placeholder="optional, if you want to receive by mail your keys">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="inputpassphrase" class="form-label">A passphrase</label>
|
||||
<input type="text" class="form-control" id="inputpassphrase" placeholder="optional, a passphrase to remember, each time something try to use your privateKey this passphrase will be requested">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="button" id="generatekeys" onclick="app.createIdentity(document.getElementById('inputalias').value,document.getElementById('inputpassphrase').value)" class="btn btn-primary">Generate keys</button>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="gridCheck">
|
||||
<label class="form-check-label small" for="gridCheck">
|
||||
<b>I trust smatchit to keep my private key and email </b><br>
|
||||
<b>If i don't trust</b> please download your keys (be aware, none than you can have access to your cipher data).<br>
|
||||
If you set a correct email then you will receive your keys on your mailbox (Carefull by sending email, smatchit and anyone that access to your email can see your keys).<br>
|
||||
The safer to be sure no one else than your local browser can see it, just download localy and save it on a personnal cold support (usb key).<br>
|
||||
If you use a browser that <b>can be accessible by someone else, don't forget to "logout"</b> to clean up any trace.<br>
|
||||
If you have any suspicious please
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="downloadkeys" class="btn-group d-none">
|
||||
<p>Download your keys at least PrivateKey this have to save in a secret place</p>
|
||||
<button id="privatekey" key="" class="btn btn-outline-primary" onclick="app.downloadlink('pagans.privateKey',apx.data,apx.data.headers.xapp);" >Download PrivateKey</button>
|
||||
<button id="publickey" key="" class="btn btn-outline-primary" onclick="app.downloadlink('publicKey',this.getAttribute('key'),apx.data.headers.xapp);">Download PublicKey</button>
|
||||
</div>
|
||||
<div id="createId" class="col-12 d-none">
|
||||
<button class="btn btn-primary" onclick="app.registerIdentity()">Create this identity</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1 @@
|
||||
{}
|
@@ -1,25 +1,32 @@
|
||||
{
|
||||
"nationName":"ants",
|
||||
"townName":"setuptown",
|
||||
"tribeName":"setuptribe",
|
||||
"dns":["adminapx"],
|
||||
"apiport":3018,
|
||||
"language":["en"],
|
||||
"jwtsecret":"longsentenceusedtoencryptionChangethisforproduction",
|
||||
"saltRounds":10,
|
||||
"exposedHeaders":[ "xauth", "xpaganid", "xlang", "xtribe", "xworkon", "xapp" ],
|
||||
"unittesting":["middlewares","models","routes","nationchains"],
|
||||
"appset":{"trust proxy":true},
|
||||
"bodyparse": {
|
||||
"urlencoded": {
|
||||
"limit": "50mb",
|
||||
"extended": true
|
||||
},
|
||||
"json": { "limit": "500mb" }
|
||||
},
|
||||
"nginx":{
|
||||
"restart":"sudo systemctl restart nginx",
|
||||
"worker_connections":1024,
|
||||
"include":["/etc/nginx/conf.d/*.conf", "/etc/nginx/sites-enabled/*"]
|
||||
}
|
||||
}
|
||||
"nationId": "ants",
|
||||
"townId": "usbfarm",
|
||||
"IP":"127.0.0.1",
|
||||
"tribeId":"devenv",
|
||||
"dns": ["adminapx"],
|
||||
"mayorId":"philc",
|
||||
"passphrase":"",
|
||||
"api": {
|
||||
"port": 3020,
|
||||
"languages": ["en","fr"],
|
||||
"jwtsecret": "longsentenceusedtoencryptionChangethisforproduction",
|
||||
"saltRounds": 10,
|
||||
"exposedHeaders": ["xhash", "xalias", "xlang", "xtribe", "xapp"],
|
||||
"nationObjects":["schema","blocks","nations","towns","tribes","pagans"],
|
||||
"unittesting": ["middlewares", "models", "routes", "nationchains"],
|
||||
"appset": { "trust proxy": true },
|
||||
"bodyparse": {
|
||||
"urlencoded": {
|
||||
"limit": "50mb",
|
||||
"extended": true
|
||||
},
|
||||
"json": { "limit": "500mb" }
|
||||
}
|
||||
},
|
||||
"nginx": {
|
||||
"restart": "sudo systemctl restart nginx",
|
||||
"worker_connections": 1024,
|
||||
"include": ["/etc/nginx/conf.d/*.conf"],
|
||||
"pageindex":"index_en.html"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user