modif towns
This commit is contained in:
		
							
								
								
									
										98
									
								
								nationschainssave/www/adminapx/index_en.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								nationschainssave/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> | ||||
							
								
								
									
										48
									
								
								nationschainssave/www/adminapx/nginx/modelwebsite.conf.mustache
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								nationschainssave/www/adminapx/nginx/modelwebsite.conf.mustache
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| 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/ { | ||||
|      add_header X-debug "plugins local $arg_plugin/keys/$arg_pluginkey sent"; | ||||
|      root {{{dirname}}}/{{{nginx.fswww}}}/plugins/; | ||||
|      if (-f {{{dirname}}}/{{{nginx.fswww}}}/plugins/$arg_plugin/keys/$arg_pluginkey) { | ||||
|       rewrite /plugins/([^/]+)/components/([^\?]+) /$1/components/$2 break; | ||||
|      } | ||||
|      return 403 "No valid token access for plugin:$arg_plugin with token:$arg_pluginkey please ask your admin"; | ||||
|    } | ||||
|  | ||||
|    location /cdn/ { | ||||
|      rewrite /cdn/(.*$) /$1 break; | ||||
|      root {{{dirname}}}/{{{nginx.fswww}}}www/cdn/; | ||||
|     } | ||||
|  | ||||
|   location /spacedev/ { | ||||
|      rewrite /spacedev/(.*$) /$1 break; | ||||
|      root {{{dirname}}}/{{{nginx.fswww}}}spacedev/{{{nginx.website}}}/dist/; | ||||
|     } | ||||
|    | ||||
|    location /api/ { | ||||
|      rewrite /api/(.*$) /$1 break; | ||||
|      proxy_pass http://localhost:{{{api.port}}}; | ||||
|      proxy_redirect off; | ||||
|      include proxy_params; | ||||
|     } | ||||
|     | ||||
|    location / { | ||||
|      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 | ||||
|     # | ||||
|     error_page   500 502 503 504  /50x.html; | ||||
|     location = /50x.html { | ||||
|         root   /usr/local/nginx/html; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								nationschainssave/www/adminapx/nginx/nginx.conf.mustache
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								nationschainssave/www/adminapx/nginx/nginx.conf.mustache
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| user  {{{sudoerUser}}}; | ||||
| worker_processes  auto; | ||||
| error_log  {{{       }}}/var/log/nginx/error.log notice; | ||||
| pid        /var/run/nginx.pid; | ||||
| #include /etc/nginx/modules-enabled/*.conf; | ||||
|  | ||||
| events { | ||||
|     worker_connections  1024; | ||||
| } | ||||
| http { | ||||
|     include       /etc/nginx/mime.types; | ||||
|     default_type  application/octet-stream; | ||||
|      | ||||
|     log_format  main  '[$time_local]##"$http_x_forwarded_for"##"$request" ' | ||||
|                       '"$http_user_agent"'; | ||||
|  | ||||
|     log_format  mainold  '$remote_addr - $remote_user [$time_local] "$request" ' | ||||
|                       '$status $body_bytes_sent "$http_referer" ' | ||||
|                       '"$http_user_agent" "$http_x_forwarded_for"'; | ||||
|     log_format trace  '$remote_addr - $remote_user [$time_local] ' | ||||
|                       '$host "$request" $status $body_bytes_sent ' | ||||
|                       '"$http_referer" "$http_user_agent" ' | ||||
|                       '"$http_x_forwarded_for" $request_id'; | ||||
|     access_log  /var/log/nginx/access.log  main; | ||||
|     sendfile        on; | ||||
|     keepalive_timeout  65; | ||||
|     gzip  on; | ||||
|    ## | ||||
|    # Virtual Host Configs | ||||
|    ## | ||||
|     {{#nginx.include}} | ||||
|       include {{{.}}}; | ||||
|     {{/nginx.include}} | ||||
| } | ||||
							
								
								
									
										11
									
								
								nationschainssave/www/adminapx/nginx/proxy_params.mustache
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								nationschainssave/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
									
								
								nationschainssave/www/adminapx/static/js/apxapp.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								nationschainssave/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
									
								
								nationschainssave/www/adminapx/static/js/apxtribcli.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								nationschainssave/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
									
								
								nationschainssave/www/adminapx/static/js/axios.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								nationschainssave/www/adminapx/static/js/axios.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								nationschainssave/www/adminapx/static/js/axios.min.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								nationschainssave/www/adminapx/static/js/axios.min.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								nationschainssave/www/adminapx/static/js/mustache.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								nationschainssave/www/adminapx/static/js/mustache.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										17
									
								
								nationschainssave/www/adminapx/static/js/openpgp.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								nationschainssave/www/adminapx/static/js/openpgp.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												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> | ||||
| @@ -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> | ||||
| @@ -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 @@ | ||||
| {} | ||||
							
								
								
									
										30
									
								
								nationschainssave/www/adminapx/townconf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								nationschainssave/www/adminapx/townconf.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| { | ||||
|   "nationId": "ants", | ||||
|   "townId": "wall", | ||||
|   "IP":"213.32.65.213", | ||||
|   "tribeId":"ndda", | ||||
|   "dns": ["wallant.ndda.fr"], | ||||
|   "mayorId":"philc", | ||||
|   "passphrase":"", | ||||
|   "api": { | ||||
|     "port": 3020, | ||||
|     "languages": ["en","fr"], | ||||
|     "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" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										25
									
								
								nationschainssave/www/adminapx/tribeconf.json
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										25
									
								
								nationschainssave/www/adminapx/tribeconf.json
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| { | ||||
|   "tribeid": "${tribeName}", | ||||
|   "genericpsw": "", | ||||
|   "saltRounds": "12", | ||||
|   "allowedDOMs": ["${townName}.${nationName}.${dns}"], | ||||
|   "customization": { | ||||
|     "claim": "Be a Producer, not a product.", | ||||
|     "name": "apxtrib", | ||||
|     "logo": "https://${townName}.${nationName}.${dns}/static/img/chartegraphique/logo_bgtransparent.png", | ||||
|     "favicon": "https://${townName}.${nationName}.${dns}/static/img//chartegraphique/favicon.png", | ||||
|     "colors": { | ||||
|       "primary": "#01717B", | ||||
|       "secondary": "#CA5F00", | ||||
|       "success": "", | ||||
|       "info": "", | ||||
|       "warning": "", | ||||
|       "danger": "", | ||||
|       "light": "#fff", | ||||
|       "dark": "#222" | ||||
|     } | ||||
|   }, | ||||
|   "smtp": {}, | ||||
|   "accepted-language": "fr,en", | ||||
|   "langueReferential": ["fr"] | ||||
| } | ||||
		Reference in New Issue
	
	Block a user