update project with new architecture

This commit is contained in:
2023-04-13 07:46:35 +02:00
parent d0a3b10cfe
commit 67a02c33a2
333 changed files with 3764 additions and 1254 deletions

89
app/middlewares/checkHeaders.js Executable file
View File

@@ -0,0 +1,89 @@
const path = require( 'path' );
const config = require( '../tribes/townconf.js' );
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 config.languagesAvailable
*
* @apiHeader {string} xauth Pagans unique jwt token store in local town Pagans data or "noauth"
* @apiHeader {string} xpaganid 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 Pagan belong to
* @apiHeader {string} xworkon Tribes on which pagansId want and have accessright to work on.
* @apiHeader {string} xapp Name of app that send the request (tribesId:websiteName) cpaganid have to have accessright on this app}
*
* @apiError missingexposedHeaders it miss an exposedHeaders
*
* @apiErrorExample {json} Error-Response:
* HTTP/1/1 404 Not Found
* {
* status:404,
* info:"|middleware|missingheaders",
* moreinfo: xpaganid xauth
* }
*
* @apiHeaderExample {json} Header-Exemple:
* {
* xtribe:"apache",
* xpaganid:"12123211222",
* xworkon:"sioux",
* xauth:"",
* xlang:"en",
* xapp:""
* }
*/
req.session = {};
const header = {};
if (!req.header('xlang') && req.header('Content-Language')) req.params.xlang=req.header('Content-Language');
let missingheader = [];
for( const h of config.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 {
missingheade.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"
info: "missingheader",
moreinfo: missingheader
} );
};
//console.log( req.app.locals.tribeids )
if( !req.app.locals.tribeids.includes( header.xtribe ) ) {
return res.status( 400 )
.json( {
ref:"headers"
info: 'tribeiddoesnotexist',
moreinfo: header.xtribe
} );
}
if( !req.app.locals.tribeids.includes( header.xworkon ) ) {
return res.status( 400 )
.send( {
info: [ 'workondoesnotexist' ],
ref: 'headers',
moreinfo:header.xworkon
} );
}
if( !config.languages.includes( header.xlang ) ) {
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( '../tribes/townconf.js' );
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,115 @@
const jwt = require( 'jwt-simple' );
const jsonfile = require( 'jsonfile' );
const fs = require( 'fs-extra' );
const moment = require( 'moment' );
const glob = require( 'glob' );
//const path = require( 'path' );
// Check if package is installed or not to pickup the right config file
//const src = '..'; // ( __dirname.indexOf( '/node_modules/' ) > -1 ) ? '../../..' : '..';
//const config = require( path.normalize( `${__dirname}/${src}/config.js` ) );
const config = require( '../tribes/townconf.js' );
const isAuthenticated = ( req, res, next ) => {
/*
check if authenticated with valid token
if not => set req.session.header.xauth=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.xpaganid == config.devnoauthxuuid && req.session.header.xauth == config.devnoauthxauth ) {
console.log( 'isAuthenticated yes: carrefull using a bypass password give you accessrights={}' );
} else if( req.session.header.xpaganid == "1" || !req.app.locals.tokens[ req.session.header.xpaganid ] ) {
console.log( `isAuthenticated no : uuid=1 (value=${req.session.header.xpaganid}) or locals.tokens[uuid] empty ` );
console.log( 'req.app.locals.tokens de xpaganid', req.app.locals.tokens[ req.session.header.xpaganid ] );
console.log( 'list key uuid de req.app.locals.tokens', Object.keys( req.app.locals.tokens ) )
req.session.header.xauth = "1"
} else if( req.app.locals.tokens[ req.session.header.xpaganid ].TOKEN !== req.session.header.xauth ) {
// console.log(req.session.header.xuuid);
// console.log(req.session.header.xauth);
// 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( `${config.tmp}/tokens.json` );
} catch ( err ) {
console.log( `check isAuthenticated issue in reading ${config.tmp}/tokens.json` );
}
if( req.app.locals.tokens[ req.session.header.xpaganid ].TOKEN !== req.session.header.xauth ) {
// if still does not exist then out
console.log( 'isAuthenticated no, token outdated' );
req.session.header.xauth = "1"
req.session.header.xpaganid = "1"
}
}
if( req.session.header.xauth == "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.xpaganid ] ) {
//console.log( `accessright pour ${req.session.header.xpaganid}`, req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS );
//set header.accessrights from tokens.json
req.session.header.accessrights = req.app.locals.tokens[ req.session.header.xpaganid ].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( `${config.tmp}/menagedone${currentday}` ) )
if( !fs.existsSync( `${config.tmp}/menagedone${currentday}` ) ) {
glob.sync( `${config.tmp}/menagedone*` )
.forEach( f => {
fs.remove( f, ( err ) => {
if( err ) {
console.log( 'err remove menagedone', err )
}
} )
} );
glob.sync( `${config.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, config.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( `${config.tmp}/tokens.json`, newtokens );
fs.writeFileSync( `${config.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,6 @@
{
"missingheader":"This header miss to have a valid request: {{#moreinfo}} {{.}} {{/moreinfo}}",
"tribeiddoesnotexist":"Header xtribe: {{moreinfo}} does not exist",
"workondoesnotexist":"Header xworkon: {{moreinfo}} does not exist",
"forbiddenAccessright":"Pagan {{moreinfo.xpaganid}} has not access right to act {{moreinfo.action}} onto object {{moreinfo.object}} for tribe {{moreinfo.xworkon}}"
}