in progress

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

82
api/middlewares/checkHeaders.js Executable file
View File

@@ -0,0 +1,82 @@
const conf = require( '../../nationchains/tribes/conf.json' );
const checkHeaders = ( req, res, next ) => {
/**
* @apiDefine apxHeader
* @apiGroup Middleware
* @apiDescription Header is mandatory to access apxtrib see tribes/townconf.json.exposedHeaders
* A turn around can be done with a simple get params has to be sent in the get url. Usefull to send simple get without header like ?xworkon=tribeName&xlang=en... priority is given to headers
* For performance, tokens are store globaly in req.app.locals.tokens={xpaganid:xauth}
* if xlang is not in conf.languagesAvailable
*
* @apiHeader {string} xjwt Pagans unique jwt token store in local town Pagans data or "noauth"
* @apiHeader {string} xpseudo Pagans unique Pagan id in uuid format or "nouuid"
* @apiHeader {string} xlang the 2 letter langage it request the api (if not exist the 2 first letter of Accept-Language header ) if lang does not exist in the town then en is set (as it always exist in en).
* @apiHeader {string} xtribe Tribes id where pseudo want to act
* @apiHeader {string} xapp Name of www/xapp folder that host app that send the request
* /tribeid/person/xpseudo.json have accessright on this app store in /tribe/tribeid/www/xapp
*
* @apiError missingexposedHeaders it miss an exposedHeaders
*
* @apiErrorExample {json} Error-Response:
* HTTP/1/1 404 Not Found
* {
* status:400,
* ref:"middleware"
* msg:"missingheaders",
* data: ["xpseudo","xjwt"]
* }
*
* @apiHeaderExample {json} Header-Exemple:
* {
* xtribe:"apache",
* xalias:"toto",
* xhash:"",
* xlang:"en",
* xapp:"popular"
* }
*/
req.session = {};
const header = {};
if (!req.header('xlang') && req.header('Content-Language')) req.params.xlang=req.header('Content-Language');
let missingheader = [];
console.log('req.headers',req.headers)
for( const h of conf.api.exposedHeaders ) {
//console.log( h, req.header( h ) )
if( req.params[ h ] ) {
header[ h ] = req.params[ h ]
} else if( req.header( h ) ) {
header[ h ] = req.header( h )
} else {
missingheader.push(h);
}
};
//console.log( 'header', header )
// store in session the header information
req.session.header = header;
// Each header have to be declared
if( missingheader != "" ) {
// bad request
return res.status( 400 )
.json( {
ref:"headers",
msg: "missingheader",
data: missingheader
} );
};
//console.log( req.app.locals.tribeids )
if( !req.app.locals.tribeids.includes( header.xtribe ) ) {
return res.status( 400 )
.json( {
ref:"headers",
msg: 'tribeiddoesnotexist',
moreinfo: header.xtribe
} );
}
if( !conf.api.languages.includes( header.xlang ) ) {
console.log('warning language requested does not exist force to en glish')
header.xlang="en";
}
next();
};
module.exports = checkHeaders;

View File

@@ -0,0 +1,42 @@
const fs = require( 'fs-extra' );
const glob = require( 'glob' );
const path = require( 'path' );
const config = require( '../../nationchains/tribes/conf.json' );
const hasAccessrighton = ( object, action, ownby ) => {
/*
@action (mandatory) : CRUDO
@object (mandatory)= name of a folder object in /tribeid space can be a tree for example objects/items
@ownby (option) = list des uuid propriétaire
return next() if all action exist in req.app.local.tokens[UUID].ACCESSRIGHTS.data[object]
OR if last action ="O" and uuid exist in ownBy
Careffull if you have many action CRO let O at the end this will force req.right at true if the owner try an action on this object
*/
return ( req, res, next ) => {
//console.log( 'err.stack hasAccessrights', err.statck )
//console.log( `test accessright on object:${object} for ${req.session.header.xworkon}:`, req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ] )
req.right = false;
if( req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ] && req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ][ object ] ) {
req.right = true;
[ ...action ].forEach( a => {
if( a == "O" && ownby && ownby.includes( req.session.header.xpaganid ) ) {
req.right = true;
} else {
req.right = req.right && req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ][ object ].includes( a )
}
} )
}
//console.log( 'Access data autorise? ', req.right )
if( !req.right ) {
return res.status( 403 )
.json( {
info:'forbiddenAccessright',
ref: 'headers',
moreinfo: {xpaganid:req.session.header.xpaganid,object:object, xworkon:req.session.header.xworkon, action:action}
} )
}
next();
}
}
module.exports = hasAccessrighton;

