access management and telemetrics #12
This commit is contained in:
@@ -0,0 +1,133 @@
|
|||||||
|
class AccessManager {
|
||||||
|
|
||||||
|
name = 'am'
|
||||||
|
init(app){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
start(app){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async audit(req, action, objectId, custom){
|
||||||
|
let data = {
|
||||||
|
t: Math.floor(Date.now() / 1000),
|
||||||
|
s: req.session?.id,
|
||||||
|
i: this.getIp(req),
|
||||||
|
r: req.headers.referer,
|
||||||
|
ua: req.headers['user-agent'],
|
||||||
|
l: req?.lang?.code,
|
||||||
|
u: req.user?._id && this.app.db.ObjectId(req.user._id),
|
||||||
|
a: action,
|
||||||
|
o: objectId && this.app.db.ObjectId(objectId),
|
||||||
|
c: custom
|
||||||
|
}
|
||||||
|
await this.app.db.create('log', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addToHistory(id, collection, action){
|
||||||
|
let o;
|
||||||
|
if (typeof id == 'string') o = await this.app.db.get(collection, {'_id': this.app.db.ObjectId(id)});
|
||||||
|
else o = id;
|
||||||
|
o._oid = this.app.db.ObjectId(o._id);
|
||||||
|
o._from = collection;
|
||||||
|
o._action = action;
|
||||||
|
await this.app.db.create('history', o);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getObjectHistory(collection, match){
|
||||||
|
let object = await this.app.db.aggregate( collection, [
|
||||||
|
{ $match: match },
|
||||||
|
{ $lookup: {from: 'users', foreignField: '_id', localField: '_meta.user', as: '_user'} },
|
||||||
|
{ $project: {action:'$_meta.action', time:'$_meta.time', user:"$_user.email", type:'current'} },
|
||||||
|
{ $unwind: {path:'$user', preserveNullAndEmptyArrays:true}}
|
||||||
|
]);
|
||||||
|
let history = await this.app.db.aggregate('history',[
|
||||||
|
{ $match: {_oid:object._id, _from:collection}},
|
||||||
|
{ $lookup: {from: 'users', foreignField: '_id', localField: '_meta.user', as: '_user'} },
|
||||||
|
{ $project: {action:'$_meta.action', time:'$_meta.time', user:"$_user.email", type:'history'} },
|
||||||
|
{ $sort: { time:-1 }},
|
||||||
|
{ $unwind: {path:'$user', preserveNullAndEmptyArrays:true}}
|
||||||
|
]);
|
||||||
|
return {object, history};
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeta(m, action, user, time, custom){
|
||||||
|
delete m.revert;
|
||||||
|
m.user = user && user._id && this.app.db.ObjectId(user._id);
|
||||||
|
m.creator = m.creator || m.user;
|
||||||
|
m.time = time || Math.floor(Date.now() / 1000);
|
||||||
|
m.ctime = m.ctime || m.time;
|
||||||
|
m.action = action;
|
||||||
|
custom && Object.assign(m, custom);
|
||||||
|
}
|
||||||
|
|
||||||
|
async processSocialLogin(p1, p2, profile, done){
|
||||||
|
//console.log(p1, p2, profile);
|
||||||
|
let externalProfile = {
|
||||||
|
loginProvider: profile.provider,
|
||||||
|
providerKey: profile.id
|
||||||
|
};
|
||||||
|
let user;
|
||||||
|
let dbUser = await this.app.db.get(collection, {social: externalProfile});
|
||||||
|
if (dbUser){
|
||||||
|
user = this.getUserProfile(dbUser);
|
||||||
|
}else{
|
||||||
|
let dbUser = {
|
||||||
|
email: (profile.emails && profile.emails[0].value) || ((profile.username || profile.id) + "@" + profile.provider),
|
||||||
|
firstName: (profile.name && profile.name.givenName) || profile.displayName,
|
||||||
|
lastName: profile.name && profile.name.familyName,
|
||||||
|
displayName: profile.displayName || (profile.name && profile.name.givenName),
|
||||||
|
profilePicture:
|
||||||
|
(profile.photos && profile.photos[0] && profile.photos[0].value)
|
||||||
|
|| (profile._json.data && profile._json.data.profile_picture),
|
||||||
|
status: 1,
|
||||||
|
social:[
|
||||||
|
externalProfile
|
||||||
|
],
|
||||||
|
roles:['user']
|
||||||
|
};
|
||||||
|
let r = await this.app.db.create(collection, dbUser);
|
||||||
|
user = this.getUserProfile(dbUser);
|
||||||
|
user._id = r.insertedId;
|
||||||
|
}
|
||||||
|
done(null, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserProfile(dbUser){
|
||||||
|
return {
|
||||||
|
_id: dbUser._id,
|
||||||
|
email: dbUser.email,
|
||||||
|
roles: dbUser.roles || ['user'],
|
||||||
|
groups: dbUser.groups || [],
|
||||||
|
firstName: dbUser.firstName,
|
||||||
|
lastName: dbUser.lastName,
|
||||||
|
displayName: dbUser.displayName,
|
||||||
|
profilePicture: dbUser.profilePicture,
|
||||||
|
status: dbUser.status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSocialCallback(provider){
|
||||||
|
const am = this;
|
||||||
|
return function(req, res, next) {
|
||||||
|
passport.authenticate(provider, function(err, user, info) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
let lang = req.cookies.lang || am.app.config.langs[0].code;
|
||||||
|
if (!user) { return res.redirect(`/${lang}/user/signin`); }
|
||||||
|
req.logIn(user, function(err) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
return res.redirect(`/${lang}`);
|
||||||
|
});
|
||||||
|
})(req, res, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is(user, role){
|
||||||
|
return user && user.roles.indexOf(role) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AccessManager }
|
||||||
@@ -72,6 +72,15 @@ class App{
|
|||||||
if(p.start) await p.start(this);
|
if(p.start) await p.start(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async stop(){
|
||||||
|
for (let p of this.plugins){
|
||||||
|
if(p.stop) {
|
||||||
|
console.debug('Stopping', p.name)
|
||||||
|
await p.stop(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -263,6 +263,10 @@ class Db {
|
|||||||
]);
|
]);
|
||||||
return ag.max || 0;
|
return ag.max || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async stop(){
|
||||||
|
await db.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Db };
|
export { Db };
|
||||||
@@ -105,6 +105,12 @@ class WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async stop(){
|
||||||
|
if (this.server) {
|
||||||
|
this.server.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { WebServer };
|
export { WebServer };
|
||||||
+19
-2
@@ -1,4 +1,5 @@
|
|||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
|
import { spawn } from "child_process";
|
||||||
|
|
||||||
console.debug = function(){
|
console.debug = function(){
|
||||||
if (process.env.debug){
|
if (process.env.debug){
|
||||||
@@ -11,6 +12,7 @@ import App from './app/App.js';
|
|||||||
const modules = [
|
const modules = [
|
||||||
{name: 'Config', path:'app/Config.js'},
|
{name: 'Config', path:'app/Config.js'},
|
||||||
{name: 'Db', path:'app/Db.js'},
|
{name: 'Db', path:'app/Db.js'},
|
||||||
|
{name: 'AccessManager', path:'app/AccessManager.js'},
|
||||||
|
|
||||||
{name: 'GameObjectsManager', path:'app/bl/GameObjectsManager.js'},
|
{name: 'GameObjectsManager', path:'app/bl/GameObjectsManager.js'},
|
||||||
{name: 'ScenariosManager', path:'app/bl/ScenariosManager.js'},
|
{name: 'ScenariosManager', path:'app/bl/ScenariosManager.js'},
|
||||||
@@ -30,10 +32,25 @@ process.on('uncaughtException', err => {
|
|||||||
console.error(reason, 'Unhandled Rejection at Promise', p);
|
console.error(reason, 'Unhandled Rejection at Promise', p);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV == 'development'){
|
||||||
|
console.log('Running in development mode');
|
||||||
|
process.stdin.resume();
|
||||||
|
process.stdin.on('data', async (data) => {
|
||||||
|
const input = data.toString().trim();
|
||||||
|
if (input === 'r') {
|
||||||
|
process.stdin.pause();
|
||||||
|
await app.stop();
|
||||||
|
console.log('Restarting...');
|
||||||
|
spawn(process.argv.shift(), process.argv, {
|
||||||
|
cwd: process.cwd(),
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const app = new App();
|
const app = new App();
|
||||||
|
|
||||||
await app.importModules(modules);
|
await app.importModules(modules);
|
||||||
|
|
||||||
await app.init();
|
await app.init();
|
||||||
|
|
||||||
console.log(`Starting...`);
|
console.log(`Starting...`);
|
||||||
|
|||||||
Reference in New Issue
Block a user