first new commit
This commit is contained in:
95
middlewares/ASUPhaveAccessrighttoanobject.js
Executable file
95
middlewares/ASUPhaveAccessrighttoanobject.js
Executable file
@@ -0,0 +1,95 @@
|
||||
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' );
|
||||
|
||||
// A REMPLACER PAR hasAccessrighton.js
|
||||
/*
|
||||
qui permet de passer en parametre des tests d'actions autoriser sur une objet
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// 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 haveAccessrighttoanobject = ( req, res, next ) => {
|
||||
/*
|
||||
from isAuthenticated req.session.header.accessrights={app:{'tribeid:projet':profile},
|
||||
data:{ "sitewebsrc": "RWCDO",
|
||||
"contacts": "RWCDO"}}
|
||||
from the last successfull authentification.
|
||||
profile is a keyword menu available into clientconf.json of tribeid
|
||||
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
|
||||
|
||||
This middleware check that we apply RESTFull CRUD concept depending of access right of a xuuid trying to act onto a xworkon tribeid
|
||||
Action get = Read put = Update post = Create delete = Delete
|
||||
object = req.Urlpath.split(/)[0]
|
||||
*/
|
||||
console.log( 'haveAccessrighttoanobject()?' );
|
||||
// req.originalUrl contain /object/action/id object id to run action
|
||||
// req.route.methods ={ put:true, delete:true post:true, get:true }
|
||||
const objet = req.baseUrl.slice( 1 ); //contain /object
|
||||
const model = objet.charAt( 0 )
|
||||
.toUpperCase() + objet.slice( 1 ); // model u object with first letter in uppercase
|
||||
let droit = "";
|
||||
let ownby = [];
|
||||
/*
|
||||
Check if object exist and get the OWNBY array, not relevant for referentials object that is only manage by CRUD no Owner logic
|
||||
*/
|
||||
if( objet != "referentials" ) {
|
||||
if( !fs.existsSync( `${config.tribes}/${req.session.header.xworkon}/${objet}/${req.params.id}.json` ) ) {
|
||||
res.status( 404 )
|
||||
.send( {
|
||||
payload: {
|
||||
info: [ 'idNotfound' ],
|
||||
model,
|
||||
moreinfo: `${config.tribes}/${req.session.header.xworkon}/${objet}/${req.params.id}.json does not exist `
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
ownby = jsonfile.readFileSync( `${config.tribes}/${req.session.header.xworkon}/${objet}/${req.params.id}.json` )
|
||||
.OWNBY;
|
||||
}
|
||||
}
|
||||
//console.log( req.session.header )
|
||||
if( req.session.header.xpaganid == config.devnoauthxuuid ) {
|
||||
console.log( 'haveAccessrighttoanobject yes cause dev test user' );
|
||||
} else {
|
||||
// accessrights was load from isAuthenticated.js middleware to make it available in req.session.header to be used into route for specific access if needed mainly to filter data in the get request depending of profil and data accessright.
|
||||
if( Object.keys( req.session.header.accessrights.data )
|
||||
.includes( "Alltribeid" ) && req.session.header.accessrights.data[ "Alltribeid" ][ objet ] ) {
|
||||
droit = req.session.header.accessrights.data[ "Alltribeid" ][ objet ];
|
||||
}
|
||||
// erase rights if tribeid is specified in addition of Alltribeid
|
||||
if( ( req.session.header.accessrights.data[ req.session.header.xworkon ] ) &&
|
||||
req.session.header.accessrights.data[ req.session.header.xworkon ][ objet ] ) {
|
||||
droit = req.session.header.accessrights.data[ req.session.header.xworkon ][ objet ];
|
||||
if( ( req.route.methods.get && droit.includes( 'R' ) ) ||
|
||||
( req.route.methods.put && droit.includes( 'U' ) ) ||
|
||||
( req.route.methods.delete && droit.includes( 'D' ) ) ||
|
||||
ownby.includes( req.params.id ) ) {
|
||||
console.log( 'haveAccessrighttoanobject yes' )
|
||||
} else if( req.route.methods.post && droit.includes( 'C' ) ) {
|
||||
console.log( 'haveAccessrighttoanobject yes create' );
|
||||
} else {
|
||||
console.log( 'haveAccessrighttoanobject no' )
|
||||
res.status( 403 )
|
||||
.send( {
|
||||
payload: {
|
||||
info: [ 'NoAccessrights' ],
|
||||
model,
|
||||
moreinfo: `User ${req.session.header.xpaganid} accessrights are not set to do this action`
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
module.exports = haveAccessrighttoanobject;
|
88
middlewares/checkHeaders.js
Executable file
88
middlewares/checkHeaders.js
Executable file
@@ -0,0 +1,88 @@
|
||||
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( '../config.js' );
|
||||
/*
|
||||
Check que le header contient des éléments necessaire pour les
|
||||
routes utilisant tribeid / language / token / uuid
|
||||
*/
|
||||
const checkHeaders = ( req, res, next ) => {
|
||||
//console.log( 'checkHeaders()' );
|
||||
// These headers must be passed in the request
|
||||
// X-Auth and X-Uuid could have any true value
|
||||
// header is stored in req.app.locals.header to be pass to route
|
||||
/* const header = {
|
||||
xtribeid: req.header('x-client-id'),
|
||||
xlang: req.header('x-language'),
|
||||
xauth: req.header('x-auth'),
|
||||
xuuid: req.header('x-uuid'),
|
||||
xworkon: req.header('x-xorkon',
|
||||
xapp:req.header('x-app'))
|
||||
};
|
||||
On recupere accessrights via is Authenticated
|
||||
*/
|
||||
req.session = {};
|
||||
const header = {};
|
||||
let missingheader = "";
|
||||
//console.log( 'avant validation headers', req.headers );
|
||||
//attention changement 7/11/2021 phil des exposedheader cf config.js
|
||||
//If in httprequest url header are send then they are used inpriority
|
||||
//Use case : send an email with a unique link that works without password and request to change password
|
||||
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 {
|
||||
// Missing header
|
||||
missingheader += " " + h
|
||||
}
|
||||
};
|
||||
//console.log( 'header', header )
|
||||
if( req.params.xauth && req.params.xuuid ) {
|
||||
// If this exist => it is a timeout limited token
|
||||
req.app.locals.tokens[ req.params.xpaganid ] = req.params.xauth;
|
||||
}
|
||||
req.session.header = header;
|
||||
// Each header have to be declared
|
||||
if( missingheader != "" ) {
|
||||
return res.status( 403 )
|
||||
.send( {
|
||||
info: [ 'forbiddenAccess' ],
|
||||
model: 'Pagans',
|
||||
moreinfo: 'checkHeader headerIsMissing:' + missingheader
|
||||
} );
|
||||
};
|
||||
//console.log( req.app.locals.tribeids )
|
||||
if( !req.app.locals.tribeids.includes( header.xtribe ) ) {
|
||||
return res.status( 404 )
|
||||
.send( {
|
||||
info: [ 'tribeiddoesnotexist' ],
|
||||
model: 'Pagans',
|
||||
moreinfo: `xtribe unknown: ${header.xtribe}`
|
||||
} );
|
||||
}
|
||||
if( !req.app.locals.tribeids.includes( header.xworkon ) ) {
|
||||
return res.status( 404 )
|
||||
.send( {
|
||||
info: [ 'tribeiddoesnotexist' ],
|
||||
model: 'Pagans',
|
||||
moreinfo: `xworkon unknown: ${header.xworkon}`
|
||||
} );
|
||||
}
|
||||
if( !config.languagesAvailable.includes( header.xlang ) ) {
|
||||
return res.status( 404 )
|
||||
.send( {
|
||||
info: [ 'langNotused' ],
|
||||
model: 'Pagans',
|
||||
moreinfo: `xlang unknown: ${header.xlang}`
|
||||
} );
|
||||
}
|
||||
//console.log( 'After middleare checkHeaders.js req.session.header', req.session.header )
|
||||
//console.log( 'checkheaders next' )
|
||||
next();
|
||||
};
|
||||
module.exports = checkHeaders;
|
42
middlewares/hasAccessrighton.js
Executable file
42
middlewares/hasAccessrighton.js
Executable file
@@ -0,0 +1,42 @@
|
||||
const fs = require( 'fs-extra' );
|
||||
const glob = require( 'glob' );
|
||||
const path = require( 'path' );
|
||||
|
||||
const config = require( '../config.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 )
|
||||
.send( {
|
||||
info: [ 'forbiddenAccess' ],
|
||||
model: 'middleware',
|
||||
moreinfo: 'no auth to act on this object'
|
||||
} )
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
module.exports = hasAccessrighton;
|
113
middlewares/isAuthenticated.js
Executable file
113
middlewares/isAuthenticated.js
Executable file
@@ -0,0 +1,113 @@
|
||||
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( '../config.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 have 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 = jsonfile.readFileSync( `${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 )
|
||||
.send( {
|
||||
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;
|
||||
jsonfile.writeFileSync( `${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;
|
Reference in New Issue
Block a user