View File

@@ -0,0 +1,207 @@
const jwt = require("jwt-simple");
const fs = require("fs-extra");
const moment = require("moment");
const dayjs = require("dayjs");
const glob = require("glob");
const conf = require("../../nationchains/tribes/conf.json");
const isAuthenticated = (req, res, next) => {
//once a day rm oldest tokens than 24hours
const currentday = dayjs().date();
console.log("dayjs", currentday);
console.log(
"test si menagedone" + currentday,
!fs.existsSync(`${conf.dirname}/tmp/tokensmenagedone${currentday}`)
);
if (!fs.existsSync(`${conf.dirname}/tmp/tokensmenagedone${currentday}`)) {
// clean oldest
const tsday = dayjs().date();
console.log("tsday", tsday);
glob.sync(`${conf.dirname}/tmp/tokensmenagedone*`).forEach((f) => {
fs.removeSync(f);
});
glob.sync(`${conf.dirname}/tmp/tokens/*.json`).forEach((f) => {
fs.readJson(f, (err, data) => {
if (!err && tsday - data.timestamp > 86400000) fs.remove(f);
});
});
}
//Check register in tmp/tokens/
console.log("isRegister?");
const resnotauth = {
ref: "headers",
msg: "notauthenticated",
data: {
xalias: req.session.header.xalias,
xtribe: req.session.header.xtribe,
},
};
console.lolg(req.session.header)
if (req.session.header.xalias == "anonymous") res.status(401).json(resnotauth);
const tmpfs = `${conf.dirname}/tmp/tokens/${req.session.header.xtribe}_${req.session.header.xalias}_${req.session.header.hash}.json`;
if (!fs.exists(tmpfs)) {
//check if pseudo exist as a pagan in pagans/ and as a person in xtribe/persons/ and check hash is coming from publickey
if (
!fs.existsSync(
`${conf.dirname}/nationchains/tribes/${req.session.header.xtribe}/persons/${req.session.header.xalias}.json`
)
) {
console.log(
`pseudo:${req.session.header.xalias} does not exist for xtribe ${req.session.header.xtribe}`
);
res.status(401).json(resnotauth);
}
if (
!fs.existsSync(
`${conf.dirname}/nationchains/pagans/${req.session.header.xalias}.json`
)
) {
console.log(
`pseudo:${req.session.header.xalias} does not exist as a pagan`
);
res.status(401).json(resnotauth);
}
const person = fs.readJsonSync(
`${conf.dirname}/nationchains/tribes/${req.session.header.xtribe}/persons/${req.session.header.xalias}.json`
);
const pagan = fs.readJsonSync(
`${conf.dirname}/nationchains/pagans/${req.session.header.xalias}.json`
);
//check hash with publickey pagan.publickey
// if good => create a /tmp/tokens/xtribe_xalias_xhash.json ={timestamp}
// if not good res.json(resnotauth)
}
next();
};
const isAuthenticatedold = (req, res, next) => {
/*
check if authenticated with valid token
if not => set req.session.header.xjwt=1
if yes => set for xWorkon
req.session.header.accessrights={
app:{'tribeid:website':[liste of menu]},
data:{ "sitewebsrc": "RWCDO",
"contacts": "RWCDO"}}
Liste of menu is linked with the app tht h
ave to be consistent with accessrights.data
data, list of object accessright Read Write Create Delete Owner
a xuuid can read any objet if R
if O wner means that it can only read write its object create by himself
*/
console.log("isAuthenticated()?");
//console.log( 'req.app.locals.tokens', req.app.locals.tokens )
//console.log( 'req.session.header', req.session.header );
// Check if token exist or not
req.session.header.accessrights = { app: "", data: {} };
if (
req.session.header.xalias == "1" ||
!req.app.locals.tokens[req.session.header.xalias]
) {
console.log(
`isAuthenticated no : uuid=1 (value=${req.session.header.xalias}) or locals.tokens[uuid] empty `
);
console.log(
"req.app.locals.tokens de xalias",
req.app.locals.tokens[req.session.header.xalias]
);
console.log(
"list key uuid de req.app.locals.tokens",
Object.keys(req.app.locals.tokens)
);
req.session.header.xjwt = "1";
} else if (
req.app.locals.tokens[req.session.header.xalias].TOKEN !==
req.session.header.xjwt
) {
// console.log(req.session.header.xuuid);
// console.log(req.session.header.xjwt);
// update tokens from file in case recently logged
try {
console.log(
"token not in list of token (req.app.locals.tokens) try to refresh from file"
);
req.app.locals.tokens = fs.readJsonSync(`${conf.tmp}/tokens.json`);
} catch (err) {
console.log(
`check isAuthenticated issue in reading ${conf.tmp}/tokens.json`
);
}
if (
req.app.locals.tokens[req.session.header.xalias].TOKEN !==
req.session.header.xjwt
) {
// if still does not exist then out
console.log("isAuthenticated no, token outdated");
req.session.header.xjwt = "1";
req.session.header.xalias = "1";
}
}
if (req.session.header.xjwt == "1") {
//return res.status( 403 )
return res.status(403).json({
info: ["forbiddenAccess"],
model: "Pagans",
moreinfo: "isAuthenticated faill",
});
} else {
console.log("isAuthenticated yes");
if (req.app.locals.tokens[req.session.header.xalias]) {
//console.log( `accessright pour ${req.session.header.xalias}`, req.app.locals.tokens[ req.session.header.xalias ].ACCESSRIGHTS );
//set header.accessrights from tokens.json
req.session.header.accessrights =
req.app.locals.tokens[req.session.header.xalias].ACCESSRIGHTS;
} else {
// case of bypass no accessright available
req.session.header.accessrights = {};
}
// Once per day, clean old token
const currentday = moment().date();
console.log(
"test si menagedone" + currentday,
!fs.existsSync(`${conf.tmp}/menagedone${currentday}`)
);
if (!fs.existsSync(`${conf.tmp}/menagedone${currentday}`)) {
glob.sync(`${conf.tmp}/menagedone*`).forEach((f) => {
fs.remove(f, (err) => {
if (err) {
console.log("err remove menagedone", err);
}
});
});
glob.sync(`${conf.tmp}/mdcreator*.log`).forEach((f) => {
fs.remove(f, (err) => {
if (err) {
console.log("err remove mdcreator log", err);
}
});
});
const newtokens = {};
for (const k of Object.keys(req.app.locals.tokens)) {
try {
const decodedToken = jwt.decode(
req.app.locals.tokens[k].TOKEN,
conf.jwtSecret
);
//console.log( moment( decodedToken.expiration ), moment() )
//console.log( moment( decodedToken.expiration ) >= moment() )
if (moment(decodedToken.expiration) >= moment()) {
newtokens[k] = req.app.locals.tokens[k];
}
} catch (err) {
console.log("Check isAuthenticated cleaning token ", err);
}
}
req.app.locals.tokens = newtokens;
fs.outputJsonSync(`${conf.tmp}/tokens.json`, newtokens);
fs.writeFileSync(
`${conf.tmp}/menagedone${currentday}`,
"fichier semaphore to clean data each day can be deleted with no consequence",
"utf-8"
);
}
next();
}
};
module.exports = isAuthenticated;

View File

@@ -0,0 +1,7 @@
{
"missingheader":"Some header miss to have a valid request: {{#data}} {{.}} {{/data}}",
"tribeiddoesnotexist":"Header xtribe: {{data}} does not exist in this town",
"authenticated":"Your perso{{{xpseudo}}} is register for tribe {{{xtribe}}}",
"notauthenticated":"Your pseudo {{xpseudo}} are not register into tribe {{xtribe}} ",
"forbiddenAccessright":"Pagan {{data.xpseudo}} has not access right to act {{data.action}} onto object {{data.object}} for tribe {{mor.xworkon}}"
}