This commit is contained in:
philc 2023-12-05 07:42:35 +01:00
parent 5997ab759a
commit 763034e077
30 changed files with 1484 additions and 2066 deletions

View File

@ -1,25 +0,0 @@
{
"title": "Une Personne au niveau d'une tribut avec des informations personnelle",
"description": "Un alias peut se stoquer comme un objet Person avec des informations supplémentaire permettant de qualifier son profil",
"properties": {
"alias": { "title": "Une identité numérique d'apxtrib" },
"dt_create": { "title": "Date de creation de cette personne" },
"dt_update": { "title": "Date de derniére mise à jour" },
"dt_lastlogin": { "title": "Date de derniere authentification" },
"dt_close": { "title": "Date de fermeture de compte" },
"recoveryauth": {
"title": "Information pour recuperer ses codes d'accès",
"properties": {
"email": { "title": "email de recuperation" },
"alias": {
"title": "Alias qui doit exister comme une Person dans une tribu"
},
"privatekey": { "title": "Private key link to alias" },
"passphrase": { "title": "Passphrase to uncipher privatekey" }
}
},
"biography": { "title": "Description courte" },
"imgavatar": { "title": "Url de l'image utilisée comme avatar" },
"accessrights": { "title": "Droits d'accès" }
}
}

View File

@ -15,7 +15,7 @@
"title": "Alias",
"description": "text to remember easily a public key",
"type": "string",
"minLength": 4,
"minLength": 3,
"pattern": "^[a-z0-9]*$"
},
"dt_delete": {
@ -34,8 +34,8 @@
"apxid": "alias",
"apxuniquekey": ["publickey"],
"apxidx": [
{ "name": "lst_alias", "keyval": "alias" },
{ "name": "alias", "keyval": "alias" }
{ "name": "lst_alias", "type":"array", "keyval": "alias" },
{ "name": "alias", "type":"view", "keyval": "alias","objkey":[],"filter":"" }
],
"apxaccessrights": {
"owner": { "R": [], "D": [] },

View File

@ -1,194 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "/schema/person",
"title": "Person minimum definition to link a person to a pagan identity",
"description": "A person is a human with a apxtrib identity (alias = Public Private Key) that accept to be part of a tribe (a person is store inside a tribe). Information stored for a person are only visible from the town's Mayor and the tribe's Druid. You need at least trust the druid that trust the mayor (for sensitive data Mayor and Druid can be the same apx Identity.) Only a pagan that have the privateKey can read cipher data. The purpose of this schema is to link a person to a tribe and manage basic activities, profil for specific purpose will be a tribe object that can be add additionalProperties of this is set at true.",
"type": "object",
"properties": {
"alias": {
"title": "alias",
"description": "A unique string identifying a unique public key",
"type": "string",
"minLength": 5,
"pattern": "^[a-z0-9]*$"
},
"owner": {
"title": "Owner of this person",
"description": "For accessright purpose this is always equal as alias",
"type": "string",
"format": "Alias"
},
"dt_create": {
"type": "string",
"format": "date-time",
"default": "dayjs.now()"
},
"dt_update": {
"type": "string",
"format": "date-time"
},
"dt_lastlogin": {
"title": "Last time login",
"description": "Last time this person authentify as alias access to this tribe",
"type": "string",
"format": "date-time"
},
"dt_delete": {
"title": "Date of leaving tribe",
"description": "Date from when this alias is ban of tribe by druid or want to leave. A pocess of data cleaning has to be run depending of Tribe's rules.",
"type": "string",
"format": "date"
},
"will": {
"title": "Will script after leaving tribe",
"description": "This will script will be apply on your data 30 days after your delete",
"type": "string",
"format": "js"
},
"recoveryauth": {
"title": "Store numeric identity to recover it by email",
"description": "This object store numeric identity alias with an email mainly used at Person level to recover by email a private and passphrase key associate to alias",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"privatekey": {
"type": "string",
"format": "pgpprivatekey"
},
"publickey": {
"type": "string",
"format": "pgppublickey"
},
"passphrase": {
"type": "string"
}
}
},
"firstname": {
"title": "A firstname",
"description": "This will be use to present yourself",
"type": "string"
},
"lastname": {
"title": "A lastname",
"description": "This will be use to present yourself",
"type": "string"
},
"dt_birth": {
"title": "Your birthdate",
"description": "Date of birth you want to communicate",
"type": "string",
"format": "date"
},
"pronom": {
"title": "Your pronom",
"description": "The way you want people communicate with you",
"type": "string",
"enum": ["0", "1", "2"]
},
"emailcom": {
"title": "email use to communicate with you",
"description": "email used by tribe to communicate with you, depending of your profil you can also define other mail to interact with other person",
"type": "string",
"format": "email"
},
"hobbies": {
"title": "My hobbies",
"type": "array",
"comment": "from a tree word combinaison /lg/hobbies_xx.json"
},
"biography": {
"title": "Your bio or few words to define yourself",
"description": "Use this to share your values, this will be public to all of tribe's members and link to your person",
"type": "string",
"pattern": "^.{O,150}$"
},
"mbti": {
"type": "object"
},
"imgavatar": {
"title": "A picture of your person or personnality",
"description": "This picture will be public to all tribe's member",
"type": "url"
},
"profils": {
"title": "Array of profil",
"description": "List of profil to get accessright on object",
"type": "array"
}
},
"required": ["alias", "profilaccess"],
"additionalProperties": true,
"apxid": "alias",
"apxuniquekey": ["alias"],
"apxidx": [
{
"name": "lst_alias",
"keyval": "alias"
},
{
"name": "alias",
"keyval": "alias"
},
{
"name": "profils_alias",
"keyval": "profils",
"objkey": "alias"
},
{
"name": "emailcom_alias",
"keyval": "emailcom",
"objkey": "alias"
},
{
"name": "hobbies_alias",
"keyval": "hobbies",
"objkey": "alias"
}
],
"apxaccessrights": {
"owner": {
"D": [],
"R": [
"alias",
"dt_create",
"dt_update",
"last_login",
"firstname",
"lastname",
"dt_birth",
"pronom",
"emailcom",
"hobies",
"biography",
"imgavatar",
"profilaccess"
],
"U": [
"firstname",
"lastname",
"dt_birth",
"pronom",
"emailcom",
"hobies",
"biography",
"imgavatar",
"profilaccess"
]
},
"pagan": {
"C": []
},
"mayor": {
"D": [],
"R": ["alias"]
},
"druid": {
"D": [],
"R": ["alias"]
}
}
}

View File

@ -0,0 +1,100 @@
// See https://nodemailer.com/message/ for available fields to add
// email template to get key registration
const tplemail={};
tplemail.sender = "smatchtit<noreply@smatchit.io>"
tplemail.replyTo="{{{name}}}<{{{email}}}>"
tplemail.inreplyTo=""
tplemail.references=""
//tplemail.from = "noreply@smatchit.io" get by default in configtrib.emailcontact or server ;emailcontact
tplemail.to="<{{emailcontact}}>"
tplemail.subject="Vos clés d'identification pour {{alias}}"
tplemail.cc=""
tplemail.bcc=""
tplemail.attachments=[]
/*example
attachments: [
{
filename: "{{data}}.txt",
pathfile: "{{data}}",
contenttype: "text/plain",
minepart: "mixed",
},
{
filename: "my-image.jpg",
content: "blabla content",
contenttype: "image/jpeg",
minepart: "alternative",
},
],
if content and filepath is present filepath content replace content
*/
tplemail.html=`
<html>
<head>
<meta charset="utf-8">
<style>
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" align="center" style="width: 600px; border: none; padding: 0;" width="600">
<tr style="padding:20px;">
<td>
<p style="padding:20px 0 5px 0;">
<img width="200px" src="https://smatchit.io/static/img/logo/logoBlackSimple.webp" srctmp="https://smatchit.io/trk/static/img/logo/logoBlackSimple.webp?alias={{alias}}&uuid={{uuid}}&srckey=registeremailcontact&version=1&consentcookie={{consentcookie}}" alt="smatchit" />
</p>
<hr style="border-top:1px solid #0DC3FF;">
</td>
</tr>
<tr>
<td style="padding:20px 0 40px 0;">
<h1 style="font-size:15px;font-family:Monserrat;">Votre identité numérique: {{alias}}</h1>
<p style="font-size:12px;font-family:Monserrat;">Vous avez souhaité recevoir vos clés d'identification via {{tribe}}. Une identité numerique est composée de 2 fichiers texte appelés clé privée et clé public. </p>
<p style="font-size:12px;font-family:Monserrat;">
Son usage est simple mais souvent méconnu, avec une fonction mathematique, la clé privée permet de signer un message. Avec une autre fonction, on vérifie que la signature est bien issue de la cle public sans avoir besoin de disposer de la clé privée.
</p>
<p style="font-size:12px;font-family:Monserrat;">Les applications de {{tribe}} fonctionnent toutes de cette façon et permettent non seulement de vous identifier mais aussi de chiffrer vos données lisible uniquement grâce à votre clé privée. Pour simplifier l'usage de ces clés nous associons un alias à votre clé public.</p>
{{#avecpassphrase}}
<p style="font-size:12px;font-family:Monserrat;">
Pour plus de securité, on peut vous demander une passphrase qui dans votre cas est :{{passphrase}}
</p>
{{/avecpassphrase}}
<p style="font-size:12px;font-family:Monserrat;">Gardez précieusement ces clés et <strong>ne communiquez jamais votre clé privée</strong>. Uniquement votre alias (et eventuellement votre clé public).</p>
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" align="center" style="width: 100%; border: none; padding: 0;" width="100%">
<tr bgcolor="#161616">
<td bgcolor="#161616" align="center" style="padding:20px;">
<p style="text-align:center;">
<img src="https://smatchit.io/static/img/logo/logoSignature.webp" alt="smatchit">
</p>
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" align="center" style="width: 600px; border: none; padding: 0;" width="600" >
<tr>
<td style="padding:20px 0 0 0;">
<p style="font-size:11px;font-family:Monserrat;">
Nos conditions d'utilisation et politique de protection des données <a href="https://smatchit.io/cgu_fr.html" target='_blank'> CGU</a>
</p>
</td>
</tr>
</table>
</body>
</html>
`
tplemail.text=`
Vos clés d'authentifications:
alias: {{alias}}
passphrase: {{passphrase}}
publickey: copier coller entre les 2 lignes -------
---------------------
{{publickey}}
---------------------
privatekye: copier coller entre les 2 lignes -------
---------------------
{{privatekey}}
---------------------
`
module.exports=tplemail;

View File

@ -30,6 +30,16 @@ location ~* /nationchains/schema/ {
rewrite /nationchains/schema/(.*$) /$1 break;
root {{{dirapi}}}/adminapi/schema/;
}
location ~* /{{tribeId}}/schema/{
rewrite /{{tribeId}}/schema/(.*$) /$1 break;
root {{dirtown}}/tribes/{{tribeId}}/schema/;
}
location ~* /{{tribeId}}/models/{
rewrite /{{tribeId}}/models/(.*$) /$1 break;
root {{dirtown}}/tribes/{{tribeId}}/api/models/lg/;
}
# /plugins/pluginame/components/xxx?plugin=pluginname&pluginkey=key
# acess if exist pluginkey
location /plugins/ {

File diff suppressed because one or more lines are too long

View File

@ -2,16 +2,16 @@
<html>
<head>
<title>apiDoc for apXtrib</title>
<meta name="description" content="A Decentralized Autonomous Organization based on express.js restFULL api, allowing Pagans to join social rules (contracts.js) engrave in a nationsChains without any man in the middle.">
<meta name="description" content="Core api documentation">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="assets/bootstrap.min.css?v=1680266444523" rel="stylesheet" media="screen">
<link href="assets/prism.css?v=1680266444523" rel="stylesheet" />
<link href="assets/main.css?v=1680266444523" rel="stylesheet" media="screen, print">
<link href="assets/favicon.ico?v=1680266444523" rel="icon" type="image/x-icon">
<link href="assets/apple-touch-icon.png?v=1680266444523" rel="apple-touch-icon" sizes="180x180">
<link href="assets/favicon-32x32.png?v=1680266444523" rel="icon" type="image/png" sizes="32x32">
<link href="assets/favicon-16x16.png?v=1680266444523" rel="icon" type="image/png" sizes="16x16">
<link href="assets/bootstrap.min.css?v=1701757832579" rel="stylesheet" media="screen">
<link href="assets/prism.css?v=1701757832579" rel="stylesheet" />
<link href="assets/main.css?v=1701757832579" rel="stylesheet" media="screen, print">
<link href="assets/favicon.ico?v=1701757832579" rel="icon" type="image/x-icon">
<link href="assets/apple-touch-icon.png?v=1701757832579" rel="apple-touch-icon" sizes="180x180">
<link href="assets/favicon-32x32.png?v=1701757832579" rel="icon" type="image/png" sizes="32x32">
<link href="assets/favicon-16x16.png?v=1701757832579" rel="icon" type="image/png" sizes="16x16">
</head>
<body class="container-fluid">
@ -928,6 +928,6 @@
</div>
</div>
<script src="assets/main.bundle.js?v=1680266444523"></script>
<script src="assets/main.bundle.js?v=1701757832579"></script>
</body>
</html>

View File

@ -1,47 +1,51 @@
const conf = require(`${process.env.dirtown}/conf.json`);
/**
* @api{get}/CheckHeaders
* @api {get} http://header/CheckHeaders - CheckHeaders
* @apiGroup Middlewares
* @apiName CheckHeaders
* @apiDescription a list of header is mandatory to access apxtrib see tribes/townconf.json.exposedHeaders
* @apiDescription a list of headers are mandatory to access apxtrib see in your space town /conf.json.exposedHeaders
*
* @apiHeader {string} xalias anonymous or unique alias
* @apiHeader {string} xapp name of the webapp store in tribe/tribeid/www/xapp
* @apiHeader {string} xalias 'anonymous' or unique alias
* @apiHeader {string} xapp name of the webapp store in tribe/tribeid/www/{xapp}
* @apiHeader {string} xlang the 2 letter request langage (if does not exist then return en = english).
* @apiHeader {string} xtribe unique tribe name ere xapp exist
* @apiHeader {string} xtribe unique tribe name where xapp exist
* @apiHeader {string} xdays a timestamp 0 or generate during the authentifyme process
* @apiHeader {string} xhash anonymous or signature of message: xalias_xdays created by alias private key during authentifyme process
* @apiHeader {array[]} xprofils list of string profil apply into xtribe for xapp
* @apiHeader {string} xuuid a unique number c reated the fisrt time a domain is visited
* @apiHeader {string} xuuid a unique number uuid.v4 created the fisrt time a domain is visited on a device
* @apiHeader {integer} xtrkversion a version number link to tracking system
*
* @apiError missingexposedHeaders it miss an exposedHeaders
* @apiErrorExample {json} Error-Response:
* HTTP/1/1 400 Not Found
* {
* status:400,
* ref:"middlewares"
* msg:"missingheaders",
* data: ["headermissing1"]
* }
*@apiErrorExample {json} Error-Response:
* HTTP/1/1 404 Not Found
* {
* status:404,
* ref:"middlewares"
* msg:"tribeiddoesnotexist",
* data: {xalias}
* }
* @apiHeaderExample {json} Header-Exemple:
* {
* xtribe:"apache",
* xalias:"toto",
* xhash:"",
* xdays:"123"
* xlang:"en",
* xapp:"popular"
* }
*/
* @apiHeaderExample {json} Header-Example:
* {
* Cache-Control: "no-cache",
* Expires: 0, Pragma:"no-cache",
* xalias:"jojo",
* xapp:"presentation",
* xdays:1700733068298
* xhash:"LS0tLS1CRUdJTiBQR1AgU0lHTkVEIE1FU1NBR0UtLS0tLQpIYXNoOiBTSEE1MTIKCmpvam9fMTcwMDczMzA2ODI5OAotLS0tLUJFR0lOIFBHUCBTSUdOQVRVUkUtLS0tLQoKd25VRUFSWUtBQ2NGZ21WZklJd0prTmFVQ0daRHVUYnBGaUVFTjZlc1ZMSWdURmtPRGFVaDFwUUlaa081Ck51a0FBR09MQVA5OS96c21YeEd0b0VuYnpnekppZDJMcDA3YlBNZ1gwNUdhOUFVWjlCQm91Z0VBOVlYVworYjZIM2JHWHVhbEVOc3BrdUk1alNlTFNUWGNkSStjTExTZk5OQTg9Cj1uVjhNCi0tLS0tRU5EIFBHUCBTSUdOQVRVUkUtLS0tLQo=",
* xlang:"fr",
* xprofils:["anonymous", "pagans"],
* xtribe:"smatchit",
* xtrkversion:1,
* xuuid:"ea1cf73f-27f5-4c69-ab53-197a0feab9b2"
* }
* @apiErrorExample {json} Error-Response:
* HTTP/1/1 400 Not Found
* {
* status:400,
* ref:"middlewares",
* msg:"missingheaders",
* data:["headermissing1"]
* }
* @apiErrorExample {json} Error-Response:
* HTTP/1/1 404 Not Found
* {
* status:404,
* ref:"middlewares"
* msg:"tribeiddoesnotexist",
* data: {xalias}
* }
*/
const checkHeaders = (req, res, next) => {
req.session = {};
const header = {};
@ -66,6 +70,7 @@ const checkHeaders = (req, res, next) => {
if (missingheader != "") {
// bad request
return res.status(400).json({
status:400,
ref: "middlewares",
msg: "missingheader",
data: missingheader,
@ -80,6 +85,7 @@ const checkHeaders = (req, res, next) => {
)
) {
return res.status(404).json({
status:404,
ref: "middlewares",
msg: "tribeiddoesnotexist",
data: { xtribe: header.xtribe },

View File

@ -14,13 +14,9 @@ Objects manage in apXtrib: pagans, notifications, nations, towns, tribes, wwws 
All others objects are manage in town/tribe 
persons is the only exception, schema is manage in apXtrib but data are store in a tribe.
apxtrib conf is set in a conf.json at the same folder level:
```plaintext
/apxtrib/ # core process
/townName_nationName/conf.json # town settings
/townName_nationName/conf.json # town settings contain all glabl parameter
```
url: **/api/routeName** For core api apXtrib in /apxtrib :
@ -29,7 +25,7 @@ url: **/api/routeName** For core api apXtrib in /apxtrib :
/apxtrib/api/middlewares/
/apxtrib/api/routes/
/apxtrib/api/models/
/apxtrib/api/models/lg/ language customisation for api response
/apxtrib/api/models/lg/ lauage accessible by https://wall-ants.ndda.fr/nationchains/models/Checkjson_fr.json
/apxtrib/api/models/unitest/
```
@ -38,13 +34,11 @@ url: **/api/smatchit/routeName** for tribe smatchit example api in /town\_nation
```plaintext
/town_nation/tribes/smatchit/api/routes/
/town_nation/tribes/smatchit/api/models/
/town_nation/tribes/smatchit/api/models/lg/ language customization
/town_nation/tribes/smatchit/api/models/lg/ language customization accessible https://smatchit.io/smatchit/models/model_lg.json
```
**static files** are served by nginx, each tribe nginx conf are store and can be customize in /town\_nation/www/nginx\_xtribe\_xapp.conf
object www/websitename are serve with nginx not express.
## Object management (Odmdb)
An object has a name and is defined by a schema that contain properties key.
@ -52,6 +46,8 @@ An object has a name and is defined by a schema that contain properties key.
A propertie has a name and a list of caracteristics (type, pattern,format,...) that have to be validate to be accepted.
All properties respect the rules [https://json-schema.org/draft/2020-12/schema,](https://json-schema.org/draft/2020-12/schema,) some extra"format" can be add to mutualise recurrent regex pattern
To access a schema [https://wall-ants.ndda.fr/nationchains/schema/nations.json](https://wall-ants.ndda.fr/nationchains/schema/nations.json) and language specifique [https//:wall-ants.ndda.fr/nationchains/schema/lg/nations\_fr.json](https//:wall-ants.ndda.fr/nationchains/schema/lg/nations_fr.json)
A checkjson.js is available to manage all specific format [https://wall-ants.ndda.fr/Checkjson.js](https://wall-ants.ndda.fr/Checkjson.js) see **Odmdb - schema Checkjson**
**Additional properties that not exist in 2020-12/schema :**
@ -75,26 +71,7 @@ Items of an object are store in files into :  
## api pre-request
**Valid header**
A private request to pass must contain exposeHeaders from town conf.json
api.exposedHeaders :\["xdays", "xhash", "xalias", "xlang", "xtribe", "xapp", "xuuid" \]
By default for anonymous user:
```plaintext
{"headers":{
"xtrkversion":1,
"xtribe":"tribeid ex: smatchit",
"xapp":"websitename ex:presentation",
"xlang":"fr",
"xalias":"anonymous",
"xhash":"anonymous",
"xdays":0
}
}
```
**Valid header see Middlewares**
App use openpgp.js lib to sign xdays\_xalias with a privatekey and store it in xhash.
@ -102,22 +79,31 @@ App use openpgp.js lib to sign xdays\_xalias with a privatekey and store it in x
See Pagans models that contain authentification process
**api Return can be direct json in case of get without authenntification or an object data**
**api Return in 3 data structure:**
{status, ref,msg,data}:
A - data file from a classical get  [https://wall-ants.ndda.fr/Checkjson.js](https://smatchit.io/Checkjson.js)
B -  a json single answer {status, ref,msg,data}:
* status: http code return
* ref: model/route name reference where message come from
* msg: a message template key store into models/lg/name\_lg.json (where lg is 2 letters language)
* data: an object data use to render the value of the message key.
C - a json multi answer {status,multimsg:\[{ref,msg,data}\]}
         Each {ref,msg,data\] work the same way than B
To show feedback context message in a language lg => get /nationchains/models/{{ref}}\_{{lg}}.json
This contain a json {msg:"mustache template string to render with data"}  
## Accessrights:
An alias is just an identity, to access a tribe a person must exist with alias into /town/tribes/tribename/persons/itm/alias.json
An alias is just an identity, to access a tribe, a person must exist with an authenticated alias into /town/tribes/tribename/persons/itm/alias.json
A person has a property profils with a list of profilename, common profiles are : pagan (an identity)  / person (an identity with access right in a tribe) / druid (the administrator of a tribe) / major (administrator of a town/server)
A person has a property profils with a list of profilename, common profiles are : anonymous (no identity) / pagan (an identity)  / person (an identity with access right into a tribe) / druid (the administrator of a tribe) / major (administrator of a town/server)
Into a tribe you can have many other profil with specifics accessright on tribe's object.
Each object has an apxaccessrights that is a list of profil and CRUD access per object key .
## Add tribe's api:

View File

@ -6,52 +6,28 @@ const glob = require("glob");
const openpgp = require("openpgp");
/**
* @api{get}/istauthenticated
* @api {get} http://header/istauthenticated - isAuthenticated
* @apiGroup Middlewares
* @apiName isAUthenticated
* @apiDescription Check that exist in town/tmp/tokens/xalias_xdays_xhash.substr(20,200) if not, check the xhash signature with message xalias_xdays come from public key belonging to xalias. If check pass then store a xhash into /tmp/tokens.
* A process run each day to clean up all xhas tmp/tokens oldest than 24 hours.
* If authentify it returns header with xprofils store into a person objject -xtribes/person/alias
*
* @apiHeader {string} xalias anonymous or unique alias
* @apiHeader {string} xapp name of the webapp store in tribe/tribeid/www/xapp
* @apiHeader {string} xlang the 2 letter request langage (if does not exist then return en = english).
* @apiHeader {string} xtribe unique tribe name ere xapp exist
* @apiHeader {string} xdays a timestamp 0 or generate during the authentifyme process
* @apiHeader {string} xhash anonymous or signature of message: xalias_xdays created by alias private key during authentifyme process
* @apiHeader {array[]} xprofils list of string profil apply into xtribe for xapp
* @apiHeader {string} xuuid a unique number c reated the fisrt time a domain is visited
* @apiHeader {integer} xtrkversion a version number link to tracking system
*
* @apiErrorExample {json} Error-Response:
* HTTP/1/1 400 Not Found
* {
* status:400,
* ref:"middlewares"
* msg:"missingheaders",
* data: ["headermissing1"]
* }
*@apiErrorExample {json} Error-Response:
* HTTP/1/1 404 Not Found
* {
* status:404,
* ref:"middlewares"
* msg:"tribeiddoesnotexist",
* data: {xalias}
* }
*
* @apiHeaderExample {json} Header-Exemple:
* {
* xtribe:"apache",
* xalias:"toto",
* xhash:"",
* xdays:"123"
* xlang:"en",
* xapp:"popular"
* }
* @apiName isAuthenticated
* @apiDescription - valid if exist xalias_xdays_xhash.substr(20,200) in town/tmp/tokens/
* - if not,
* - valid if xhash signature sign xalias_xdays with alias's publickey.
* - if not valid => not allowed
* - If valid =>
* - store a xalias_xdays_xhash.substr (20,200) into /tmp/tokens with xprofils array from person.
* - update header.xprofils from this token
*
* apXtrib profils are anonymous, pagans, mayor (on a node server), druid (on a tribe like smatchit).
*
* pagan identity is independant of domain (tribe), by default profils are :['anonymous','pagans']. if this alias exist in a tribe domain as a person then his profils come from /tribes/{tribeId}/objects/person/itm/{alias}.json profils:['anonymous','pagans','person','seeker'] any profils allowed to act on tribe objects.
*
* Each profil have CRUD accessright on object managed in schema in apxaccessrights:{owner,profil:{"C":[],"R":[properties],"U":[properties],"D":[]}}, see Odmdb for details.
*
* A process run once each day to clean up all xhash tmp/tokens oldest than 24 hours.
*
**/
const isAuthenticated = async (req, res, next) => {
const withlog = true;
const withlog = false;
const currentday = dayjs().date();
fs.ensureDirSync(`${process.env.dirtown}/tmp/tokens`);
let menagedone = fs.existsSync(
@ -197,8 +173,7 @@ const isAuthenticated = async (req, res, next) => {
return res.status(resnotauth.status).send(resnotauth);
}
// authenticated then get person profils (person = pagan for a xtrib)
req.session.header.xprofils.push("pagans");
const person = `${process.env.dirtown}/tribes/${req.session.header.xtribe}/persons/itm/${req.session.header.xalias}.json`;
const person = `${process.env.dirtown}/tribes/${req.session.header.xtribe}/objects/persons/itm/${req.session.header.xalias}.json`;
if (withlog) {
console.log("Profils tribe/app management");
console.log("person", person);
@ -206,7 +181,11 @@ const isAuthenticated = async (req, res, next) => {
if (fs.existsSync(person)) {
const infoperson = fs.readJSONSync(person);
console.log(infoperson);
infoperson.profils.forEach((p) => req.session.header.xprofils.push(p));
infoperson.profils.forEach((p) => {
if (!req.session.header.xprofils.includes(p)) req.session.header.xprofils.push(p);
})
}else{
if (!req.session.header.xprofils.includes('pagans')) req.session.header.xprofils.push("pagans");
}
fs.outputJSONSync(tmpfs, req.session.header.xprofils);
} else {

View File

@ -12,6 +12,7 @@ Checkjson.schema.properties = {};
Checkjson.schema.properties.type = {};
Checkjson.schema.properties.type.string = (str) => typeof str === "string";
Checkjson.schema.properties.type.array = (val) => Array.isArray(val);
Checkjson.schema.properties.type.object = (val) => typeof val === 'object' && val !== null && !Array.isArray(val);
Checkjson.schema.properties.type.number = (n) => typeof n === "number";
Checkjson.schema.properties.type.boolean = (n) => typeof n === "boolean";
Checkjson.schema.properties.type.integer = (n) =>
@ -130,18 +131,25 @@ Checkjson.schema.validation = (schema) => {
}
if (
properties[p].type &&
typeof properties[p].type === "object" &&
Array.isArray(properties[p].type)
) {
properties[p].type.forEach((tp) => {
if (!Checkjson.schema.properties.type[tp])
typeof properties[p].type === "object"){
if (properties[p]['$ref']){
//This is manage by Odmdb.schema to load recursively complex schema
multimsg.push({
ref: "Checkjson",
msg: "schemaerrtypedoesnotexist",
data: { propertie: p, type: properties[p].type },
});
});
}
msg: "externalrefnotload",
data: { propertie: p, ref: properties[p]["$ref"]},
});
}
//case type=="object" with properties
if (properties[p].properties){
const checksub = Checkjson.schema.validation(properties[p])
if (checksub.status!=200){
multimsg = multimsg.concat(checksub.multimsg)
}
}
// if not $ref or no properties then any object is accepted
}
if (
properties[p].format &&
!Checkjson.schema.properties.format[properties[p].format]
@ -189,40 +197,38 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
console.log('---------')
console.log(data)
*/
if (withschemacheck) {
const validschema = Checkjson.schema.validation(schema);
if (validschema.status != 200) return validschema;
}
const multimsg = [];
const res = {
status: 200,
data: { itm: data },
};
if (schema.properties) {
const properties = schema.properties;
const propertiescheck=(properties,subdata)=>{
// properties ={prop1:{type,format},prop2:{type:object,...}}
// subdata={prop1,prop2}
// Return [] => no error, else 1 item per error {msg,ref:checkjson,data}
let multimsg=[]
Object.keys(properties).forEach((p) => {
//type is mandatory in a propertie
if (data[p]) {
if (subdata[p]) {
if (properties[p].properties){
//means it is a subobject
multimsg=multimsg.concat(propertiescheck(properties[p].properties,subdata[p]))
}
//type can be a list of string; number, array, boolean, object, null
const typlist =
properties[p].type && typeof properties[p].type === "string"
? [properties[p].type]
: properties[p].type;
let valid = false;
typlist.forEach((typ) => {
// at least one test have to be ok
if (Checkjson.schema.properties.type[typ](data[p])) valid = true;
// at least one test have to be valid
if (Checkjson.schema.properties.type[typ](subdata[p])) valid = true;
});
if (!valid)
multimsg.push({
ref: "Checkjson",
msg: "dataerrpropertie",
data: { key: p, value: data[p] },
data: { key: p, value: subdata[p] },
});
if (
properties[p].minLength &&
!Checkjson.schema.properties.minLength(
data[p],
subdata[p],
properties[p].minLength
)
) {
@ -231,7 +237,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
msg: "dataerrpropertie",
data: {
key: p,
value: data[p],
value: subdata[p],
minLength: properties[p].minLength,
},
});
@ -239,7 +245,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
if (
properties[p].maxLength &&
!Checkjson.schema.properties.maxLength(
data[p],
subdata[p],
properties[p].maxLength
)
) {
@ -248,7 +254,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
msg: "dataerrpropertie",
data: {
key: p,
value: data[p],
value: subdata[p],
maxLength: properties[p].maxLength,
},
});
@ -256,7 +262,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
if (
properties[p].multipleOf &&
!Checkjson.schema.properties.multipleOf(
data[p],
subdata[p],
properties[p].multipleOf
)
) {
@ -265,7 +271,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
msg: "dataerrpropertie",
data: {
key: p,
value: data[p],
value: subdata[p],
multipleOf: properties[p].multipleOf,
},
});
@ -279,7 +285,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
// test range
if (
!Checkjson.schema.properties.range(
data[p],
subdata[p],
properties[p].minimum,
properties[p].exclusiveMinimum,
properties[p].maximum,
@ -291,7 +297,7 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
msg: "dataerrpropertie",
data: {
key: p,
value: data[p],
value: subdata[p],
minimum: properties[p].minimum,
maximum: properties[p].maximum,
exclusiveMinimum: properties[p].exclusiveMinimum,
@ -302,12 +308,12 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
}
if (
properties[p].enum &&
!Checkjson.schema.properties.enum(data[p], properties[p].enum)
!Checkjson.schema.properties.enum(subdata[p], properties[p].enum)
) {
multimsg.push({
ref: "Checkjson",
msg: "dataerrpropertie",
data: { key: p, value: data[p], enumlst: properties[p].enum },
data: { key: p, value: subdata[p], enumlst: properties[p].enum },
});
}
if (properties[p].format) {
@ -316,12 +322,12 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
}
if (
properties[p].pattern &&
!Checkjson.schema.properties.pattern(data[p], properties[p].pattern)
!Checkjson.schema.properties.pattern(subdata[p], properties[p].pattern)
) {
multimsg.push({
ref: "Checkjson",
msg: "dataerrpropertie",
data: { key: p, value: data[p], pattern: properties[p].pattern },
data: { key: p, value: subdata[p], pattern: properties[p].pattern },
});
}
} else if (schema.required && schema.required.includes(p)) {
@ -332,18 +338,27 @@ Checkjson.schema.data = (schema, data, withschemacheck) => {
});
}
});
} //end properties
if (schema.apxid) {
res.data.apxid = data[schema.apxid];
return multimsg
};//end propertiescheck()
if (withschemacheck) {
const validschema = Checkjson.schema.validation(schema);
if (validschema.status != 200) return validschema;
}
if (multimsg.length > 0) {
let multi=propertiescheck(schema.properties,data)
const res = {};
if (multi.length > 0) {
res.status = 417;
res.multimsg = multimsg;
res.multimsg = multi;
} else {
res.status = 200;
res.ref = "Checkjson";
res.msg = "validcheck";
}
if (schema.apxid) {
res.data={apxid : data[schema.apxid],itm:data};
}
return res;
};
if (typeof module !== "undefined") module.exports = Checkjson;

View File

@ -113,6 +113,7 @@ Nations.updateobjectsfromfreshesttown = (dnstownlist, objectidx) => {
});
}
}
return {status:200,ref:"Nations",msg:"updated",data:{}};
};
Nations.synchronizeold = () => {
/*

View File

@ -11,29 +11,38 @@ const conf = require(`${process.env.dirtown}/conf.json`);
* volatile notification message from tribe activities to Pagans / person ()
*
*/
const Notifications = {};
Notifications.get = (alias, tribeId) => {
const notiffile = `${conf.dirtown}/tribes/${req.params.tribeId}/notifications/${req.params.alias}.json`;
const msg = fs.existsSync(notiffile) ? fs.readJSONSync(notiffile) : {};
return {
status: 200,
ref: "Notification",
msg: "Messagelist",
data: { notif: [{ tribeId, msg }] },
};
};
Notifications.sendsms = async (data, tribeId) => {
/**
* Never use need wallet in mailjet to test
* To set up with mailjet see https://dev.mailjet.com/sms/guides/send-sms-api/#authentication
*
* @param {string} data.To a phone number with international +3360101010101
* @param {string} data.Text text to send
*
* a conf.sms with {url:"smsurl", Token:"", From:""}
*
*
*/
/**
* Never use need wallet in mailjet to test
* To set up with mailjet see https://dev.mailjet.com/sms/guides/send-sms-api/#authentication
*
* @param {string} data.To a phone number with international +3360101010101
* @param {string} data.Text text to send
*
* a conf.sms with {url:"smsurl", Token:"", From:""}
*
*
*/
if (!conf.sms) {
return {
status: 412,
ref: "Notifications",
msg: "missingconf",
tribe: tribeId,
data: { tribe: tribeId },
};
}
let missingk = [][("To", "Text")].forEach((k) => {
@ -46,10 +55,10 @@ Notifications.sendsms = async (data, tribeId) => {
status: 428,
ref: "Notifications",
msg: "missingdata",
missingk: missingk,
data: { missingk: missingk },
};
}
let confsms= conf.sms;
let confsms = conf.sms;
if (
fs.existsSync(
`${process.env.dirtown}/tribes/itm/${req.session.header.xtribe}.json`
@ -60,19 +69,28 @@ Notifications.sendsms = async (data, tribeId) => {
);
if (conftrib.sms) confsms = conftrib.sms;
}
data.From=confsms.From
const sendsms= await axios.post(confsms.url,
{
data.From = confsms.From;
const sendsms = await axios.post(confsms.url, {
headers: {
Authorization: `Bearer ${confsms.MJ_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (sendsms.status==200){
return {status:200,ref:"Notifications",msg:"successfullsentsms"};
}else{
return {status:sendsms.status, ref:"Notifications",msg:"errsendsms",err:sendsms.data}
if (sendsms.status == 200) {
return {
status: 200,
ref: "Notifications",
msg: "successfullsentsms",
data: {},
};
} else {
return {
status: sendsms.status,
ref: "Notifications",
msg: "errsendsms",
data: { err: sendsms.data },
};
}
/* si tout se passe bien:
@ -100,36 +118,39 @@ Notifications.sendsms = async (data, tribeId) => {
Notifications.sendmail = async (data, tribe) => {
/**
* @param {string} data.From an email authorized by smtp used priority from header xtribe
* @param {string} data.To list of email separate by ,
* @param {string} [data.from] an email authorized by smtp used priority from header xtribe
* @param {string} data.to list of email separate by ,
* @param {string} data.subject
* @param {string} data.html
* @param {string} data.text
* @param {string} data.Cc list of email in copy
* @param {string} data.Bcc list of email in hidden copy
* @param {string} data.filelist an array of object {filename:"",pathfile:"",filetype:""} pathfile to attach as file name of type:filetype "filename" to this email
* @param {string} [data.Cc] list of email in copy
* @param {string} [data.Bcc] list of email in hidden copy
* @param {string} [data.filelist} an array of object {filename:"",pathfile:"",filetype:""} pathfile to attach as file name of type:filetype "filename" to this email
* example of filetype : "text/plain", "text/csv", image/gif", "application/json", "application/zip"
*
* @example data
* {"From":"wall-ants.ndda.fr",
* "To":"wall-ants.ndda.fr",
* {"to":"wall-ants.ndda.fr",
* "subject":"Test",
* "html":"<h1>test welcome</h1>",
* "text":"test welcome",
* "attachments":[{filename:"text.txt",pathfile:"/media/phil/textA.txt","contenttype":"text/plain"}]
* }
* @return {object} { status: 200, ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
* @return {object}
* { status: 200, ref:"pagans",msg:"aliasexist",data: { alias, publicKey } }
*
*
*/
if (!conf.smtp) {
if (!conf.smtp || !conf.emailcontact) {
return {
status: 412,
ref: "Notifications",
msg: "missingconf",
tribe: tribeId,
data: { tribe: tribe },
};
}
if (!data.from) {
data.from = conf.emailcontact;
}
let missingk = [];
["from", "to", "subject", "html", "text"].forEach((k) => {
if (!data[k]) {
@ -138,35 +159,59 @@ Notifications.sendmail = async (data, tribe) => {
});
if (missingk.lenght > 0) {
return {
status: 428,
status: 428,
ref: "Notifications",
msg: "missingdata",
missingk: missingk,
data: { missingk: missingk },
};
}
const conftribfile=`${process.env.dirtown}/tribes/itm/${tribe}.json`;
const confsmtp =(fs.existsSync(conftribfile))? fs.readJSONSync(conftribfile).smtp : conf.smtp;
let confsmtp = conf.smtp;
const conftribfile = `${process.env.dirtown}/tribes/itm/${tribe}.json`;
if (fs.existsSync(conftribfile)) {
const conftrib = fs.readJSONSync(conftribfile);
confsmtp = conftrib.smtp;
data.from = conftrib.emailcontact;
}
//const client = smtp.connect(confsmtp);
const transporter = await nodemailer.createTransport(confsmtp);
//@todo add attachments management
let missingfile=[]
if (missingfile.lenght > 0)
if (data.filelist) {
let missingfile = [];
data.filelist.forEach((fo) => {
if (fs.existsSync(fo.pathfile)){
}else{ missingfile.push(fo.pathfile);}
});
if (missingfile.lenght > 0)
return {
status: 428,
ref: "Notifications",
msg: "missingfile",
data: { missingfile: missingfile },
};
}
console.log("data:", data);
const res = await transporter.sendMail(data);
if (
res.accepted &&
data.to.split(",").reduce((acc, m) => acc && res.accepted.includes(m), true)
) {
data.accepted = res.accepted;
data.rejected = res.rejected;
return {
status: 428,
status: 200,
ref: "Notifications",
msg: "missingfile",
missingfile: missingfile,
msg: "successfullsentemail",
data,
};
try {
// Send the email
//const res = await client.sendMail(data)
const res = await transporter.sendMail(data)
//console.log('res envoie',res)
return { status: 200, ref: "Notifications", msg: "successfullsent", data };
} catch (err) {
//console.log('err envoie',err)
return { status: 502, ref: "Notifications", msg: "errsendmail", err: err };
} else if (res.accepted && res.rejected) {
data.accepted = res.accepted;
data.rejected = res.rejected;
return { status: 410, ref: "Notifications", msg: "errsendmail", data };
} else {
data.errmailer = res.err;
return { status: 417, ref: "Notifications", msg: "errsendmail", data };
}
};

View File

@ -5,6 +5,7 @@ const dayjs = require("dayjs");
const axios = require("axios");
const conf = require(`${process.env.dirtown}/conf.json`);
const Checkjson = require(`./Checkjson.js`);
const { promiseHooks } = require("v8");
/**
* This manage Objects for indexing, searching, checking and act to CRUD
@ -153,72 +154,100 @@ Odmdb.updateObject = (objectPathname, meta) => {};
* @return {status:200,data:{conf:"schemaconf",schema:"schemacontent"} }
*/
Odmdb.Schema = (objectPathname, validschema) => {
const getpath = (schemaPath) => {
if (schemaPath.slice(-5) != ".json") schemaPath += ".json";
if (schemaPath.substring(0, 4) == "http") {
// lance requete http pour recuperer le schema avec un await axios
} else {
if (schemaPath.substring(0, 9) == "adminapi/") {
schemaPath = `${conf.dirapi}/${schemaPath}`;
} else {
schemaPath = `${conf.dirtown}/tribes/${schemaPath}`;
}
if (!fs.existsSync(schemaPath)) {
return {};
} else {
return fs.readJsonSync(schemaPath);
}
}
};
const confschema = fs.readJsonSync(`${objectPathname}/conf.json`);
let schemaPath = confschema.schema;
const res = {
status: 200,
ref: "Odmdb",
msg: "getschema",
data: { conf: confschema },
};
if (schemaPath.slice(-5) != ".json") schemaPath += ".json";
if (schemaPath.substring(0, 4) == "http") {
// lance requete http pour recuperer le schema avec un await axios
} else {
if (schemaPath.substring(0, 9) == "adminapi/") {
schemaPath = `${conf.dirapi}/${schemaPath}`;
} else {
schemaPath = `${conf.dirtown}/tribes/${schemaPath}`;
}
if (!fs.existsSync(schemaPath)) {
return {
status: 404,
ref: "Odmdb",
msg: "schemanotfound",
data: { schemaPath, schema: {} },
};
}
res.data.schema = fs.readJsonSync(schemaPath);
if (!res.data.schema.apxid) {
return {
status: 406,
ref: "Odmdb",
msg: "missingprimarykey",
data: {},
};
}
if (res.data.schema.apxidx) {
//add apxidx to apxuniquekey in case not
if (!res.data.schema.apxuniquekey.includes(res.data.schema.apxid)) {
res.data.schema.apxuniquekey.push(res.data.schema.apxid);
res.data.schema = getpath(confschema.schema);
if (Object.keys(res.data.schema).length == 0) {
return {
status: 404,
ref: "Odmdb",
msg: "schemanotfound",
data: { schemaPath, schema: {} },
};
}
//looking for type:object with $ref to load and replace by ref content (ref must be adminapi/ or tribeid/)
//@todo only 1 level $ref if multi level need to rewrite with recursive call
Object.keys(res.data.schema.properties).forEach((p) => {
if (
res.data.schema.properties[p].type == "object" &&
res.data.schema.properties[p]["$ref"]
) {
const subschema = getpath(res.data.schema.properties[p]["$ref"]);
if (Object.keys(res.data.schema).length == 0) {
res.status = 404;
res.msg = "missingref";
res.data.missingref = res.data.schema.properties[p]["$ref"];
return res;
} else {
subschema.description += ` from external schema: ${res.data.schema.properties[p]["$ref"]}`;
res.data.schema.properties[p] = subschema;
}
res.data.schema.apxidx.forEach((idx) => {
if (
idx.objkey &&
!res.data.schema.apxuniquekey.includes(idx.keyval) &&
!idx.objkey.includes(res.data.schema.apxid)
) {
return {
status: 406,
ref: "Odmdb",
msg: "unconsistencyapxidx",
data: {
name: idx.name,
keyval: idx.keyval,
objkey: idx.objkey,
apxid: res.data.schema.apxid,
},
};
}
});
}
if (validschema || 1 == 1) {
// return {status:200, ref, msg} or {status!:200,multimsg:[{ref,msg;data}]}
const check = Checkjson.schema.validation(res.data.schema);
if (check.status != 200) {
res.multimsg = check.multimsg;
res.status = check.status;
});
if (!res.data.schema.apxid) {
return {
status: 406,
ref: "Odmdb",
msg: "missingprimarykey",
data: {},
};
}
if (res.data.schema.apxidx) {
//add apxidx to apxuniquekey in case not
if (!res.data.schema.apxuniquekey.includes(res.data.schema.apxid)) {
res.data.schema.apxuniquekey.push(res.data.schema.apxid);
}
res.data.schema.apxidx.forEach((idx) => {
if (
idx.objkey &&
!res.data.schema.apxuniquekey.includes(idx.keyval) &&
!idx.objkey.includes(res.data.schema.apxid)
) {
return {
status: 406,
ref: "Odmdb",
msg: "unconsistencyapxidx",
data: {
name: idx.name,
keyval: idx.keyval,
objkey: idx.objkey,
apxid: res.data.schema.apxid,
},
};
}
});
}
if (validschema || 1 == 1) {
// return {status:200, ref, msg} or {status!:200,multimsg:[{ref,msg;data}]}
const check = Checkjson.schema.validation(res.data.schema);
if (check.status != 200) {
res.multimsg = check.multimsg;
res.status = check.status;
}
}
return res;
@ -243,6 +272,32 @@ Odmdb.search = (objectPath, objectName, search) => {
if (schema.status != 200) return schema;
};
Odmdb.r =(objectPathname, apxid, role)=>{
const itmf=`${objectPathname}/itm/${apxid}.json`
if (!fs.existsSync(itmf)){
return {status:404,ref: "Odmdb",msg: "persondoesnotexist",data: {person:apxid}}
}
const getschema = Odmdb.Schema(objectPathname, true);
if (getschema.status != 200) return getschema;
const itm=fs.readJsonSync(itmf);
if (itm.owner && itm.owner == role.xalias) {
role.xprofils.push("owner");
}
const accessright = Odmdb.accessright(
getschema.data.schema.apxaccessrights,
role
);
if (!accessright.R) {
return {status:403, ref:"Odmdb",msg:"forbidden",data: {person:apxid}}
}
const data={}
accessright.R.forEach(p=>{
data[p]=itm[p]
})
return {status:200, ref:"Odmdb",msg:"found",data}
}
/**
* To get an array of item (itm) per primarykey with a list of field
* Object are store in objectPath/objectName/conf.json contain
@ -252,8 +307,12 @@ Odmdb.search = (objectPath, objectName, search) => {
* @role {xalias,xprofiles} allow to get accessright come from header
* @propertiesfilter (optionnal) key to return for each object (if undefined then return all)
* @Return {status:200; data:{uuid:{data filter by @propertiesfilter},uuid:"notfound"}}
*/
Odmdb.reads = (objectPathname, apxidlist, role, propertiesfilter) => {
ASUP doit être gerer au niveau des view des index
*/
Odmdb.ASUPreads = (objectPathname, apxidlist, role, propertiesfilter) => {
const res = { status: 200, data: {} };
const getschema = Odmdb.Schema(objectPathname, true);
if (getschema.status != 200) return getschema;
@ -313,6 +372,8 @@ Odmdb.reads = (objectPathname, apxidlist, role, propertiesfilter) => {
* example: {"C":[],"R":[properties list],"U":[properties ist],"D":[]}
*/
Odmdb.accessright = (apxaccessrights, role) => {
//console.log("apxaccessrights",apxaccessrights)
//console.log("role",role)
const accessright = {};
role.xprofils.forEach((p) => {
if (apxaccessrights[p]) {
@ -324,6 +385,7 @@ Odmdb.accessright = (apxaccessrights, role) => {
...new Set([...accessright[act], ...apxaccessrights[p][act]]),
];
}
//console.log(act,accessright[act])
});
}
});
@ -340,7 +402,7 @@ Odmdb.accessright = (apxaccessrights, role) => {
* */
Odmdb.cud = (objectPathname, crud, itm, role) => {
Odmdb.cud = (objectPathname, crud, itm, role,runindex=true) => {
const getschema = Odmdb.Schema(objectPathname, true);
if (getschema.status != 200) return getschema;
@ -352,14 +414,19 @@ Odmdb.cud = (objectPathname, crud, itm, role) => {
data: { missingkey: getschema.data.schema.apxid },
};
}
const pathindex=`${objectPathname}/idx/lst_${getschema.data.schema.apxid}.json`;
if (!fs.existsSync(pathindex)){
fs.outputJSONSync(pathindex,[])
fs.ensureDirSync(`${objectPathname}/itm/`)
fs.ensureDirSync(`${objectPathname}/idx/`)
const existid=fs.existsSync(`${objectPathname}/itm/${itm[getschema.data.schema.apxid]}.json`);
/*const pathindex = `${objectPathname}/idx/lst_${getschema.data.schema.apxid}.json`;
if (!fs.existsSync(pathindex)) {
fs.outputJSONSync(pathindex, []);
fs.ensureDirSync(`${objectPathname}/itm/`);
}
const existid = fs
.readJSONSync(pathindex)
.includes(itm[getschema.data.schema.apxid]);
*/
if (existid && crud == "C") {
return {
status: 406,
@ -391,9 +458,11 @@ Odmdb.cud = (objectPathname, crud, itm, role) => {
: {};
if (existid && itmold.owner && itmold.owner == role.xalias) {
role.xprofils.push("owner");
} else {
}
if (!existid && crud=="C" && !itm.owner) {
// set owner cause this is a Create
itm.owner = role.xalias;
role.xprofils.push("owner");
}
//get accessright {C:[],R:[],U:[],D:[]} if exist means authorize, if array contain properties (for R and U) right is only allowed on properties
const accessright = Odmdb.accessright(
@ -415,7 +484,7 @@ Odmdb.cud = (objectPathname, crud, itm, role) => {
}
//delete or save
if (crud == "D") {
itmold["dt_delete"] = dayjs();
itmold["dt_delete"] = dayjs().toISOString();
fs.outputJSONSync(
`${objectPathname}/delitm/${itmold[getschema.data.schema.apxid]}.json`,
itmold
@ -431,9 +500,9 @@ Odmdb.cud = (objectPathname, crud, itm, role) => {
accessright.U.forEach((p) => {
itmtostore[p] = itm[p];
});
itmtostore.dt_update = dayjs();
itmtostore.dt_update = dayjs().toISOString();
}
if (crud == "C") itmtostore.dt_create = dayjs();
if (crud == "C") itmtostore.dt_create = dayjs().toISOString();
// check consistency of datatostore
const chkdata = Checkjson.schema.data(
getschema.data.schema,
@ -443,31 +512,109 @@ Odmdb.cud = (objectPathname, crud, itm, role) => {
if (chkdata.status != 200) return chkdata;
if (!getschema.data.schema.apxuniquekey)
getschema.data.schema.apxuniquekey = [];
console.log(`${objectPathname}/itm/${chkdata.data.apxid}.json`);
console.log(chkdata.data.itm);
fs.outputJSONSync(
`${objectPathname}/itm/${chkdata.data.apxid}.json`,
chkdata.data.itm
);
}
console.log("getschema", getschema);
//update idx
Odmdb.idxfromitm(
objectPathname,
crud,
itm,
itmold,
[],
getschema.data.schema
);
getschema.data.conf.lastupdatedata = dayjs();
//console.log("getschema", getschema);
//rebuild index if requested
console.log("runidx",runindex)
console.log(objectPathname)
if (runindex) Odmdb.runidx(objectPathname,getschema.data.schema);
getschema.data.conf.lastupdatedata = dayjs().toISOString();
fs.outputJSONSync(`${objectPathname}/conf.json`, getschema.data.conf);
return {
status: 200,
ref: "Odmdb",
msg: "cudsuccessfull",
data: { itm: chkdata.data.itm },
data: {},
};
};
/**
* apxidx:[list of index file
* { name: string, // filename in /idx/name.json
* type: array (list of unique value found in keyval), example: [val1, val2, val3,....] eventualy filter
* view (only unique key and object with objkey eventually filter by filter ) example: {idalias:{itm}}
* distribution (=> {val of keyval:[apxid itm value]} with )
* keyval:string, // a propertie of type string or array
* objkeys:[] and array of properties if empty [] means all properties, if 1 element => an array of this properties
* filter : an eval function base on itm data (itm.key) that return true (return data item) or false (ignore item)
*
*/
Odmdb.runidx = (objectPathname, schema) => {
console.log(`idx for ${objectPathname}`);
if (!schema || !schema.apxid) {
const getschema = Odmdb.Schema(objectPathname, true);
if (getschema.status != 200) return getschema;
schema = getschema.data.schema;
}
const ventil = {};
schema.apxidx.forEach((id) => {
ventil[id.name] = id;
ventil[id.name].isunique = schema.apxuniquekey.includes(id.keyval);
ventil[id.name].nbobjkey = id.objkey ? id.objkey.length : 0;
ventil[id.name].keyvaltype = schema.properties[id.keyval].type;
ventil[id.name].filter = id.filter ? id.filter.replace(/;/g, "") : ""; // check integrity of string
ventil[id.name].data = ventil[id.name].type == "array" ? [] : {};
});
glob.sync(`${objectPathname}/itm/*.json`).forEach((i) => {
const itm = fs.readJSONSync(i);
Object.keys(ventil).forEach((n) => {
let keep = true;
if (ventil[n].filter != "") {
try {
keep = eval(ventil[n].filter);
} catch (err) {
keep = false;
}
}
if (keep && ventil[n].type == "array" && itm[ventil[n].keyval]) {
if (ventil[n].keyvaltype == "array") {
itm[ventil[n].keyval].forEach((v) => {
if (!ventil[n].data.includes(v)) ventil[n].data.push(v);
});
} else {
if (!ventil[n].data.includes(itm[ventil[n].keyval]))
ventil[n].data.push(itm[ventil[n].keyval]);
}
}
if (
keep &&
ventil[n].type == "view" &&
ventil[n].isunique &&
itm[ventil[n].keyval]
) {
if (ventil[n].nbobjkey == 0)
ventil[n].data[itm[ventil[n].keyval]] = itm;
if (ventil[n].nbobjkey == 1)
ventil[n].data[itm[ventil[n].keyval]] = itm[ventil[n].objkey[0]];
if (ventil[n].nbobjkey > 1) {
const objdata={}
Object.keys(itm).forEach(k=>{
if (ventil[n].objkey.includes(k)) objdata[k]=itm[k];
})
ventil[n].data[itm[ventil[n].keyval]]=objdata
}
}
if (keep && ventil[n].type == "distribution" && itm[ventil[n].keyval] ) {
const listval = (ventil[n].keyvaltype=="string")? [itm[ventil[n].keyval]] : itm[ventil[n].keyval];
// itm[ventil[n].keyval] is an array
listval.forEach(val=>{
if (!ventil[n].data[val]) ventil[n].data[val] = [];
ventil[n].data[val].push(itm[schema.apxid])
});
}
});
});
Object.keys(ventil).forEach((n)=>{
//console.log(`${objectPathname}/idx/${ventil[n].name}.json`)
fs.outputJSON(`${objectPathname}/idx/${ventil[n].name}.json`,ventil[n].data);
})
};
/**
* create/update idx from itm(s)
*
@ -490,7 +637,7 @@ Odmdb.cud = (objectPathname, crud, itm, role) => {
* Odmdb.idxfromitm('.../tribes/ndda/pagans',"I",{},{},[{ name:"publickey_alias",keyval:"publickey",objkey:["alias"]}], {pagans schema})
*
*/
Odmdb.idxfromitm = (objectPathname, crud, itm, itmold, idxs = [], schema) => {
Odmdb.ASUPidxfromitm = (objectPathname, crud, itm, itmold, idxs = [], schema) => {
console.log(`idxfromitem for ${objectPathname} action:${crud}`);
if (!schema || !schema.apxid) {
const getschema = Odmdb.Schema(objectPathname, true);
@ -601,8 +748,8 @@ Odmdb.idxfromitm = (objectPathname, crud, itm, itmold, idxs = [], schema) => {
if (crud != "I") {
//update lastupdatedata to inform something change
const confschema = fs.readJSONSync(`${objectPathname}/conf.json`);
confschema.lastupdatedata = dayjs();
fs.outputJSONSync(`${objectPathname}/conf.json`, getschema.data.conf);
confschema.lastupdatedata = dayjs().toISOString();
fs.outputJSONSync(`${objectPathname}/conf.json`, confschema);
}
return { status: 200, ref: "Odmdb", msg: "successreindex", data: {} };
};
@ -652,7 +799,7 @@ Odmdb.updatefromidxall = (objectname, idxname, data, lastupdate) => {
//check if it miss id in fresher update means conf.lastupdate will be now to indicate
Object.keys(localidx).forEach((id) => {
if (!data[id]) {
conflastupdate = dayjs();
conflastupdate = dayjs().toISOString();
}
});
// update the object files

View File

@ -3,13 +3,11 @@ const path = require("path");
const dayjs = require("dayjs");
const fs = require("fs-extra");
const axios = require("axios");
const Mustache = require('mustache');
const openpgp = require("openpgp");
const Notifications = require("../models/Notifications.js");
const Odmdb = require("../models/Odmdb.js");
/*if (fs.existsSync("../../nationchains/tribes/conf.json")) {
conf = require("../../nationchains/tribes/conf.json");
}*/
const conf = require(`${process.env.dirtown}/conf.json`);
/**
@ -37,6 +35,7 @@ Pagans.logout = (alias, tribe, xdays, xhash) => {
//max filename in ext4: 255 characters
tmpfs += `_${xhash.substring(150, 150 + tmpfs.length - 249)}.json`;
fs.remove(tmpfs);
console.log('logout token',tmpfs)
return { status: 200, ref: "Pagans", msg: "logout" };
};
@ -47,7 +46,7 @@ Pagans.logout = (alias, tribe, xdays, xhash) => {
*
**/
Pagans.getalias = (alias) => {
//bypass Odmdb cause all is public
//bypass Odmdb cause all is public save ressources
if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`)) {
return {
status: 200,
@ -67,106 +66,7 @@ Pagans.getalias = (alias) => {
}
};
/**
* @param {string} alias that exist
* @param {string} tribeId that exist with a person alias
* @return {object} { status: 200, ref:"pagans",msg:"personexist",data: { person } }
* { status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } }
*
**/
Pagans.getperson = (tribeid, alias, role) => {
const objlst = Odmdb.reads(
`${conf.dirtown}/tribes/${tribeid}/persons`,
[alias],
role
);
if (objlst.data[alias] == "notfound") {
return {
status: 404,
ref: "Pagans",
msg: "persondoesnotexist",
data: { alias, tribeid },
};
} else {
return {
status: 200,
ref: "Pagans",
msg: "personexist",
data: objlst.data[alias],
};
}
};
Pagans.create = (objpagan, role) => {
/**
* @param {object} objpagan {alias,publickey} a unique alias/publickey that identify an identity
* @param {array} role {xalias,xprofils} requester and list of profil
* @return {object} { status: 200, data: { alias, publicKey } }
* xhash was checked by isauthenticated
* @todo use Odmdb to add a pagan
*/
return Odmdb.cud(`${conf.dirapi}/nationchains/pagans`, "C", objpagan, role);
/*
let apxpagans = {};
if (fs.existsSync(`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`)) {
apxpagans = fs.readJsonSync(
`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`
);
}
if (apxpagans[objpagan.alias]) {
return { status: 409, ref: "Pagans", msg: "aliasexist", data: { alias } };
}
apxpagans[objpagan.alias] = { alias, publicKey };
fs.outputJsonSync(
`${conf.dirapi}/nationchains/pagans/idx/alias_all.json`,
apxpagans
);
fs.outputJsonSync(`${conf.dirapi}/nationchains/pagans/itm/${alias}.json`, {
alias,
publicKey,
});
return {
status: 200,
ref: "Pagans",
msg: "identitycreate",
data: { alias, publicKey },
};
*/
};
/**
* @Param {string} alias pagan unique id
* @Param {string} tribeid tribe id in this town
* @Param {object} persondata that respect /nationchains/schema/person.json + nationchains/tribe/tribeid/schema/personextented.json
* @return create or update a person /tribe/tribeid/person/alias.json
* todo later use Odmdb ans schema person to manage this
*/
Pagans.personupdate = (tribeid, alias, personupdate, role) => {
const personinit = {
alias: alias,
dt_create: dayjs(),
profils: ["person"],
};
const personfile = `${process.env.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`;
const persondata = fs.existsSync(personfile)
? fs.readJSONSync(personfile)
: personinit;
persondata.dt_update = dayjs();
Object.keys(personupdate).forEach((d) => {
persondata[d] = personupdate[d];
});
//const checkjson= Checkjson.schema.data = (fs.readJsonSync(`${conf.dirapi}/nationchains/schema/person.json`, person, false)
// if checkjson.status==200 create /update with odmdb to update index data
// see odmdb that did all and return standard message
fs.outputJSONSync(personfile, persondata, { space: 2 });
return {
status: 200,
ref: "Pagans",
msg: "successfullupdate",
data: { alias: alias, tribeid: tribeid },
};
};
/**
* Send email with alias's keys to email or person alias person.recovery.email
*
@ -183,38 +83,38 @@ Pagans.personupdate = (tribeid, alias, personupdate, role) => {
Pagans.sendmailkey = (
alias,
privatekey,
tribeid,
tribe,
passphrase,
publickey,
email
email,
lg
) => {
const person = { alias, privatekey, tribeid };
const person = { alias, privatekey, tribe };
console.log(
alias,
"-",
privatekey,
privatekey.substring(0,10),
"-",
tribeid,
tribe,
"-",
passphrase,
"-",
publickey,
publickey.substring(0,10),
"-",
email
);
if (!publickey || !email || !passphrase || !privatekey) {
const personfile = `${process.env.dirtown}/tribes/${tribeid}/person/itm/${alias}.json`;
const persondata = fs.existsSync(personfile)
? fs.readJsonSync(personfile)
: {};
if (persondata.length == 0) {
if (!publickey || !email || !privatekey) {
const personfile = `${process.env.dirtown}/tribes/${tribe}/objects/persons/itm/${alias}.json`;
if (!fs.existsSync(personfile)) {
return {
status: 404,
ref: "Pagans",
msg: "persondoesnotexist",
data: { alias, tribeid },
data: { alias, tribe },
};
}
const persondata= fs.readJsonSync(personfile);
person.email = persondata.recoveryauth.email;
person.publickey = persondata.recoveryauth.publickey;
person.privatekey = persondata.recoveryauth.privatekey;
@ -224,48 +124,30 @@ Pagans.sendmailkey = (
person.passphrase = passphrase;
person.publickey = publickey;
}
person.avecpassphrase=(person.passphrase!="")
console.log("person:", person);
const tplemail = require(`${conf.dirapi}/adminapi/template/createidentity_${lg}.js`)
//feedback.withemail = true;
//feedback.email = email;
//feedback.privatekey = privatekey;
//feedback.passphrase = passphrase;
const mailidentity = {
subjecttpl: "Information pour l'alias: {{alias}}",
htmltpl:
"<h1>Votre identité {{alias}} via {{tribeid}}</h1><p>Passphrase:</p></p><p>{{{passphrase}}</p><p>Cle public:</p><p>{{{publickey}}</p><p>Cle privée</p><p>{{{privatekey}}</p>",
texttpl:
"Votre identité {{alias}}\nPassphrase:\n{{{passphrase}}\nCle public:\n{{{publickey}}\nCle privée\n{{{privatekey}}",
filelist: [],
};
person.message
const maildata = {
To: person.email,
subject: Mustache.render(mailidentity.subject, person),
htmlpart: Mustache.render(mailidentity.htmltpl, person),
textpart: Mustache.render(mailidentity.texttpl, person),
filelist: [],
to: person.email,
subject: Mustache.render(tplemail.subject, person),
html: Mustache.render(tplemail.html, person),
text: Mustache.render(tplemail.text, person),
attachments: [
{
filename:`${person.alias}_publickey.txt`,
content: person.publickey,
contentType:"text/plain"
},
{
filename:`${person.alias}_privatekey.txt`,
content: person.privatekey,
contentType:"text/plain"
}
]
};
fs.outputFileSync(
`${conf.dirtown}/tmp/${person.alias}_privatekey.txt`,
person.privatekey,
"utf8"
);
maildata.filelist.push({
filename: "${person.alias}_privatekey.txt",
pathfile: `${conf.dirtown}/tmp/${person.alias}_privatekey.txt`,
});
fs.outputFileSync(
`${conf.dirtown}/tmp/${person.alias}_publickey.txt`,
person.publickey,
"utf8"
);
maildata.filelist.push({
filename: "${person.alias}_publickey.txt",
pathfile: `${conf.dirtown}/tmp/${person.alias}_publickey.txt`,
});
//fs.readJSONSync('${conf.dirapi}/api/')
return Notifications.sendmail(maildata, tribeid);
return Notifications.sendmail(maildata, tribe);
};
Pagans.authenticatedetachedSignature = async (
@ -306,15 +188,6 @@ Pagans.authenticatedetachedSignature = async (
}
};
/**
* todo recuperer tous les tokens et les distribuer à la town
* @param {string} alias
*/
Pagans.deletealias = (alias) => {
// check if alias is used in the blockchain
// if not then delete itm pagan alias => this means that alias is now available for someone else
};
Pagans.deleteperson = (alias, tribeId) => {};
Pagans.keyrecovery = (tribeid, email) => {
glob
.GlobSync(`${conf.dirtown}/tribes/${tribeId}/Person/*.json`)

View File

@ -2,5 +2,6 @@
"validcheck":"Your data are valid",
"typedoesnnotexistinschema":"This type in your propertie is not manage by Checkjson.js",
"dataerrpropertie":"Check your data that not fit your schema rules propertie",
"dataerrpropertiesrequired":"This propertie is required and not present in your data"
"dataerrpropertiesrequired":"This propertie is required and not present in your data",
"externalrefnotload":"You have in your schema a relative sub schema, you have to load it before"
}

View File

@ -1,14 +1,19 @@
{
"alreadyexist": "Un object {{objectname}} avec la clé {{key}} existe déjà avec {{val}}",
"doesnotexist": "L'object {{objectname}} avec la clé {{key}} ,'existe pas avec {{val}}",
"doesnotexist": "L'object {{objectname}} n'existe pas avec {{key}}:{{val}}",
"getschema": "Schema {{{conf.name}}}",
"schemanotfound": "Schema introuvable dans {{{schemaPath}}}",
"pathnamedoesnotexist": "Le repertoire n'existe pas {{{indexpath}}}",
"objectfiledoesnotexist": "Le fichier n'existe pas {{{objectpath}}}",
"cudsuccessfull": "Mise à jour effectuée avec succés",
"successfulcreatewithoutemail":"Créer sans envoi d'email",
"successfulcreatewitemail":"Créer vous allez recevoir un email",
"missingprimarykey": "Il manque une clé primaire apxid pour stocker et identifier les objects",
"unconsistencyapxidx": "L'index {{name}} doit contenir en objkey au moins {{apxid}} car keyval n'est pas unique",
"profilnotallow": "Vous n'avez pas le profil de {{profils}}, cette action n'est pas authorisée",
"successreindex": "Objet reindexé à partir des items, vos index sont à jour",
"indexexist":"L'indexe existe"
"indexexist":"L'indexe existe",
"typenotavailable":"Le type: {{type}} pour la propertie : {{propertie}} de l'object :{{objectPathname}} n'est pas pris en compte pour l'indexation",
"objectslist":"Liste des objects d'apxtrib et de {{tribe}}",
"errordelete":"Desolé impossible de supprimer ce compte"
}

View File

@ -1,13 +1,12 @@
{
"aliasexist": "Cet alias {{data.alias}} existe",
"emailerr": "Verifier votre email",
"aliasexist": "Cet alias {{alias}} existe",
"emailerr": "Verifier votre email {{email}}",
"aliasorprivkeytooshort": "Vérifiez votre alias et votre clé privée",
"aliasdoesnotexist": "Cet alias {{data.alias}} n'existe pas",
"personexist": "Cette personne {{data.alias}} existe pour {{data.tribeid}}",
"persondoesnotexist": "Cette personne {{data.alias}} n'existe pas pour {{data.tribeid}}",
"successfullcreate": "La création de cette identité {{data.alias}} a été un succès. {{#data.withemail}} Un email a été envoyé à {{data.email}}, si vous ne le recevez pas, veuillez télécharger vos clés avant de quitter cette page.{{/data.withemail}}",
"successfulcreatewithoutemail": "La creation de data.alias}} a été un succès. Aucun email ,'a été envoyé, verifier bien que vos clés sont bien sauvegardé de votre coté",
"successfulluppdate": "Votre alias en tant que Personne est maintenant mis à jour dans {{data.tribeid}}",
"aliasdoesnotexist": "Cet alias {{alias}} n'existe pas",
"personexist": "Cette personne {{alias}} existe pour {{tribeid}}",
"persondoesnotexist": "Cette personne {{alias}} n'existe pas pour {{tribeid}}",
"successfulcreate":"Votre identité {{alias}} a été créee à partir de vos clés.{{#emailsent}} Un email a été envoyé à {{email}}, si vous ne le recevez pas, veuillez télécharger vos clés avant de quitter cette page.{{/emailsent}} {{#emailerror}}Un problème lors de l'envoi sur {{email}} s'est produit. Veuillez télécharger vos clés avant de quitter cette page.{{/emailerror}}<br>{{#createperson}}Félicitation Votre compte est ouvert chez {{tribe}}. {{/createperson}} {{#errorperson}}Attention votre identité n'a pas été associée à {{tribe}}. Vous pourrez rejoindre {{tribe}} dans l'écran suivant. {{/errorperson}}",
"successfulluppdate": "Votre alias en tant que Personne est maintenant mis à jour dans {{tribeid}}",
"errcreate": "Desolé, un probléme inconnu empeche la creation",
"logout": "Votre token a été supprimé du server"
}

View File

@ -1,4 +1,5 @@
const express = require( 'express' );
const fs=require('fs-extra');
const conf = require(`${process.env.dirtown}/conf.json`);
// Classes
@ -9,32 +10,26 @@ const isAuthenticated = require( '../middlewares/isAuthenticated' );
const router = express.Router();
/*
Manage the social world
@Todo
Manage a new nation
Manage nation
A major create a nation with at least a town => nation:{name, towns:[]} contracts/nationname.js + contracts/townsname.js
Manage a new towns in a nation => update nation:[nationname:towns:[]} contracts/townname.js
*/
router.post( '/push', checkHeaders, ( req, res ) => {
// Get information from other apxtrib instance in req.body
// check req.body.hashnext => means this is a candidate to validate next block
//
// return it's own information back with the last call to Nationchains.synchronize()
res.send( { status: 200, payload: { moreinfo: fs.readFileSync( `${conf.tribes}/${conf.mayorId}/nationchains/nodes/${conf.rootURL}`, 'utf-8' ) } } )
/**
* @api {put} /nations/viewtown/:town - nationlist from a town major
* @apigroup Nation
* @apiName nationlist
* @apiDescription get list of nation from a town to help this instance to update network topology
* @apiParam {string} town fromwhich the data come from
* @apiSuccess {object} refreshnetworktopoly
* * HTTP/1.1 200 OK
* {status:200,ref:"Nations",msg:"updated",data:{}};
*
*/
router.put( '/', checkHeaders, isAuthenticated, ( req, res ) => {
const uptown = Nations.updatetown()
res.status(uptown.status).send(uptown)
} )
router.get('/synchro',checkHeaders, isAuthenticated,(req,res)=>{
// run a sync from a list of electedtown to update nationchains folder
console.log('TODO')
})
module.exports = router;

View File

@ -1,9 +1,6 @@
const express = require("express");
const fs = require("fs-extra");
const path = require("path");
// Classes
const Pagans = require("../models/Notifications.js");
const Notifications = require("../models/Notifications.js");
// Middlewares
const checkHeaders = require("../middlewares/checkHeaders");
@ -12,48 +9,22 @@ const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* Get form data and send notification to user by email, sms, alert
* @api{post}/messageanonymous
* @apiName Notification
* @apiDescription Send information as anonymous to tribe's druid
* @apiGroup apxtrib
* @api {get} /notifications/:alias/:tribeId
* @apiName notiflist
* @apiDescription Get list of notifications for an alias and a tribe
* @apiGroup Notification
*
* @apiUse apxHeader
* @apiParam {string} objectname Mandatory
* @apiParam {String} indexname Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname/idx/indexname indexname contains the ObjectName .*_ (before the first _)
*
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
{"status":404,"ref":"Odmdb","msg":"pathnamedoesnotexist","data":{indexpath}}
*
* @apiSuccess {object} indexfile content
* @apiParam {string} alias
* @apiParam {string} tribeId
* @apiSuccess {object} notif content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{indexname,content:{index file}}
* {status:200,ref:"Notification",msg:"Messagelist",data:{notif:[{tribeId,msg:{from(email or uuid or alias):[{dt,msg}]}}]}
*
*
**/
router.get("/alias/:alias", (req, res) => {
const getalias = Pagans.getalias(req.params.alias);
router.get("/:alias/:tribeId", (req, res) => {
const getnot = Notification.get(req.params.alias,req.params.tribeId);
res.status(getalias.status).send(getalias);
});
/**
* Remove serveur token
* @api {get} /pagans/logout
* @apiName Remove token
* @apiGroup Pagans
*
*/
router.get("/logout", checkHeaders, isAuthenticated, (req, res) => {
console.log(req.session.header);
const logout = Pagans.logout(
req.session.header.xalias,
req.session.header.xtribe,
req.session.header.xdays,
req.session.header.xhash
);
res.status(logout.status).json(logout);
});
module.exports=router;

View File

@ -9,13 +9,52 @@ const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* @api{get}/odmdb/idx/:objectname/:indexname - index Get
* @api {get} /odmdb/objects - objects Get
* @apiGroup Odmdb
* @apiName getIndex
* @apiDescription Get objects available for header.xtribe
*
* @apiSuccess {object} contain data.indexname
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"objectslist", "data":{indexname,content:{index file}}
*
*
*/
router.get("/objects", checkHeaders, isAuthenticated, (req, res) => {
const data = {
tribe: req.session.headers.xtribe,
apx: { conf: {}, objectnames: [] },
tribe: { conf: {}, objectnames: [] },
};
glob.sync(`${conf.dirapi}/adminapi/schema/*.json`).forEach((f) => {
const objectname = path.basename(f, ".json");
if (objectname == "conf") {
data.apx.conf = fs.readJSONSync(f);
} else {
data.apx.objectnames.push(objectnames);
}
});
glob
.sync(`${conf.dirtown}/tribes/${req.session.headers.xtribe}/schema/*.json`)
.forEach((f) => {
const objectname = path.basename(f, ".json");
if (objectname == "conf") {
data.apx.conf = fs.readJSONSync(f);
} else {
data.apx.objectnames.push(objectnames);
}
});
res.status(200).json({ status: 200, ref: "Odmdb", msg: "objectslist", data });
});
/**
* @api {get} /odmdb/idx/:tribe/:objectname/:indexname - index Get
* @apiGroup Odmdb
* @apiName getIndex
* @apiDescription Get index file for an object
*
* @apiParam {string} tribe if common adminapi or tribename
* @apiParam {string} objectname If in conf.nationObjects then object is into nationchains/ else in tribes/xtribe/objectname/idx/indexname indexname
* @apiParam {String} indexname name of index file in /idx/indexnamme.json
*
@ -32,39 +71,37 @@ const router = express.Router();
*
*
*/
router.get(
"/idx/:objectname/:indexname",
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("passe");
// indexname = objectname_key_value.json
let objectLocation = "../../nationchains/";
if (!conf.api.nationObjects.includes(req.params.objectname)) {
objectLocation += `tribes/${req.session.headers.xtribe}/`;
// check if accessright
}
const indexpath = `${objectLocation}/${req.params.objectname}/idx/${req.params.indexname}`;
if (fs.existsSync(indexpath)) {
res
.status(200)
.json({
ref: "Odmdb",
msg: "indexexist",
data: {
indexname: req.params.indexname,
content: fs.readJsonSync(indexpath),
},
});
} else {
res.status(404).json({
ref: "Odmdb",
msg: "pathnamedoesnotexist",
data: { indexpath },
});
}
router.get(
"/idx/:tribe/:objectname/:indexname",
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("passe");
// indexname = objectname_key_value.json
let objectLocation = "../../nationchains/";
if (!conf.api.nationObjects.includes(req.params.objectname)) {
objectLocation += `tribes/${req.session.headers.xtribe}/`;
// check if accessright
}
);
const indexpath = `${objectLocation}/${req.params.objectname}/idx/${req.params.indexname}`;
if (fs.existsSync(indexpath)) {
res.status(200).json({
ref: "Odmdb",
msg: "indexexist",
data: {
indexname: req.params.indexname,
content: fs.readJsonSync(indexpath),
},
});
} else {
res.status(404).json({
ref: "Odmdb",
msg: "pathnamedoesnotexist",
data: { indexpath },
});
}
}
);
/**
* @api {get} /odmdb/rebuildidx/:objectname - index refresh all
@ -75,7 +112,7 @@ const router = express.Router();
* @apiParam {string} objectname Mandatory
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* @apiSuccessExample {json} successreindex
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"successreindex", "data":{"indexlist":[]}}
*
@ -85,58 +122,56 @@ const router = express.Router();
{"status":404,"ref":"Odmdb","msg":"see nationchains/model/lg/Odmdb_xx.json","data":"object to render with msg"}
*
*/
router.get(
"/rebuildidx/:objectname",
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("reindex");
// check validity and accessright
const objectPathname = conf.api.nationObjects.includes(
req.params.objectname
)
? `${conf.dirapi}/nationchains/${req.params.objectname}`
: `${conf.dirtown}/tribes/${req.session.header.xtribe}/${req.params.objectname}`;
//console.log(objectPathname);
if (!fs.existsSync(objectPathname)) {
res.status(404).json({
status: 404,
ref: "Odmdb",
msg: "pathnamedoesnotexist",
data: { indexpath: objectPathname },
});
return false;
}
if (
conf.api.nationObjects.includes(req.params.objectname) &&
!req.session.header.xprofils.includes("mayor")
) {
res.status(403).json({
status: 403,
ref: "Odmdb",
msg: "profilnotallow",
data: { profils: "mayor" },
});
return false;
}
if (
!conf.api.nationObjects.includes(req.params.objectname) &&
!req.session.header.xprofils.includes("druid")
) {
res.status(403).json({
status: 403,
ref: "Odmdb",
msg: "profilnotallow",
data: { profils: "druid" },
});
return false;
}
const reindex = Odmdb.idxfromitm(objectPathname, "I", {}, {}, [], {});
res.status(reindex.status).json(reindex);
router.get(
"/rebuildidx/:objectname",
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("reindex");
// check validity and accessright
const objectPathname = conf.api.nationObjects.includes(
req.params.objectname
)
? `${conf.dirapi}/nationchains/${req.params.objectname}`
: `${conf.dirtown}/tribes/${req.session.header.xtribe}/${req.params.objectname}`;
//console.log(objectPathname);
if (!fs.existsSync(objectPathname)) {
res.status(404).json({
status: 404,
ref: "Odmdb",
msg: "pathnamedoesnotexist",
data: { indexpath: objectPathname },
});
return false;
}
);
if (
conf.api.nationObjects.includes(req.params.objectname) &&
!req.session.header.xprofils.includes("mayor")
) {
res.status(403).json({
status: 403,
ref: "Odmdb",
msg: "profilnotallow",
data: { profils: "mayor" },
});
return false;
}
if (
!conf.api.nationObjects.includes(req.params.objectname) &&
!req.session.header.xprofils.includes("druid")
) {
res.status(403).json({
status: 403,
ref: "Odmdb",
msg: "profilnotallow",
data: { profils: "druid" },
});
return false;
}
const reindex = Odmdb.idxfromitm(objectPathname, "I", {}, {}, [], {});
res.status(reindex.status).json(reindex);
}
);
/**
* @api {post} /odmdb/itm/:objectname - item Create
@ -144,22 +179,22 @@ const router = express.Router();
* @apiName postItm
* @apiPermission none
* @apiDescription Add an new item (data) into a collection of objectname items. Before Check data integrity with the relevant schema.
* Then create a new primarykey. For multilanguage return see nationchains/model/lg/Odmdb_xx.json.
*
* Then create a new primarykey. For multilanguage return see nationchains/model/lg/Odmdb_xx.json.
*
* @apiParam {string} objectname Place where to create new item, schema and version are available in /objectname/conf.json
*
*
* @apiBody {Object} data must pass Checkjson.js with schema
*
*
* @apiSuccess {json} data idxprimary Value of idxprimary into objectname collection
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"cudsuccessfull", "data":{"itm":{}}}
*
*
* @apiError {json} schemanotfound The objectname schema is not found
* @apiError {json} pathnamedoesnotexist The objectname does not exist for the tribe
* @apiError {json} missingprimarykey Body data must have primarykey to be created
* @apiError {json} unconsistencyapxidx some Body data get unique key that already exist
* @apiError {json} checkjsonfalse The body data are not consistent with the schema
* @apiError {json} unconsistencyapxidx some Body data get unique key that already exist
* @apiError {json} checkjsonfalse The body data are not consistent with the schema
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
* {"status":404,"ref":"Odmdb","msg":"see nationchains/model/lg/Odmdb_xx.json","data":"object to render with msg"}
@ -168,7 +203,7 @@ const router = express.Router();
router.post("/itm/:objectname", checkHeaders, isAuthenticated, (req, res) => {
// Create an item of an object with no specificities
// if specificities then create a route / model that import odmdb
res.json({})
res.json({});
});
router.get(
"/searchitems/:objectname/:question",
@ -246,14 +281,14 @@ router.get(
}
);
/**
* @api {get} https://wall-ants.ndda.fr/Checkjson.js - schema check data lib
* @api {get} https://wall-ants.ndda.fr/Checkjson.js - schema Checkjson.js
* @apiGroup Odmdb
* @apiName checkjsonjs
* @apiDescription Public js lib to import in a browser by :<br>
* ```<script src="wall-ants.ndda.fr/nationchains/contracts/Checkjson.js"></script>```
* to import in a node.js:<br>
* ```const Checkjson = require(`Checkjson.js`);```
*
*
* with functions:<br>
* <strong>Checkjson.schema.validation(schema)</strong> that return<br>
* - {status:200, ref:"Checkjson", msg:"validcheck"} => all rules are correct<br>
@ -262,14 +297,12 @@ router.get(
* <strong>Checkjson.schema.data(schema{json},data{json},withschemacheck{boolean})</strong> that return<br>
* - {status:200, ref:"Checkjson", msg:"validcheck"} => all data keys respect schema rules <br>
* - {status:417, multimsg:[{ref:"Checkjson",msg:"errorkey",data:{}}]}<br>
*
*
* To identify issues, get the language errorkey list with a get
* https://wall-ants.ndda.fr/nationchains/models/Checkjson_lg.json
*
* https://wall-ants.ndda.fr/nationchains/models/Checkjson_lg.json
*
*/
/**
* @api {get} https://wall-ants.ndda.fr/nationchains/schema/:objectname - schema Get public
* @apiGroup Odmdb
@ -331,43 +364,170 @@ router.get(
**/
/**
* @api {get} /odmdb/schema/:objectname - schema Get private
* @api {get} https://tribedns/:tribe/schema/:objectname.json - schema Get from tribe
* @apiGroup Odmdb
* @apiName getPrivateSchema
* @apiDescription Get a private (profil must have accessright R on object) to a Schema model
* @apiDescription Get a tribe schema or schema/lg/:objectname_xx.json this is served by nginx not express. tribedns is the domain name (ex:smatchit.io)
*
* @apiParam {String} objectname Mandatory
* @apiParam {string} tribe where schema is stored ex;smatchit
* @apiParam {String} objectname the json file name ex persons.json or for language /lg/persons_fr.json
*
* @apiError {object} ref objectmodel to get in the right language
* @apiError {object} ref objectname note found
* @apiErrorExample {json} Error-response:
* HTTP/1.1 404 Not Found
* {"status":404,"ref":"Odmdb","msg":"schemanotfound","data":{"fullpath"}}
*
* @apiSuccess {object} data contains schema requested
* @apiSuccessExample {json} Success-Response:
* <html>...</html>
* @apiSuccess {json} data contains schema requested
* @apiSuccessExample {json} Success-Response for : https://smatchit.io/smatchit/schema/persons.json
* HTTP/1.1 200 Success-response:
* {"status":200,"data":{schema}}
*/
router.get("schema/:objectname", checkHeaders, isAuthenticated, (req, res) => {
const fullpath = path.resolve(
`${__dirname}/tribes/${req.session.header.xworkon}/schema/${req.params.pathobjectname}.json`
);
if (fs.existsSync(fullpath)) {
res.status(200).json({ data: fs.readJsonSync(fullpath) });
} else {
res
.status(404)
.json({ status:404, msg: "schemanotfound", ref: "odmdb", data: { fullpath } });
* {{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "/smatchit/schema/sirets",
"title": "Siret is a legal french company",
"description": "A recruiter can active a jobad if a maxnumber is not reach for this siret. Maxnumber is set depending of an offer or can be set manualy",
"type": "object",
"properties": {
"siret": {
"title": "siret",
"description": "A unique string identifying a company ",
"type": "string",
"minLength": 14,
"pattern": "^[0-9]*$"
},
"owner": {
"title": "Owner of this siret",
"description": "For accessright purpose this is set by the alias that pay the first time a subscription",
"type": "string"
},
"dt_create": {
"type": "string",
"format": "date-time",
"default": "dayjs.now()"
},
"dt_update": {
"type": "string",
"format": "date-time"
},
"subscription": {
"title": "Offer subscribe",
"type": "array",
"items": {
"type": "object",
"properties": {
"offer": { "type": "string", "enum": ["A", "B", "C", "FREE"] },
"dt_payment": { "type": "string", "format": "date-time" }
}
}
},
"emailbilling":{
"type":"string",
"format":"email"
},
"namebilling":{
"type":"string"
},
"maxactivejobad": {
"title": "Number of active jobad at the same time",
"description": "Alloaw by subscription payment for a date inside the last dt_payment and offer",
"type": "integer"
},
"activejobad": {
"title": "Current number of active jobadd",
"type": "integer"
},
"frenchlocation": {
"title": "Location",
"description": "use franch gov refential to locaize",
"$ref": "nationchains/schema/frenchlocation"
},
"denomination": {
"title": "Company name",
"type": "string"
}
},
"required": ["siret"],
"additionalProperties": true,
"apxid": "siret",
"apxuniquekey": ["siret"],
"apxidx": [
{
"name": "lst_siret",
"keyval": "siret"
}
],
"apxaccessrights": {
"owner": {
"D": [],
"R": [
"siret",
"dt_create",
"dt_update",
"subscription",
"maxactivejobadd",
"activejobadd",
"frenchlocation",
"demomination"
],
"U": ["frenchlocation", "demomination"]
},
"druid": {
"C": [],
"D": [],
"R": [
"siret",
"dt_create",
"dt_update",
"subscription",
"maxactivejobadd",
"activejobadd",
"frenchlocation",
"demomination"
],
"U": [
"subscription",
"maxactivejobadd",
"activejobadd",
"frenchlocation",
"demomination"
]
},
"pagans": { "C": [] },
"adminrecruiter": {
"C": [],
"R": [
"siret",
"dt_create",
"dt_update",
"subscription",
"maxactivejobadd",
"activejobadd",
"frenchlocation",
"demomination"
],
"U": ["frenchlocation", "demomination"]
},
"recruiter": {
"R": [
"siret",
"dt_create",
"dt_update",
"subscription",
"maxactivejobadd",
"activejobadd",
"frenchlocation",
"demomination"
]
}
}
});
}}
*/
/**
* @api {put} /odmdb/schema/:objectname - schema Put
* @api {put} https://wall-ants.ndda.fr/odmdb/schema/:tribe/:objectname - schema Put
* @apiGroup Odmdb
* @apiName putSchema
* @apiDescription Replace a schema by another one need druid profil for a tribe
*
* @apiParam {String} objectname Mandatory
* @apiParam {String} objectname
*
* @apiBody {string} schemapath where to store schema .../schema
* @apiBody {string} objectpath where to store object ...objectname/idx/conf.json
@ -386,23 +546,27 @@ router.get("schema/:objectname", checkHeaders, isAuthenticated, (req, res) => {
*
*
*/
router.put("schema/:objectname", checkHeaders, isAuthenticated, (req, res) => {
const fullpath = path.resolve(
`${__dirname}/tribes/${req.session.header.xworkon}/schema/${req.params.pathobjectname}.json`
);
const set = Odmdb.setObject(
path.resolve(`${__dirname}/tribes/${req.session.header.xworkon}`)
);
router.put(
"schema/:tribe/:objectname",
checkHeaders,
isAuthenticated,
(req, res) => {
const fullpath = path.resolve(
`${__dirname}/tribes/${req.session.header.xworkon}/schema/${req.params.pathobjectname}.json`
);
const set = Odmdb.setObject(
path.resolve(`${__dirname}/tribes/${req.session.header.xworkon}`)
);
if (fs.existsSync(fullpath)) {
res.status(200).json({ data: fs.readJsonSync(fullpath) });
} else {
res
.status(404)
.json({ msg: "schemanotfound", ref: "odmdb", data: { fullpath } });
if (fs.existsSync(fullpath)) {
res.status(200).json({ data: fs.readJsonSync(fullpath) });
} else {
res
.status(404)
.json({ msg: "schemanotfound", ref: "odmdb", data: { fullpath } });
}
}
});
);
/**
* @api {get} https://wall-ants.ndda.fr/nationchains/models/:modelname_lg.json - translation notif Get public

View File

@ -1,14 +1,15 @@
const express = require("express");
const fs = require("fs-extra");
const path = require("path");
// Classes
const Pagans = require("../models/Pagans.js");
const Odmdb = require("../models/Odmdb.js");
// Middlewares
const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const conf = require(`${process.env.dirtown}/conf.json`);
const router = express.Router();
/**
* /api/models/Pagans.js
@ -44,8 +45,8 @@ router.get("/alias/:alias", (req, res) => {
* @api {get} /pagans/logout - pagan Logout
* @apiName Removetoken
* @apiGroup Pagans
* @apiDescription Remove token
*
* @apiDescription Remove token
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
@ -101,6 +102,12 @@ router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
* - xhash is well signed from private key linked to the publickey of alias
* - check that alias does not already exist (if yes then verifiedsigne would be false)
* Need to wait next block chain to be sure that alias is register in the blokchain
* @apiBody {string} alias available (that does not already exist check get /api/alias/:alias that must return 404).
* @apiBody {string} publickey
* @apiBody {string} [email] if specified then an email is sent to it with public and privatekey
* @apiBody {string} [privatekey]
* @apiBody {string} [passphrase] if not specidied => passphrase=""
* @apiBody {string} [trustedtribe] the tribename if not specified then the process will only create a pagan identity, else an item person is create for trustedtribe (that must exist with profil 'person'). To create a person with an existing pagan identity use put /api/person/:alias after authenticated you (headers). In case a person is created then we use all valid other apiBody respecting rules https://smatchit.io/api/odmdb/schema/persons.json
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
@ -113,42 +120,64 @@ router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
* {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{indexname,content:{index file}}
*
*/
router.post("/", checkHeaders, isAuthenticated, (req, res) => {
//console.log("pass ici", req.body);
const objpagan = { alias: req.body.alias, publickey: req.body.publickey };
const newpagan = Pagans.create(objpagan, {
router.post("/", checkHeaders, isAuthenticated, async (req, res) => {
console.log("pass ici", req.body);
const role = {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
});
};
const emailregex =
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!(req.body.trustedtribe && req.body.email && emailregex.test(req.body.email) )) {
res.status(400).json({status:400,ref:"Pagans",msg:"emailerr", data:{email:req.body.email}})
return
}
const objpagan = { alias: req.body.alias, publickey: req.body.publickey };
const newpagan = Odmdb.cud(`${conf.dirapi}/nationchains/pagans`, "C", objpagan, role);
const createprocess={status:200, ref:"Pagans", msg:"successfulcreate",data:{alias:req.body.alias}};
if (newpagan.status == 200) {
if (req.body.email) {
const emailsent = Pagans.sendmailkey(
const emailsent = await Pagans.sendmailkey(
req.body.alias,
req.body.privatekey,
req.session.header.xtribe,
req.body.passphrase,
req.body.publickey,
req.body.email
req.body.email,
req.session.header.xlang
);
createprocess.data.emailsent = (emailsent.status == 200);
createprocess.data.email=req.body.email
createprocess.data.tribe=req.session.header.xtribe;
if (emailsent.status!=200) {
console.log("err emailsent: ",emailsent)
createprocess.data.emailerror = emailsent.data.err;
}
}
if (req.body.trustedtribe) {
const personup = Pagans.personupdate(
req.body.alias,
req.body.trustedtribe,
{
recoveryauth: {
email: req.body.email,
privatekey: req.body.privatekey,
publickey: req.body.publickey,
passphrase: req.body.passphrase,
},
}
);
if (personup.status !== 200)
console.log("Warning no recovery registration", personup);
}
if (emailsent && emailsent.status != 200) {
newpagan.msg = "successfulcreatewithoutemail";
const persondata = {
alias: req.body.alias,
owner: req.body.alias,
profils: ["pagans", "persons"],
recoveryauth: {
email: req.body.email,
privatekey: req.body.privatekey,
publickey: req.body.publickey,
passphrase: req.body.passphrase,
},
};
const personup = Odmdb.cud(`${conf.dirtown}/tribes/${req.body.trustedtribe}/objects/persons`, "C", persondata, {xprofils:["pagan"],xalias:req.body.alias});
console.log('personup',personup)
if (personup.status==200){
createprocess.data.createperson=true;
}else{
createprocess.data.createperson=false;
createprocess.data.errorperson=true;
createprocess.data.errpersonup=personup.data;
console.log("Warning pagan created but person not created and no recovery registration", personup);
}
res.status(createprocess.status).json(createprocess);
}else{
res.status(newpagan.status).json(newpagan);
}
} else {
@ -161,31 +190,45 @@ router.post("/", checkHeaders, isAuthenticated, (req, res) => {
* @apiName deletepagan
* @apiGroup Pagans
* @apiDescription
* Delete an alias and his publickey
* Delete an alias and his publickey, this mean that publickey disapear as well as alias. All tribe will be inform and will delete person of this alias if they have. This alias will be availlable after 1 year.
* */
router.delete("/alias/:alias", checkHeaders, isAuthenticated, (req, res) => {
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
const result = Pagans.deletealias(req.params.id, req.session.header);
res.status(result.status).send(result.data);
res.status(result.status).send(result);
});
/**
* @api {delete} /pagans/person/:alias - person Delete
* @apiName deleteperson
* @apiGroup Pagans
* @apiDescription
* Unsubscribe a person to a tribe => remove a person item and all data link to this alias
* */
router.delete("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
const result = Pagans.deleteperson(req.params.id, req.session.header);
res.status(result.status).send(result.data);
const personpath=`${conf.dirtown}/tribes/${req.session.header.xtribe}/objects/persons`;
const role = {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
};
req.session.header.role
const delperson = Odmdb.cud(personpath,"D",{alias:req.params.alias},role,true);
console.log(`DELETE person ${personpath}/${req.params.alias}.json `);
console.log(delperson)
res.status(delperson.status).json(delperson);
});
/**
* @api {get} /pagans/person:alias - person Get
* @api {get} /pagans/person/:alias - person Get
* @apiName getpersondata
* @apiDescription Get person information from his alias for a xtribe (data and profils per apps)
* @apiDescription Get person information from his alias for a xtribe (data and profils per apps)
* @apiGroup Pagans
*
* @apiParam {string} alias
*
*
* @apiSuccess (200) personExist
* @apiSuccessExample {json}
* {status:200, ref:"pagans",msg:"personexist",data: { person } }
*
*
* @apiError (404) Notfound
* @apiErrorExample {json}
* {status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } }
@ -195,57 +238,32 @@ router.delete("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
* else need accessright to on person set at R
* */
router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
const getperson = Pagans.getperson(
req.session.header.xtribe,
req.params.alias,
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
);
const getperson=Odmdb.r( `${conf.dirtown}/tribes/${req.session.header.xtribe}/objects/persons`,req.params.alias,{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias })
res.status(getperson.status).send(getperson);
});
/**
* @api {post} /pagans/person - person Post
* @apiName addperson
* @apiGroup Pagans
* @apiDescription
* add a person = alias + tribe with specific accessright and specific schema link to tribe
*
*
*
* @todo add tribe/schema/person.json
*/
router.post("/person", checkHeaders, isAuthenticated, (req, res) => {
//console.log(req.body);
const persoad = Pagans.personcreate(
req.session.header.xtribe,
req.body.alias,
req.body,
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
);
res.status(persoad.status).json(persoad);
});
/**
* @api {put} /pagans/person - person Put
* @apiName updateperson
* @apiGroup Pagans
* @apiDescription
* update a person = alias + tribe with specific accessright and specific schema link to tribe
* @todo add tribe/schema/person.json
* @apiDescription add or update a person = alias in a tribe. alias authenticated must have a profil with accessright into schema person.
* @apiHeader {string} xalias
* @apiParam {object} in line with schema in https://smatchit.io/api/odmdb/schema/persons
*
*/
router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
//console.log(req.body);
const persoup = Pagans.personupdate(
req.session.header.xtribe,
req.body.alias,
req.body,
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
);
res.status(persoup.status).json(persoup);
const pathobj=`${conf.dirtown}/tribes/${req.session.header.xtribe}/objects/persons`;
const action = (fs.existsSync(`${pathobj}/itm/${req.body.alias}.json`))? "U":"C";
//set req.body to be in line with schema
if (!req.body.profils){
req.body.profils=["anonymous","pagans","persons"]
}
const personup = Odmdb.cud(pathobj, action, req.body, {xprofils:req.session.header.xprofils, xalias:req.session.header.xalias});
console.log('personup',personup)
res.status(personup.status).json(personup);
});
/**
* @api {get} /pagans/keyrecovery/tribe/email - recovery key by email
* @apiName recoveryKey

View File

@ -8,161 +8,25 @@ const Notifications = require("../models/Notifications.js");
const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/*
*/
router.get("/changeowner/:alias",checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {get} /towns/ownershipr/:alias
* @apiName Change owner of a town mayorId
* @apiGroup Pagans
/**
* @api {get} /towns/ownershipr/:alias - town owner change
* @apiName changeowner
* @apiGroup Towns
* @apiDescription Change owner (major role) of a town (server) after a first install or just to resale it. Only the current major can run this.
* @param {string} alias an alias that will become owner of a town
* @apiSuccess (200) {object} {ref:"towns",msg:"ownerchangesuccess",data: { alias } }
* @apiError (404) {object} {ref:"towns",msg:"aliasnotallow",data: { alias} }
* @apiSuccess (object) ownerchangesuccess
* @apiSuccessExample {json}
* HTTP/1.1 200 OK
* {status:200, ref:"towns",msg:"ownerchangesuccess",data: { alias } }
* @apiError {object} aliasnotallow
* @apiErrorExample {json}
* HTTP/1.1 403 Forbidden
* {status:403,ref:"towns",msg:"aliasnotallow",data: { alias} }
*
**/
router.get("/changeowner/:alias",checkHeaders, isAuthenticated, (req, res) => {
res.send(Towns.changeowner(req.params.alias, req.session.header.xalias));
});
//=======================================================================================
router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {get} /pagans/person:alias
* @apiName Is register check xalias and xhash
* @apiGroup Pagans
* @apiUse apxHeader
* @param {string} alias that exist
* @param {string} tribeId that exist with a person alias
* @apiSuccess (200) {ref:"pagans",msg:"personexist",data: { person } }
* @apiError (404) {ref:"pagans",msg:"persondoesnotexist",data: { person } }
*
* @todo check accessright for req.session.header.xalias to see if jhe can get person data
* if req.param.alias == req.session.header.xalias => Owner
* else need accessright to on person set at R
* */
res.send(Pagans.getperson(req.params.alias, req.session.header.xtribe));
});
router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {get} /pagans/isauth
* @apiName Is register check xalias and xhash
* @apiGroup Pagans
* @apiUse apxHeader
*
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
* @apiError (401) {object} alias anonymous (not authenticated)
* @apiError (404) {string} tribe does not exist
*
* @apiSuccess (200) {object} data contains indexfile requested
*
*/
res.send({
status: 200,
ref: "headers",
msg: "authenticated",
data: {
xalias: req.session.header.xalias,
},
});
});
router.post("/", checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {post} /pagans
* @apiName Is register check xalias and xhash
* @apiGroup Pagans
* @apiUse apxHeader
*
* Create a pagan account from alias, publickey, if trusted recovery =>
* Create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}
* Middleware isAuthenticated check that:
* - xhash is well signed from private key linked to the publickey of alias
* - check that alias does not already exist (if yes then verifiedsigne would be false)
* Need to wait next block chain to be sure that alias is register in the blokchain
*/
console.log("pass ici", req.body);
const feedback = { alias: req.body.alias, publickey: req.body.publickey };
const newpagan = Pagans.create(req.body.alias, req.body.publickey);
if (newpagan.status == 200) {
if (req.body.email) {
feedback.withemail = true;
feedback.email = req.body.email;
feedback.privatekey = req.body.privatekey;
feedback.passphrase = req.body.passphrase;
Notifications.send({
type: "email",
from: "",
dest: [req.body.email],
tpl: "registeremail",
tribe: req.session.header.xtribe,
data: feedback,
});
}
if (req.body.trustedtribe) {
if (req.app.locals.tribeids.includes(req.body.trustedtribe)) {
delete feedback.withemail;
const persondata = { recovery: feedback };
res.send(
Pagans.personupdate(req.body.alias, req.body.trustedtribe, persondata)
);
} else {
res.send({
status: 404,
ref: "Pagans",
msg: "tribedoesnotexist",
data: { tribe: req.body.trustedtribe },
});
}
} else {
newpagan.data = feedback;
res.send(newpagan);
}
} else {
//error to create pagan
res.send(newpagan);
}
});
router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {put} /pagans/person
* @apiName Is register check xalias and xhash
* @apiGroup Pagans
* @apiUse apxHeader
*
* add/update a person = alias + tribe with specific accessright and specific schema link to tribe
* @todo add tribe/schema/person.json
*/
console.log(req.body);
res.send(
Pagans.personupdate(req.body.alias, req.session.header.xtribe, req.body)
);
});
router.delete("/:alias", checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {delete} /pagans/:alias
* @apiName Is register check xalias and xhash
* @apiGroup Pagans
* @apiUse apxHeader
* */
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
const result = Pagans.delete(req.params.id, req.session.header);
res.status(result.status).send(result.data);
});
router.get("/keyrecovery/:tribeid/:email", checkHeaders, (req, res) => {
/**
* @api {get} /pagans/keyrecovery/tribe/email
* @apiName apxtrib
* @apiGroup Pagans
*
*
*
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
* @apiError (401) {object} alias anonymous (not authenticated)
* @apiError (404) {string} tribe does not exist
*
* @apiSuccess (200) {object} data contains indexfile requested
*
*/
res.send(Pagans.keyrecovery(req.params.tribeId, req.params.email));
});
module.exports = router;

View File

@ -1,6 +1,7 @@
const express = require( 'express' );
const fs = require( 'fs-extra' );
const path = require( 'path' );
const glob = require('glob');
const conf = require(`${process.env.dirtown}/conf.json`);
// Classes
@ -10,25 +11,24 @@ const checkHeaders = require( '../middlewares/checkHeaders' );
const isAuthenticated = require( '../middlewares/isAuthenticated' );
const router = express.Router();
/**
* @api {get} /tribes/www/:tribeId - tribe list
* @apiName getlisttrib
* @apiDescription Get list of www object (space web)
* @apiGroup Tribes
*
* @apiParam {String} tribeId it identify an existing tribe*
* @apiSuccess (object) listwww contains folder name in www for tribeId
* @apiSuccessExample {json} listwww
* HTTP/1.1 200 OK
* {status:200,ref:"Tribes",msg:"listwww",data:{listwww}}
*/
router.get('www', checkHeaders,isAuthenticated,(req,res)=>{
/**
* @api {get} /tribes/www/:tribeId
* @apiName Get list of www object (space web)
* @apiGroup Tribes
*
* @apiUse apxHeader
*
* @apiParam {String} tribeId Mandatory it identify an existing tribe
* @apiParam {String} Check if Person has access as Read to object www
* @apiError (404) {string} status the file does not exist
* @apiError (404) {string} ref objectmodel to get in the right language
* @apiError (404) {string} msg key to get template from objectmodel
* @apiError (404) {object} data use to render lg/objectmodel_lg.json
*
* @apiSuccess (200) {object} data contains indexfile requested
*/
res.status(200).json({data:{}})
let listwww=[]
glob.sync(`${conf.dirtown}/tribes/${req.params.tribeId}/www/*`).forEach(d=>{
listwww.push(d.split("/").pop())
})
res.status(200).json({status:200,ref:"Tribes",msg:"listwww",data:{listwww}})
})
//router.post('www/') to create a webspace

View File

@ -8,39 +8,12 @@ const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* To manage an nginx conf
*
*/
router.get("/tribes/:tribeId", checkHeaders, isAuthenticated, (req, res) => {
/**
* @api {get} /www/tribes/:tribeId
* @apiName Get list of application Name
* @apiGroup Www
*
* @apiUse apxHeader
*
* @apiParam {String} tribeId Mandatory that have to exist in current town and
*
* @apiError (404) {string} status the folder does not exist
* @apiError (404) {string} ref objectmodel to get in the right language
* @apiError (404) {string} msg key to get template from objectmodel
* @apiError (404) {object} data use to www's model: 'Www' } );render lg/objectmodel_lg.json
*
* @apiSuccess (200) {object} data contains liste of www conf of a tribe
*
*/
// GET api/wwws/conf/:tribeId/:website
// if profils accessright return the nginx conf in ${conf.dirtown}/tribes/${req.param.tribeId}/www/nginx_${req.params.tribeId}_${req.params.website}.conf
router.get("/conf/:tribeId/:website", checkHeaders, isAuthenticated, (req, res) => {
res.send(Www.configlist(req.params.tribeId));
});
router.post("/:webappname", checkHeaders, isAuthenticated, (req, res) => {
/**
* Create a space web /tribes/www/webappname
*
*
* */
router.post("/conf/:tribeId/:website", checkHeaders, isAuthenticated, (req, res) => {
res.send(Wwws.create(req.params.tribeId));
});
module.exports = router;

View File

@ -1,58 +0,0 @@
const express = require("express");
const fs = require("fs-extra");
const path = require("path");
// Classes
const Pagans = require("../models/Notifications.js");
// Middlewares
const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* Get form data and send notification to user by email, sms, alert
* @api{post}/messageanonymous
* @apiName Notification
* @apiDescription Send information as anonymous to tribe's druid
* @apiGroup apxtrib
*
* @apiUse apxHeader
* @apiParam {string} objectname Mandatory
* @apiParam {String} indexname Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname/idx/indexname indexname contains the ObjectName .*_ (before the first _)
*
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
{"status":404,"ref":"Odmdb","msg":"pathnamedoesnotexist","data":{indexpath}}
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{indexname,content:{index file}}
*
*
**/
router.get("/alias/:alias", (req, res) => {
const getalias = Pagans.getalias(req.params.alias);
res.status(getalias.status).send(getalias);
});
/**
* Remove serveur token
* @api {get} /pagans/logout
* @apiName Remove token
* @apiGroup Pagans
*
*/
router.get("/logout", checkHeaders, isAuthenticated, (req, res) => {
console.log(req.session.header);
const logout = Pagans.logout(
req.session.header.xalias,
req.session.header.xtribe,
req.session.header.xdays,
req.session.header.xhash
);
res.status(logout.status).json(logout);
});

View File

@ -1,437 +0,0 @@
const express = require("express");
const glob = require("glob");
const fs = require("fs-extra");
const path = require("path");
const conf = require(`${process.env.dirtown}/conf.json`);
const Odmdb = require("../models/Odmdb.js");
// Middlewares
const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* @api{get}/odmdb/idx/:objectname/:indexname - index Get
* @apiGroup Odmdb
* @apiName getIndex
* @apiDescription Get index file for an object
*
* @apiParam {string} objectname If in conf.nationObjects then object is into nationchains/ else in tribes/xtribe/objectname/idx/indexname indexname
* @apiParam {String} indexname name of index file in /idx/indexnamme.json
*
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
{"status":404,"ref":"Odmdb","msg":"pathnamedoesnotexist","data":{indexpath}}
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{indexname,content:{index file}}
*
*
*/
router.get(
"/idx/:objectname/:indexname",
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("passe");
// indexname = objectname_key_value.json
let objectLocation = "../../nationchains/";
if (!conf.api.nationObjects.includes(req.params.objectname)) {
objectLocation += `tribes/${req.session.headers.xtribe}/`;
// check if accessright
}
const indexpath = `${objectLocation}/${req.params.objectname}/idx/${req.params.indexname}`;
if (fs.existsSync(indexpath)) {
res
.status(200)
.json({
ref: "Odmdb",
msg: "indexexist",
data: {
indexname: req.params.indexname,
content: fs.readJsonSync(indexpath),
},
});
} else {
res.status(404).json({
ref: "Odmdb",
msg: "pathnamedoesnotexist",
data: { indexpath },
});
}
}
);
/**
* @api {get} /odmdb/rebuildidx/:objectname - index refresh all
* @apiGroup Odmdb
* @apiName refreshAllIndex
* @apiDescription Rebuild all index for an object, this can be usefull in case crash or any data conflict.
*
* @apiParam {string} objectname Mandatory
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"successreindex", "data":{"indexlist":[]}}
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
{"status":404,"ref":"Odmdb","msg":"see nationchains/model/lg/Odmdb_xx.json","data":"object to render with msg"}
*
*/
router.get(
"/rebuildidx/:objectname",
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("reindex");
// check validity and accessright
const objectPathname = conf.api.nationObjects.includes(
req.params.objectname
)
? `${conf.dirapi}/nationchains/${req.params.objectname}`
: `${conf.dirtown}/tribes/${req.session.header.xtribe}/${req.params.objectname}`;
//console.log(objectPathname);
if (!fs.existsSync(objectPathname)) {
res.status(404).json({
status: 404,
ref: "Odmdb",
msg: "pathnamedoesnotexist",
data: { indexpath: objectPathname },
});
return false;
}
if (
conf.api.nationObjects.includes(req.params.objectname) &&
!req.session.header.xprofils.includes("mayor")
) {
res.status(403).json({
status: 403,
ref: "Odmdb",
msg: "profilnotallow",
data: { profils: "mayor" },
});
return false;
}
if (
!conf.api.nationObjects.includes(req.params.objectname) &&
!req.session.header.xprofils.includes("druid")
) {
res.status(403).json({
status: 403,
ref: "Odmdb",
msg: "profilnotallow",
data: { profils: "druid" },
});
return false;
}
const reindex = Odmdb.idxfromitm(objectPathname, "I", {}, {}, [], {});
res.status(reindex.status).json(reindex);
}
);
/**
* @api {post} /odmdb/itm/:objectname - item Create
* @apiGroup Odmdb
* @apiName postItm
* @apiPermission none
* @apiDescription Add an new item (data) into a collection of objectname items. Before Check data integrity with the relevant schema.
* Then create a new primarykey. For multilanguage return see nationchains/model/lg/Odmdb_xx.json.
*
* @apiParam {string} objectname Place where to create new item, schema and version are available in /objectname/conf.json
*
* @apiBody {Object} data must pass Checkjson.js with schema
*
* @apiSuccess {json} data idxprimary Value of idxprimary into objectname collection
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"cudsuccessfull", "data":{"itm":{}}}
*
* @apiError {json} schemanotfound The objectname schema is not found
* @apiError {json} pathnamedoesnotexist The objectname does not exist for the tribe
* @apiError {json} missingprimarykey Body data must have primarykey to be created
* @apiError {json} unconsistencyapxidx some Body data get unique key that already exist
* @apiError {json} checkjsonfalse The body data are not consistent with the schema
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
* {"status":404,"ref":"Odmdb","msg":"see nationchains/model/lg/Odmdb_xx.json","data":"object to render with msg"}
*
*/
router.post("/itm/:objectname", checkHeaders, isAuthenticated, (req, res) => {
// Create an item of an object with no specificities
// if specificities then create a route / model that import odmdb
});
router.get(
"/searchitems/:objectname/:question",
checkHeaders,
isAuthenticated,
(req, res) => {
/**
*
*
*/
console.log(
"route referentials get all language" +
req.params.objectname +
"-" +
req.params.question
);
const getref = Referentials.getref(
true,
req.params.source,
req.params.idref,
req.session.header.xworkon,
req.session.header.xlang
);
// Return any status the data if any erreur return empty object
res.jsonp(getref.payload.data);
}
);
/**
* @api {get} /odmdb/itm/:objectname/:primaryindex - item Get
* @apiGroup Odmdb
* @apiName getItemFromId
* @apiDescription Get itm for a primaryid of an object
*
* @apiParam {String} objectname name Mandatory if in conf.nationObjects then file is into nationchains/ else in /nationchains/tribes/xtribe/objectname
* @apiParam {String} primaryindex the unique id where item is store
*
* @apiError {json} objectNotfound the file item does not exist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
* {"status":404,"ref":"Odmdb","msg":"doesnotexist","data":{"objectname":"objectname","key":"apxid","val":"primaryindex"}}
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{"indexname","content":{itm file}}
*
*
*/
// indexname = objectname_key_value.json
router.get(
"/itm/:objectname/:primaryindex",
checkHeaders,
isAuthenticated,
(req, res) => {
const objectName = req.params.objectname;
const objectId = req.params.primaryindex;
let objectLocation = "../../nationchains/";
if (!conf.api.nationObjects.includes(objectName)) {
objectLocation += `tribes/${req.session.headers.xtribe}/${objectName}`;
// check if accessright on object on item
// in case not res.status(403)
}
const objectpath = `${objectLocation}/${objectName}/itm/${objectId}`;
if (fs.existsSync(objectpath)) {
res.status(200).json({ data: fs.readJsonSync(objectpath) });
} else {
res.status(404).json({
ref: "Odmdb",
msg: "objectfiledoesnotexist",
data: { objectpath },
});
}
}
);
/**
* @api {get} https://wall-ants.ndda.fr/Checkjson.js - schema check data lib
* @apiGroup Odmdb
* @apiName checkjsonjs
* @apiDescription Public js lib to import in a browser by :<br>
* ```<script src="wall-ants.ndda.fr/nationchains/contracts/Checkjson.js"></script>```
* to import in a node.js:<br>
* ```const Checkjson = require(`Checkjson.js`);```
*
* with functions:<br>
* <strong>Checkjson.schema.validation(schema)</strong> that return<br>
* - {status:200, ref:"Checkjson", msg:"validcheck"} => all rules are correct<br>
* - {status:406, multimsg:[{ref:"Checkjson",msg:"errorkey",data:{}}]}<br>
*
* <strong>Checkjson.schema.data(schema{json},data{json},withschemacheck{boolean})</strong> that return<br>
* - {status:200, ref:"Checkjson", msg:"validcheck"} => all data keys respect schema rules <br>
* - {status:417, multimsg:[{ref:"Checkjson",msg:"errorkey",data:{}}]}<br>
*
* To identify issues, get the language errorkey list with a get
* https://wall-ants.ndda.fr/nationchains/models/Checkjson_lg.json
*
*/
/**
* @api {get} https://wall-ants.ndda.fr/nationchains/schema/:objectname - schema Get public
* @apiGroup Odmdb
* @apiName getPublicSchema
* @apiDescription Get a Schema model from public apxtrib (nations, pagans,persons,towns, tribes,wwws)
* @apiSuccess {json} contain json file
* @apiSuccessExample {json} Fichier direct
* HTTP/1.1 200 Success-response:
{
"$id": "https://smatchit.io/schema/pagan",
"$comment": "To create account bin apxtrib",
"title": "Pagans identity",
"description": "A numeric id in the nationchains world",
"type": "object",
"properties": {
"publickey": {
"title": "Alias's publickey",
"description": "Public key generate with openpgp.js",
"type": "string",
"format": "pgppublickey"
},
"alias": {
"title": "Alias",
"description": "text to remember easily a public key",
"type": "string",
"minLength": 4,
"pattern": "^[a-z0-9]*$"
},
"dt_delete": {
"title": "Date of death",
"description": "Date of alias delete request, your will will be apply",
"type": "string",
"format": "date-time"
},
"will": {
"title": "Will script after death",
"description": "This will script will be apply on your data 30 days after your death",
"type": "string"
}
},
"required": ["publickey", "alias"],
"apxid": "alias",
"apxuniquekey": ["publickey"],
"apxidx": [
{ "name": "lst_alias", "keyval": "alias" },
{ "name": "alias", "keyval": "alias" }
],
"apxaccessrights": {
"owner": { "R": [], "D": [] },
"anonymous": { "C": [], "R": ["alias"] },
"pagan": { "R": ["alias", "publickey"] }
}
}
* @apiError {json} contain json file
* @apiErrorExample {string} nginx html not found message
* HTTP/1.1 404 Not Found
* <html>...</html>
**/
/**
* @api {get} /odmdb/schema/:objectname - schema Get private
* @apiGroup Odmdb
* @apiName getPrivateSchema
* @apiDescription Get a private (profil must have accessright R on object) to a Schema model
*
* @apiParam {String} objectname Mandatory
*
* @apiError {object} ref objectmodel to get in the right language
* @apiErrorExample {json} Error-response:
* HTTP/1.1 404 Not Found
* {"status":404,"ref":"Odmdb","msg":"schemanotfound","data":{"fullpath"}}
*
* @apiSuccess {object} data contains schema requested
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 Success-response:
* {"status":200,"data":{schema}}
*/
router.get("schema/:objectname", checkHeaders, isAuthenticated, (req, res) => {
const fullpath = path.resolve(
`${__dirname}/tribes/${req.session.header.xworkon}/schema/${req.params.pathobjectname}.json`
);
if (fs.existsSync(fullpath)) {
res.status(200).json({ data: fs.readJsonSync(fullpath) });
} else {
res
.status(404)
.json({ status:404, msg: "schemanotfound", ref: "odmdb", data: { fullpath } });
}
});
/**
* @api {put} /odmdb/schema/:objectname - schema Put
* @apiGroup Odmdb
* @apiName putSchema
* @apiDescription Replace a schema by another one need druid profil for a tribe
*
* @apiParam {String} objectname Mandatory
*
* @apiBody {string} schemapath where to store schema .../schema
* @apiBody {string} objectpath where to store object ...objectname/idx/conf.json
* @apiBody {json} schema content
* @apiBody {json} schemalang content in lg
* @apiBody {string} lang define which schemalg is (2 letters)
*
* @apiError {object} ref objectmodel to get in the right language
* @apiErrorExample {json} Error-response:
* HTTP/1.1 404 Not Found
* {"status":404,"ref":"Odmdb","msg":"schemanotfound","data":{"fullpath"}}
*
* @apiSuccess {object} data contains schema requested
* HTTP/1.1 200 Success-response:
* {"status":200,"data":{schema}}
*
*
*/
router.put("schema/:objectname", checkHeaders, isAuthenticated, (req, res) => {
const fullpath = path.resolve(
`${__dirname}/tribes/${req.session.header.xworkon}/schema/${req.params.pathobjectname}.json`
);
const set = Odmdb.setObject(
path.resolve(`${__dirname}/tribes/${req.session.header.xworkon}`)
);
if (fs.existsSync(fullpath)) {
res.status(200).json({ data: fs.readJsonSync(fullpath) });
} else {
res
.status(404)
.json({ msg: "schemanotfound", ref: "odmdb", data: { fullpath } });
}
});
/**
* @api {get} https://wall-ants.ndda.fr/nationchains/models/:modelname_lg.json - translation notif Get public
* @apiGroup Odmdb
* @apiName getPublicModelmessagekey
* @apiDescription Get a public json object for the ref: modelname in language lg, to get a template description with key msg
* @apiParam {string} modelname Mandatory
* @apiSuccess {json} contain json file
* @apiSuccessExample {json} Fichier direct
* HTTP/1.1 200 Success-response:
* {
"alreadyexist": "Un object {{objectname}} avec la clé {{key}} existe déjà avec {{val}}",
"doesnotexist": "L'object {{objectname}} avec la clé {{key}} ,'existe pas avec {{val}}",
"getschema": "Schema {{{conf.name}}}",
"schemanotfound": "Schema introuvable dans {{{schemaPath}}}",
"pathnamedoesnotexist": "Le repertoire n'existe pas {{{indexpath}}}",
"objectfiledoesnotexist": "Le fichier n'existe pas {{{objectpath}}}",
"cudsuccessfull": "Mise à jour effectuée avec succés",
"missingprimarykey": "Il manque une clé primaire apxid pour stocker et identifier les objects",
"unconsistencyapxidx": "L'index {{name}} doit contenir en objkey au moins {{apxid}} car keyval n'est pas unique",
"profilnotallow": "Vous n'avez pas le profil de {{profils}}, cette action n'est pas authorisée",
"successreindex": "Objet reindexé à partir des items, vos index sont à jour",
"indexexist":"L'indexe existe"
}
* @apiError {json} contain json file
* @apiErrorExample {string} nginx html not found message
* HTTP/1.1 404 Not Found
* <html>...</html>
**/
module.exports = router;

View File

@ -1,264 +0,0 @@
const express = require("express");
const fs = require("fs-extra");
const path = require("path");
// Classes
const Pagans = require("../models/Pagans.js");
// Middlewares
const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* /api/models/Pagans.js
*
* Managed:
/**
* Alias exist then return public key or not
* @api {get} /pagans/alias/:alias - alias Get
* @apiName isalias
* @apiGroup Pagans
* @apiDescription If alias exist return its publickey
*
* @param {string} alias
*
* @apiError {json} aliasdoesnotexist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
{"status":404,"ref":"pagans","msg":"aliasdoesnotexist","data": { alias}}
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, ref:"pagans","msg":"aliasexist","data": { alias, publicKey }}
* *
**/
router.get("/alias/:alias", (req, res) => {
const getalias = Pagans.getalias(req.params.alias);
res.status(getalias.status).send(getalias);
});
/**
* Remove serveur token
* @api {get} /pagans/logout - pagan Logout
* @apiName Removetoken
* @apiGroup Pagans
* @apiDescription Remove token
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {status: 200, ref: "Pagans", msg: "logout"
*
*/
router.get("/logout", checkHeaders, isAuthenticated, (req, res) => {
console.log(req.session.header);
const logout = Pagans.logout(
req.session.header.xalias,
req.session.header.xtribe,
req.session.header.xdays,
req.session.header.xhash
);
res.status(logout.status).json(logout);
});
/**
* @api {get} /pagans/isauth - pagan isAuthenticated?
* @apiName isAuth
* @apiGroup Pagans
* @apiDescription Check if pagan's token is still valid
*
* @apiError (400) missingheaders
* @apiError (400) xaliasdoesnotexist
* @apiError (400) signaturefailled
* @apiError (401) aliasanonymous
* @apiError (404) tribedoesnotexist
*
* @apiSuccess (200) valid
* {object} data contains indexfile requested
*
*/
router.get("/isauth", checkHeaders, isAuthenticated, (req, res) => {
res.status(200).send({
status: 200,
ref: "headers",
msg: "authenticated",
data: {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
},
});
});
/**
* @api {post} /pagans - pagan Post
* @apiName addpagan
* @apiGroup Pagans
* @apiDescription
* Create a pagan account from alias, publickey, if trusted recovery =>
* Create a person in xtribe/person/xalias.json with profil.auth={email,privatekey, passphrase}
* Middleware isAuthenticated check that:
* - xhash is well signed from private key linked to the publickey of alias
* - check that alias does not already exist (if yes then verifiedsigne would be false)
* Need to wait next block chain to be sure that alias is register in the blokchain
*
* @apiError {json} objectNotfound the file does not exist
* @apiErrorExample {json}
* HTTP/1.1 404 Not Found
{"status":404,"ref":"Odmdb","msg":"pathnamedoesnotexist","data":{indexpath}}
*
* @apiSuccess {object} indexfile content
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {"status":200, "ref":"Odmdb", "msg":"indexexist", "data":{indexname,content:{index file}}
*
*/
router.post("/", checkHeaders, isAuthenticated, (req, res) => {
//console.log("pass ici", req.body);
const objpagan = { alias: req.body.alias, publickey: req.body.publickey };
const newpagan = Pagans.create(objpagan, {
xalias: req.session.header.xalias,
xprofils: req.session.header.xprofils,
});
if (newpagan.status == 200) {
if (req.body.email) {
const emailsent = Pagans.sendmailkey(
req.body.alias,
req.body.privatekey,
req.session.header.xtribe,
req.body.passphrase,
req.body.publickey,
req.body.email
);
}
if (req.body.trustedtribe) {
const personup = Pagans.personupdate(
req.body.alias,
req.body.trustedtribe,
{
recoveryauth: {
email: req.body.email,
privatekey: req.body.privatekey,
publickey: req.body.publickey,
passphrase: req.body.passphrase,
},
}
);
if (personup.status !== 200)
console.log("Warning no recovery registration", personup);
}
if (emailsent && emailsent.status != 200) {
newpagan.msg = "successfulcreatewithoutemail";
res.status(newpagan.status).json(newpagan);
}
} else {
//error to create pagan certaily already exist
res.status(newpagan.status).json(newpagan);
}
});
/**
* @api {delete} /pagans/alias/:alias - pagan Delete
* @apiName deletepagan
* @apiGroup Pagans
* @apiDescription
* Delete an alias and his publickey
* */
router.delete("/alias/:alias", checkHeaders, isAuthenticated, (req, res) => {
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
const result = Pagans.deletealias(req.params.id, req.session.header);
res.status(result.status).send(result.data);
});
router.delete("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
console.log(`DELETE pagans nationchains/pagans/${req.params.alias}.json`);
const result = Pagans.deleteperson(req.params.id, req.session.header);
res.status(result.status).send(result.data);
});
/**
* @api {get} /pagans/person:alias - person Get
* @apiName getpersondata
* @apiDescription Get person information from his alias for a xtribe (data and profils per apps)
* @apiGroup Pagans
*
* @apiParam {string} alias
*
* @apiSuccess (200) personExist
* @apiSuccessExample {json}
* {status:200, ref:"pagans",msg:"personexist",data: { person } }
*
* @apiError (404) Notfound
* @apiErrorExample {json}
* {status: 404, ref:"pagans",msg:"persondoesnotexist",data: { person } }
*
* @todo check accessright for req.session.header.xalias to see if jhe can get person data
* if req.param.alias == req.session.header.xalias => Owner
* else need accessright to on person set at R
* */
router.get("/person/:alias", checkHeaders, isAuthenticated, (req, res) => {
const getperson = Pagans.getperson(
req.session.header.xtribe,
req.params.alias,
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
);
res.status(getperson.status).send(getperson);
});
/**
* @api {post} /pagans/person - person Post
* @apiName addperson
* @apiGroup Pagans
* @apiDescription
* add a person = alias + tribe with specific accessright and specific schema link to tribe
*
*
*
* @todo add tribe/schema/person.json
*/
router.post("/person", checkHeaders, isAuthenticated, (req, res) => {
//console.log(req.body);
const persoad = Pagans.personcreate(
req.session.header.xtribe,
req.body.alias,
req.body,
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
);
res.status(persoad.status).json(persoad);
});
/**
* @api {put} /pagans/person - person Put
* @apiName updateperson
* @apiGroup Pagans
* @apiDescription
* update a person = alias + tribe with specific accessright and specific schema link to tribe
* @todo add tribe/schema/person.json
*/
router.put("/person", checkHeaders, isAuthenticated, (req, res) => {
//console.log(req.body);
const persoup = Pagans.personupdate(
req.session.header.xtribe,
req.body.alias,
req.body,
{ xprofils: req.session.header.xprofils, xalias: req.session.header.xalias }
);
res.status(persoup.status).json(persoup);
});
/**
* @api {get} /pagans/keyrecovery/tribe/email - recovery key by email
* @apiName recoveryKey
* @apiGroup Pagans
*
* @apiError (400) {object} status missingheaders / xalias does not exist / signaturefailled
* @apiError (401) {object} alias anonymous (not authenticated)
* @apiError (404) {string} tribe does not exist
*
* @apiSuccess (200) {object} data contains indexfile requested
*
*/
router.get("/keyrecovery/:tribeid/:email", checkHeaders, (req, res) => {
res.send(Pagans.keyrecovery(req.params.tribeId, req.params.email));
});
module.exports = router;

View File

@ -1,82 +0,0 @@
const express = require("express");
const glob = require("glob");
const fs = require("fs-extra");
const path = require("path");
const conf = require(`${process.env.dirtown}/conf.json`);
const Odmdb = require("../models/Odmdb.js");
// Middlewares
const checkHeaders = require("../middlewares/checkHeaders");
const isAuthenticated = require("../middlewares/isAuthenticated");
const router = express.Router();
/**
* @api {get} https://dns.xx/trk/pathtofile? - tracking system
* @apiGroup Trackings
* @apiName trackingsystem
* @apiDescription
* without header:<br>
* <code>https://dns.xx/trk/pathtofile?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&src=btnregister&version=1&lg=fr </code>
*
* with header<br>
* <code>https://dns.xx/trk/pathtofile?srckey=btnregister&version=1</code>
*
* where pathtofile is a ressource accessible from https://dns.xx/pathtofile
* html usage to track a loading page or email when a picture is load
* using apxwebapp in /src/ we got:
* <code> < img src="static/img/photo.jpg" data-trksrckey="loadpage" data-version="1" > </code>
*
* using html + apx.js (or at least with header {xalias,xuuid,xlang})
* <code>< img lazysrc="trk/static/img/photo.jpg data-trksrckey="loadpage" data-version="1" ></code>
*
* in js action:
*
* <code>
* <button></button>
* <a data-trksrckey="linktoblabla" href='https:..'
* onclick="apx.trackvisit("btnaction",1);actionfct();">
* </a>
* </code>
* #will hit an eventlistener<br>
* <code> axios.get("https://dns.xx/trk/cdn/empty.json?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&srckey=btnregister&version=1");
* </code>
*
* #or if no js available (example:email or pdf document)<br>
* <code> < img src="https://dns.xx/trk/static/img/photo.jpg?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&srckey=loadpage&version=1"</code>
*
* <code>
* <a href="https://dns.xx/trk/redirect?alias=anonymous&uuid=1b506f71-1bff-416c-9057-cb8b86296f60&srckey=loadpage&version=1&url=http://..."
* </code>
*
* will hit a tracker then redirect to url></a> *
*
*
*
* **if you use apx.js** : in html add in < button >, < img >, < a > tag data-trksrc="srckey"
* <code>
* < img src="https://dns.xx/static/img/photo.jpg" data-trkversion="1" data-trksrckey="registerform">
* < button data-trksrc="https://dns.xx/static/img/photo.jpg" data-trkversion="1" data-trksrckey="registerform">
* </code>
*
* Tracking log are store into tribe/logs/nginx/tribe_appname.trk.log
* Src have to be manage in tribe/api/models/lg/src_en.json
* <code>{"srckey":{
* "app":"presentation|app|apptest",
* "title":"",
* "description":""
* }
* }
* </code>
*
* @apiParam {String} alias=anonymous if authenticated we get from headers
* @apiParam {String} uuid a uuid v4 generate the first time a web page is open on a browser
* @apiParam {String} srckey source action that trig this get
* @apiParam {integer} version=1 can be an int, date or any version of the src
* @apiParam {integer} [tm] a timestamp of action when it is not immediate (for offline app)
*
*/
module.exports=router;

View File

@ -19,15 +19,15 @@
"logpm2": "pm2 logs apxtrib.js --lines 200",
"dev": "node apxtrib.js",
"unittest": "node unittest.js",
"apidoc": "apidoc -i api/middlewares api/test -o adminapi/www/apidoc",
"apidocsmatchit": "apidoc -i ../devfarm-ants/tribes/smatchit/api/routes -o adminapi/www/apidoc"
"apidoc": "apidoc -i api/middlewares api/routes -o adminapi/www/cdn/apidoc",
"apidocsmatchit": "apidoc -i ../devfarm-ants/tribes/smatchit/api/middlewares ../devfarm-ants/tribes/smatchit/api/routes -o ../devfarm-ants/tribes/smatchit/www/cdn/apidoc"
},
"apidoc": {
"name": "apXtrib",
"version": "1.0.0",
"title": "apiDoc for apXtrib",
"description": "Core api documentation",
"url": "https://smatchit.io/api",
"url": "https://wall-ants.ndda.fr/api",
"urlprod": "https://wall-ants.ndda.fr/apidoc/v1",
"order": [
"Middlewares",