Compare commits
6 Commits
5c89e3a766
...
5d13783ed5
Author | SHA1 | Date |
---|---|---|
Ruben Meyer | 5d13783ed5 | |
Ruben Meyer | f79d5771f1 | |
Ruben Meyer | fd9e52bd65 | |
Ruben Meyer | cd8cedf592 | |
Ruben Meyer | 4cf687bd58 | |
Ruben Meyer | 265e270110 |
20
app.js
20
app.js
|
@ -8,17 +8,15 @@
|
|||
// GDS: Global Data System
|
||||
global['gds'] = {
|
||||
debug: (process.env.NODE_ENV === 'debug') ? true : false,
|
||||
db: null,
|
||||
cache: {},
|
||||
cfg: require(__dirname+'/bin/config')
|
||||
};
|
||||
global['modules'] = {};
|
||||
global['__dirname'] = __dirname;
|
||||
|
||||
/**
|
||||
* load modules
|
||||
*/
|
||||
let load = (name) => {
|
||||
let load = global['requireModule'] = (name) => {
|
||||
return require(__dirname+'/bin/'+name+'/module');
|
||||
};
|
||||
|
||||
|
@ -33,17 +31,9 @@ env_vars.forEach((el) => {
|
|||
});
|
||||
if(env_missing) process.exit();
|
||||
|
||||
global['modules'].events = load('events'); // event handler
|
||||
global['modules'].cli = load('cli'); // command line interface
|
||||
load('events'); // event handler
|
||||
|
||||
global['modules'].logs = load('logs'); // log handler
|
||||
global['logs'] = global['modules'].logs; // alias
|
||||
global['logs'] = load('logs'); // log handler
|
||||
|
||||
global['modules'].database = load('database'); // database service
|
||||
global['modules'].web = load('web'); // web server
|
||||
global['modules'].auth = load('auth'); // authentication handler
|
||||
|
||||
global['logs'] = global['modules'].logs; // alias
|
||||
|
||||
// start web server
|
||||
global['modules'].web.start();
|
||||
let web = load('web'); // web server
|
||||
web.start(); // start web server
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
var methods = {};
|
||||
var crypto = require('crypto');
|
||||
|
||||
var cfg = require(global['__dirname']+'/bin/config');
|
||||
delimiter = cfg.app.passhashDelimiter;
|
||||
|
||||
/**
|
||||
* Generating Hash
|
||||
* returns a hash|salt combination
|
||||
* @author Ruben Meyer
|
||||
* @param {String} key "user password"
|
||||
* @param {String} salt (OPTIONAL)
|
||||
|
@ -27,11 +30,11 @@ methods.generateHash = (key, salt) => {
|
|||
hash.update(key);
|
||||
hash = hash.digest('hex');
|
||||
|
||||
return hash+'|'+salt;
|
||||
return hash+delimiter+salt;
|
||||
};
|
||||
|
||||
/**
|
||||
* validate hashed password
|
||||
* validates a hashed input
|
||||
* @author Ruben Meyer
|
||||
* @param {String} hash "hashed password"
|
||||
* @param {String} key "plaintext password"
|
||||
|
@ -40,15 +43,15 @@ methods.generateHash = (key, salt) => {
|
|||
methods.validateHash = (hash, key) => {
|
||||
if(typeof hash !== 'string' || typeof key !== 'string') return false;
|
||||
|
||||
let salt = hash.split('|')[1];
|
||||
let salt = hash.split(delimiter)[1];
|
||||
let generated = methods.generateHash(key, salt);
|
||||
|
||||
if(
|
||||
hash.split('|')[0].length === generated.split('|')[0].length
|
||||
hash.split(delimiter)[0].length === generated.split(delimiter)[0].length
|
||||
&&
|
||||
crypto.timingSafeEqual(
|
||||
Buffer.from(generated.split('|')[0], 'hex'),
|
||||
Buffer.from(hash.split('|')[0], 'hex')
|
||||
Buffer.from(generated.split(delimiter)[0], 'hex'),
|
||||
Buffer.from(hash.split(delimiter)[0], 'hex')
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* This file is part of the authRXBN single sign-on package.
|
||||
*
|
||||
* (c) Ruben Meyer <contact@rxbn.de>
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
'command': 'cache [action] [type]',
|
||||
'description': 'do something with the cache',
|
||||
'actionDependencies': ['vorpal'],
|
||||
'action': (actionDependencies) => {
|
||||
let vorpal = actionDependencies.vorpal;
|
||||
return (args, cb) => {
|
||||
if(typeof args.action !== 'undefined') {
|
||||
let action = args.action.toLowerCase();
|
||||
|
||||
if(typeof args.type !== 'undefined') { var type = args.type.toLowerCase(); }
|
||||
else { var type = ''; }
|
||||
|
||||
//Object.keys(args.options).length > 0
|
||||
if(action == 'help' || action == '?') {
|
||||
vorpal.exec('cache --help');
|
||||
}
|
||||
else if(action == 'flush') {
|
||||
if(typeof global['gds'].cache[type] !== "undefined") {
|
||||
global['gds'].cache[type] = {};
|
||||
console.log(type+' cache flush');
|
||||
} else if(type == 'all') {
|
||||
global['gds'].cache = {};
|
||||
console.log('full cache flush');
|
||||
}
|
||||
else vorpal.exec('cache --help');
|
||||
}
|
||||
else if(action == 'get') {
|
||||
console.log(Object.keys(global['gds'].cache));
|
||||
console.log(type);
|
||||
console.log(type in Object.keys(global['gds'].cache));
|
||||
console.log(Object.keys(global['gds'].cache).hasOwnProperty(type));
|
||||
if(typeof global['gds'].cache[type] !== "undefined") {
|
||||
console.log(JSON.stringify(global['gds'].cache[type]));
|
||||
} else if(type == 'all'){
|
||||
console.log(JSON.stringify(global['gds'].cache));
|
||||
} else {
|
||||
console.log("The cache \""+type+"\" doesnt exists.");
|
||||
vorpal.exec('cache --help');
|
||||
}
|
||||
} else vorpal.exec('cache --help');
|
||||
} else vorpal.exec('cache --help');
|
||||
cb();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* This file is part of the authRXBN single sign-on package.
|
||||
*
|
||||
* (c) Ruben Meyer <contact@rxbn.de>
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
'command': 'clear',
|
||||
'description': 'clear the output',
|
||||
'action': (args, cb) => {
|
||||
process.stdout.write ("\u001B[2J\u001B[0;0f");
|
||||
cb();
|
||||
}
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* This file is part of the authRXBN single sign-on package.
|
||||
*
|
||||
* (c) Ruben Meyer <contact@rxbn.de>
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
'command': 'logs',
|
||||
'description': 'output logs',
|
||||
'action': (args, cb) => {
|
||||
console.log(JSON.stringify(global['gds'].cache.logs));
|
||||
cb();
|
||||
}
|
||||
};
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
* This file is part of the authRXBN single sign-on package.
|
||||
*
|
||||
* (c) Ruben Meyer <contact@rxbn.de>
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
'command': 'user <action> <nick> [data...]',
|
||||
'description': 'add, get, update or remove an user',
|
||||
'actionDependencies': ['vorpal'],
|
||||
'action': (actionDependencies) => {
|
||||
let vorpal = actionDependencies.vorpal;
|
||||
return (args, cb) => {
|
||||
if(typeof args.action !== 'undefined') {
|
||||
let action = args.action.toLowerCase();
|
||||
let profile = {
|
||||
user: args.nick,
|
||||
pass: null,
|
||||
mail: null,
|
||||
group: 0
|
||||
};
|
||||
|
||||
// add a new user
|
||||
if(action === 'add') {
|
||||
if(Array.isArray(args.data) && args.data.length >= 1) {
|
||||
// set data
|
||||
profile.pass = global['modules'].auth.generateHash(args.data[0]);
|
||||
if(args.data.length >= 2) profile.mail = args.data[1];
|
||||
if(args.data.length >= 3) profile.group = args.data[2];
|
||||
|
||||
// haystack verifying
|
||||
let haystack = profile.user;
|
||||
if(typeof profile.mail !== 'undefined' && profile.mail !== null) haystack = [profile.user, profile.mail];
|
||||
|
||||
// query user by haystack
|
||||
global['modules'].database.getUser(haystack, (err, rep) => {
|
||||
if(err) {
|
||||
global['logs'].error("ERR: While finding user");
|
||||
global['logs'].error(err);
|
||||
}
|
||||
else {
|
||||
// no users exist, add user
|
||||
if (!rep) {
|
||||
global['modules'].database.addUser(profile.user, (profile.mail || ''), profile.pass, profile.group, (errAdd, repAdd) => {
|
||||
if(errAdd) {
|
||||
global['logs'].error("ERR: While adding user");
|
||||
global['logs'].error(errAdd);
|
||||
}
|
||||
else vorpal.log("Reply: "+repAdd);
|
||||
});
|
||||
// user already exists
|
||||
} else {
|
||||
vorpal.log("User exists: ");
|
||||
|
||||
rep.forEach((el, i) => {
|
||||
el["passhash"] = undefined; // not needed
|
||||
rep[i] = el;
|
||||
});
|
||||
vorpal.log(rep);
|
||||
}
|
||||
}
|
||||
});
|
||||
// missing data
|
||||
} else {
|
||||
global['logs'].log("No data is present or is missing. Please see:");
|
||||
global['logs'].log("$ user help add");
|
||||
cb();
|
||||
}
|
||||
// query users
|
||||
} else if(action === 'get' || action === 'ls') {
|
||||
// wildcard catch-all
|
||||
if(profile.user === '*') {
|
||||
global['modules'].database.getUsers((err, rep) => {
|
||||
if(rep) {
|
||||
rep.forEach((el, i) => {
|
||||
el["passhash"] = undefined; // not needed
|
||||
rep[i] = el;
|
||||
});
|
||||
global['logs'].log(rep);
|
||||
}
|
||||
if(err) {
|
||||
global['logs'].error('$ user get *');
|
||||
global['logs'].error(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// query users by first input <nickname>
|
||||
global['modules'].database.getUser(profile.user, (err, rep) => {
|
||||
// user exists
|
||||
if(rep && rep.length == 1) {
|
||||
global['logs'].log("User exists: ");
|
||||
|
||||
rep.forEach((el, i) => {
|
||||
el["passhash"] = undefined; // not needed
|
||||
rep[i] = el;
|
||||
});
|
||||
global['logs'].log(rep);
|
||||
} else {
|
||||
// found more than one user
|
||||
if(rep && rep.length >= 2) {
|
||||
global['logs'].warn("multiple users found for "+profile.user+".");
|
||||
rep.forEach((el) => {
|
||||
global['logs'].warn("found user with id: "+el._id);
|
||||
});
|
||||
// user does not exist
|
||||
} else {
|
||||
global['logs'].warn("User "+profile.user+" doesn't exist.");
|
||||
}
|
||||
}
|
||||
|
||||
// query error
|
||||
if(err) {
|
||||
global['logs'].error('$ user get '+profile.user);
|
||||
global['logs'].error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// update users, just one property
|
||||
} else if(action === 'update') {
|
||||
if(args.data.length < 2) global['logs'].error("No data supplied.");
|
||||
else {
|
||||
let property = args.data[0];
|
||||
let param = args.data[1];
|
||||
global['logs'].debug("Prop: "+property+"; Param: "+param);
|
||||
|
||||
// query user
|
||||
global['modules'].database.getUser(profile.user, (err, rep) => {
|
||||
// user exists
|
||||
if(rep && rep.length == 1) {
|
||||
let obj = {};
|
||||
obj[property] = param;
|
||||
global['modules'].database.updateUser(String(rep[0]._id), obj, (errUpd, repUpd) => {
|
||||
// updated user
|
||||
if(repUpd) {
|
||||
global['logs'].log("User with id "+String(rep[0]._id)+" was updated.");
|
||||
// user not updated
|
||||
} else {
|
||||
global['logs'].warn("User with id "+String(rep[0]._id)+" doesn't exist.");
|
||||
}
|
||||
|
||||
// query error
|
||||
if(errUpd) {
|
||||
global['logs'].error('$ user update '+profile.user+' '+property+' '+param+' [on update]');
|
||||
global['logs'].error(errUpd);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// found more than one user
|
||||
if(rep && rep.length >= 2) {
|
||||
global['logs'].warn("multiple users found for "+profile.user+". bad state. can't update.");
|
||||
rep.forEach((el) => {
|
||||
global['logs'].warn("found user with id: "+el._id);
|
||||
});
|
||||
// user does not exist
|
||||
} else {
|
||||
global['logs'].warn("User "+profile.user+" doesn't exist.");
|
||||
}
|
||||
}
|
||||
|
||||
// query error
|
||||
if(err) {
|
||||
global['logs'].error('$ user update '+profile.user+' '+field+' '+param+' [on query]');
|
||||
global['logs'].error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
// remove users
|
||||
} else if(action === 'remove' || action === 'delete') {
|
||||
// haystack
|
||||
let haystack = profile.user;
|
||||
if(typeof profile.mail !== 'undefined' && profile.mail !== null) haystack = [profile.user, profile.mail];
|
||||
|
||||
// query user
|
||||
global['modules'].database.getUser(haystack, (err, rep) => {
|
||||
if(rep) {
|
||||
vorpal.log("user exists. deleting him.");
|
||||
global['logs'].debug(rep);
|
||||
|
||||
// remove user
|
||||
global['modules'].database.delUser(rep[0].email, (errDel, repDel) => {
|
||||
if(repDel) {
|
||||
vorpal.log("deleted user.");
|
||||
global['logs'].debug(repDel);
|
||||
}
|
||||
else {
|
||||
vorpal.log("ERR: while deleting user.");
|
||||
global['logs'].debug(errDel);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if(action === 'help') {
|
||||
if(args.nick === 'add') {
|
||||
vorpal.log("user add <nickname> <raw password> <mail> [group]");
|
||||
vorpal.log("<nickname>: user nickname");
|
||||
vorpal.log("<raw password>: will be hashed ASAP");
|
||||
vorpal.log("<mail>: format: user@example.tld");
|
||||
vorpal.log("[group]: not needed; only Numbers; group id");
|
||||
|
||||
vorpal.log("---");
|
||||
|
||||
vorpal.log("returns 0 or 1 and printing errors");
|
||||
} else if(args.nick === 'get') {
|
||||
vorpal.log("user get <nickname or email>");
|
||||
vorpal.log("<nickname or email>: searching both in both; format: foobar OR user@example.tld");
|
||||
|
||||
vorpal.log("---");
|
||||
vorpal.log("user get * - to get all users");
|
||||
vorpal.log("prints JSON-object of user data");
|
||||
} else if(args.nick === 'update') {
|
||||
vorpal.log("user update <nickname> <field> <parameter>");
|
||||
vorpal.log("<nickname>: user nickname");
|
||||
vorpal.log("<field>: string");
|
||||
vorpal.log("<parameter>: mixed data; will be converted to Boolean, Number or String");
|
||||
|
||||
vorpal.log("---");
|
||||
|
||||
vorpal.log("returns 0 or 1 and printing errors");
|
||||
vorpal.log("prints JSON-object of updated user data");
|
||||
} else if(args.nick === 'remove' || args.nick === 'delete') {
|
||||
vorpal.log("user remove|delete <nickname>");
|
||||
vorpal.log("<nickname>: user nickname or mail");
|
||||
|
||||
vorpal.log("---");
|
||||
|
||||
vorpal.log("returns 0 or 1 and printing errors");
|
||||
}
|
||||
}
|
||||
|
||||
cb();
|
||||
} else {
|
||||
vorpal.exec('user --help');
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* This file is part of the authRXBN single sign-on package.
|
||||
*
|
||||
* (c) Ruben Meyer <contact@rxbn.de>
|
||||
*/
|
||||
|
||||
let vorpal = require('vorpal')();
|
||||
let chalk = require('chalk');
|
||||
let fs = require('fs');
|
||||
|
||||
/**
|
||||
* read command files and interpret them
|
||||
* @author Ruben Meyer
|
||||
* @todo options, types, hide command, parsing, help, autocompletion, allow unknown options
|
||||
*/
|
||||
let cmdPath = global['__dirname']+'/bin/cli/cmds';
|
||||
fs.readdir(cmdPath, (err, files) => {
|
||||
if(files.length > 0)
|
||||
files.forEach((file) => {
|
||||
let cmd = require(cmdPath+'/'+file); // read file
|
||||
|
||||
// exported data is an object
|
||||
if(typeof cmd == 'object' && typeof cmd.command !== 'undefined') {
|
||||
// set initial building steps
|
||||
let builder = vorpal.command(cmd.command);
|
||||
|
||||
// description
|
||||
if(typeof cmd.description !== 'undefined') builder = builder.description(cmd.description);
|
||||
|
||||
// aliases
|
||||
if(typeof cmd.alias !== 'undefined') {
|
||||
if(typeof cmd.alias === 'object' && Array.isArray(cmd.alias)) builder = builder['alias'](...cmd.alias);
|
||||
if(typeof cmd.alias === 'string' && cmd.alias.split(',').length >= 2) {
|
||||
let args = cmd.alias.split(',');
|
||||
for(let i = 0; i < args.length; i++)
|
||||
args[i] = args[i].trim();
|
||||
builder = builder['alias'](...cmd.alias);
|
||||
}
|
||||
}
|
||||
|
||||
// action
|
||||
if(typeof cmd.action !== 'undefined' && typeof cmd.action === 'function') {
|
||||
if(typeof cmd.actionDependencies !== 'undefined') {
|
||||
let dependencies = [];
|
||||
let actionDependencies = {};
|
||||
|
||||
// format input
|
||||
if(typeof cmd.actionDependencies === 'object') {
|
||||
if(Array.isArray(cmd.actionDependencies))
|
||||
cmd.actionDependencies.forEach((dependency) => dependencies.push(dependency));
|
||||
} else if(typeof cmd.actionDependencies === 'string') {
|
||||
let strArr = cmd.actionDependencies.split(',');
|
||||
for(let i = 0; i < strArr.length; i++)
|
||||
dependencies.push(strArr[i].trim());
|
||||
}
|
||||
|
||||
// retrieve dependencies; unknown dependencies wont be handled
|
||||
dependencies.forEach((dependency) => {
|
||||
switch(dependency) {
|
||||
case 'vorpal':
|
||||
actionDependencies['vorpal'] = vorpal;
|
||||
break;
|
||||
case 'chalk':
|
||||
actionDependencies['chalk'] = chalk;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
builder = builder['action'](cmd.action(actionDependencies));
|
||||
} else {
|
||||
builder = builder['action'](cmd.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
@TODO remove code
|
||||
isJson = (str) => {
|
||||
try {
|
||||
let o = JSON.parse(str);
|
||||
|
||||
|
||||
return (o && typeof o === "object") ? true : false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
vorpal.delimiter('auth@rxbn$').show();
|
||||
|
||||
module.exports = vorpal;
|
|
@ -27,6 +27,7 @@ module.exports = {
|
|||
},
|
||||
app: {
|
||||
locale: 'de-DE', // default locale (de-DE & en-EN should be available)
|
||||
passhashDelimiter: '|'
|
||||
},
|
||||
mongoose: {
|
||||
uri: process.env.DB_URL,
|
||||
|
|
|
@ -13,28 +13,40 @@ var sanitize = require('mongo-sanitize');
|
|||
var crypto = require('crypto');
|
||||
var methods = {};
|
||||
|
||||
// connect
|
||||
mongoose.connect(global['gds'].cfg.mongoose.uri, {
|
||||
useNewUrlParser: true
|
||||
});
|
||||
mongoose.set('useFindAndModify', false);
|
||||
|
||||
global['gds'].db = mongoose.connection;
|
||||
var log = require(global['__dirname']+'/bin/logs/module');
|
||||
var cfg = require(global['__dirname']+'/bin/config');
|
||||
|
||||
var db;
|
||||
var mdls = require('./models.js');
|
||||
var models = mdls(global['gds'].db);
|
||||
var models;
|
||||
|
||||
(async function() {
|
||||
global['gds'].db = await global['gds'].db.useDb(global['gds'].cfg.mongoose.db);
|
||||
|
||||
models = mdls(global['gds'].db);
|
||||
})();
|
||||
/**
|
||||
* connects to db
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
*/
|
||||
methods.connect = async () => {
|
||||
if(typeof db !== "undefined") return;
|
||||
|
||||
// connection error handling
|
||||
global['gds'].db.on('error', (data) => {
|
||||
global['modules'].logs.error('MongoDB connection error:\n', data);
|
||||
process.exit(); // exit on connection error
|
||||
});
|
||||
// connect
|
||||
mongoose.connect(cfg.mongoose.uri, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
useFindAndModify: false
|
||||
});
|
||||
|
||||
|
||||
db = mongoose.connection;
|
||||
db = await db.useDb(cfg.mongoose.db);
|
||||
models = mdls(db);
|
||||
|
||||
// connection error handling
|
||||
db.on('error', (data) => {
|
||||
log.error('MongoDB connection error:\n', data);
|
||||
process.exit(); // exit on connection error
|
||||
});
|
||||
}
|
||||
|
||||
// // // //////// //////// ///////
|
||||
// // // // // // //
|
||||
|
@ -47,19 +59,19 @@ global['gds'].db.on('error', (data) => {
|
|||
|
||||
/**
|
||||
* Adds User to Database
|
||||
* @author Ruben Meyer
|
||||
* @param {String} nick nickname
|
||||
* @param {String} email email
|
||||
* @param {String} passhash hashed password
|
||||
* @param {Number} group Group id (normally 0 -> user)
|
||||
* @param {Function} callback Callback function (error, reply)
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @param {String} nick nickname
|
||||
* @param {String} email email
|
||||
* @param {String} passhash hashed password
|
||||
* @param {Number} group Group id (normally 0 -> user)
|
||||
* @return {Array} async (reply, err)
|
||||
*/
|
||||
methods.addUser = (nick, email, passhash, group, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof nick !== 'string') return callback(new TypeError('nick is not a string::database.addUser('+nick+','+email+','+passhash+','+group+',callback)', module.filename));
|
||||
if(typeof email !== 'string') return callback(new TypeError('email is not a string::database.addUser('+nick+','+email+','+passhash+','+group+',callback)', module.filename));
|
||||
if(typeof passhash !== 'string') return callback(new TypeError('passhash is not a string::database.addUser('+nick+','+email+','+passhash+','+group+',callback)', module.filename));
|
||||
if(isNaN(group)) return callback(new TypeError('group is not a number::database.addUser('+nick+','+email+','+passhash+','+group+',callback)', module.filename));
|
||||
methods.addUser = async (nick, email, passhash, group) => {
|
||||
if(typeof nick !== 'string') return {err: new TypeError('nick is not a string::database.addUser('+nick+','+email+','+passhash+','+group+')', module.filename)};
|
||||
if(typeof email !== 'string') return {err: new TypeError('email is not a string::database.addUser('+nick+','+email+','+passhash+','+group+')', module.filename)};
|
||||
if(typeof passhash !== 'string') return {err: new TypeError('passhash is not a string::database.addUser('+nick+','+email+','+passhash+','+group+')', module.filename)};
|
||||
if(isNaN(group)) return {err: new TypeError('group is not a number::database.addUser('+nick+','+email+','+passhash+','+group+')', module.filename)};
|
||||
|
||||
let userModel = models.user;
|
||||
|
||||
|
@ -69,70 +81,70 @@ methods.addUser = (nick, email, passhash, group, callback) => {
|
|||
user.passhash = sanitize(passhash);
|
||||
user.group = sanitize(group);
|
||||
|
||||
user.save((err) => {
|
||||
if(!err) callback(null, 1);
|
||||
else callback(err);
|
||||
});
|
||||
try {
|
||||
reply = await user.save();
|
||||
return {reply: 1};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes User from Database
|
||||
* deletes user identified by haystack from database
|
||||
* @author Ruben Meyer
|
||||
* @TODO
|
||||
* @async
|
||||
* @TODO add functionality
|
||||
* @param {String} haystack email or nick
|
||||
* @param {Function} callback Callback function (error, reply)
|
||||
* @return {Array} async(reply, err)
|
||||
*/
|
||||
methods.delUser = (haystack, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof haystack !== 'string') return callback(new TypeError('haystack is not a string::database.delUser('+haystack+',callback)', module.filename));
|
||||
methods.delUser = async (haystack) => {
|
||||
if(typeof haystack !== 'string') return {err: new TypeError('haystack is not a string::database.delUser('+haystack+')', module.filename)};
|
||||
|
||||
let userModel = models.user;
|
||||
|
||||
// sanitize input
|
||||
haystack = sanitize(haystack);
|
||||
|
||||
userModel.findOneAndDelete().or([{nickname: haystack}, {email: haystack}])
|
||||
.then((rep) => {
|
||||
// TODO delete user
|
||||
global['logs'].debug('deleted user: '+haystack);
|
||||
callback(null, 1);
|
||||
}).catch((err) => {
|
||||
callback(err);
|
||||
});
|
||||
try {
|
||||
reply = await userModel.findOneAndDelete().or([{nickname: haystack}, {email: haystack}]).exec();
|
||||
log.debug('deleted user: '+haystack);
|
||||
return {reply: 1};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* get all users
|
||||
* @author Ruben Meyer
|
||||
* @param {Function} callback Callback function (reply -> Array users)
|
||||
* @async
|
||||
* @return {Array} async(reply, err)
|
||||
*/
|
||||
methods.getUsers = (callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
|
||||
methods.getUsers = async () => {
|
||||
let userModel = models.user;
|
||||
|
||||
userModel.find({})
|
||||
.then((users) => {
|
||||
try {
|
||||
users = await userModel.find({}).exec();
|
||||
if(users.length > 0)
|
||||
return callback(null, users);
|
||||
return {reply: users};
|
||||
else
|
||||
return callback(null, false);
|
||||
}).catch((err) => {
|
||||
return callback(err);
|
||||
});
|
||||
return {reply: false};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* query users by email, nickname or rememberme token
|
||||
* query users by UUID, email, nickname or rememberme token
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @param {String|String[]} haystack email or nick
|
||||
* @param {Function} callback Callback function (reply -> Array users)
|
||||
* @return async(reply, err)
|
||||
*/
|
||||
methods.getUser = (haystack, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof haystack !== 'string' && typeof haystack !== 'object') return callback(new TypeError('email or nickname is not a string|object::database.getUser('+haystack+',callback)', module.filename));
|
||||
methods.getUser = async (haystack) => {
|
||||
if(typeof haystack !== 'string' && typeof haystack !== 'object') return {err: new TypeError('email or nickname is not a string|object::database.getUser('+haystack+')', module.filename)};
|
||||
|
||||
let userModel = models.user;
|
||||
|
||||
|
@ -154,35 +166,39 @@ methods.getUser = (haystack, callback) => {
|
|||
}
|
||||
}
|
||||
|
||||
userModel.find().or(or)
|
||||
.then((users) => {
|
||||
try {
|
||||
users = await userModel.find().or(or).exec();
|
||||
|
||||
if(users.length > 0)
|
||||
return callback(null, users);
|
||||
return {reply: users};
|
||||
else
|
||||
return callback(null, false);
|
||||
}).catch((err) => {
|
||||
return callback(err);
|
||||
});
|
||||
return {reply: false};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* updates obj keys in user entry
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @param {Number} id User ID
|
||||
* @param {Object} obj data
|
||||
* @param {Function} callback Callback function
|
||||
* @return {Array} async(reply, err)
|
||||
*/
|
||||
methods.updateUser = (id, obj, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof id !== 'string') return callback(new TypeError('id is not a string::database.updateUser('+id+','+JSON.stringify(obj)+',callback)', module.filename));
|
||||
if(typeof obj !== 'object') return callback(new TypeError('obj is not an object::database.updateUser('+id+','+JSON.stringify(obj)+',callback)', module.filename));
|
||||
methods.updateUser = async (id, obj) => {
|
||||
if(typeof id !== 'string') return {err: new TypeError('id is not a string::database.updateUser('+id+','+JSON.stringify(obj)+')', module.filename)};
|
||||
if(typeof obj !== 'object') return {err: new TypeError('obj is not an object::database.updateUser('+id+','+JSON.stringify(obj)+')', module.filename)};
|
||||
|
||||
let userModel = models.user;
|
||||
userModel.findByIdAndUpdate(id, obj, (err, data) => {
|
||||
if(err) callback(err);
|
||||
else callback(null, data);
|
||||
});
|
||||
|
||||
try {
|
||||
data = await userModel.findByIdAndUpdate(id, obj).exec();
|
||||
return {data: data};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@ -190,43 +206,49 @@ methods.updateUser = (id, obj, callback) => {
|
|||
/**
|
||||
* updates data based on login
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @TODO UPDATE METHOD; PROBABLY OUTDATED
|
||||
* @param {Number} id User ID
|
||||
* @param {Object} data data JSON -> remember
|
||||
* @param {Function} callback Callback function (date => 'Login Date', token => 'RememberMe Cookie Token')
|
||||
* @return {Array} async({date => 'Login Date', token => 'RememberMe Cookie Token'}, err)
|
||||
*/
|
||||
methods.addActivity = (id, data, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof id !== 'string') return callback(new TypeError('id is not a string::database.updateNewAction('+id+','+JSON.stringify(options)+',callback)', module.filename));
|
||||
if(typeof options !== 'object' && options !== null) return callback(new TypeError('obj is not an object::database.updateUserProfile('+id+','+JSON.stringify(obj)+',callback)', module.filename));
|
||||
methods.addActivity = async (id, data) => {
|
||||
if(typeof id !== 'string') return {err: new TypeError('id is not a string::database.updateNewAction('+id+','+JSON.stringify(options)+')', module.filename)};
|
||||
if(typeof options !== 'object' && options !== null) return {err: new TypeError('obj is not an object::database.updateUserProfile('+id+','+JSON.stringify(obj)+')', module.filename)};
|
||||
|
||||
let date = new Date().toISOString();
|
||||
let timestamp = new Date(date).getTime();
|
||||
|
||||
functions.updateUserProfile(id, {
|
||||
last_action: date
|
||||
}, (err, rep) => {
|
||||
if(err) return callback(err);
|
||||
try {
|
||||
reply = await methods.updateUser(id, {
|
||||
last_action: date
|
||||
});
|
||||
|
||||
if(options.rememberme && options.new_token !== false) {
|
||||
var token = ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, (c) => (c ^ crypto.randomBytes(new Uint8Array(1).length)[0] & 15 >> c / 4).toString(16));
|
||||
|
||||
var Remember = models.remember;
|
||||
Remember.findOneAndUpdate({userId: id}, {token: token, timestamp: Date.now()}, {upsert: true}, (err1, data) => {
|
||||
if(err1) callback(err1);
|
||||
return callback(null, {
|
||||
|
||||
try {
|
||||
data = await Remember.findOneAndUpdate({userId: id}, {token: token, timestamp: Date.now()}, {upsert: true}).exec();
|
||||
return {reply: {
|
||||
date: date,
|
||||
timestamp: timestamp,
|
||||
token: token
|
||||
});
|
||||
});
|
||||
}};
|
||||
}
|
||||
catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
} else {
|
||||
callback(null, {
|
||||
return {reply: {
|
||||
date: date,
|
||||
timestamp: timestamp,
|
||||
token: options.old_token
|
||||
});
|
||||
}};
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -241,27 +263,28 @@ methods.addActivity = (id, data, callback) => {
|
|||
/**
|
||||
* get Applications
|
||||
* @author Ruben Meyer
|
||||
* @param {Function} callback Callback function (err, apps)
|
||||
* @async
|
||||
* @return {Array} async(apps, err)
|
||||
*/
|
||||
methods.getApps = (callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
methods.getApps = async () => {
|
||||
var Application = models.application;
|
||||
|
||||
Application.find({}, (err, apps) => {
|
||||
if(err) callback(err);
|
||||
else callback(null, apps);
|
||||
});
|
||||
try {
|
||||
apps = await Application.find({}).exec();
|
||||
return {reply: apps};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* return auth obj
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @param {Object} obj data obj (aId, uId)
|
||||
* @param {Function} callback Callback function (err, obj) obj -> (aId, uId, token)
|
||||
* @return {Array} async({timestamp, token}, err)
|
||||
*/
|
||||
methods.setAuthCode = (obj, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof obj !== 'object') return callback(new TypeError('obj is not an object::database.setAuthCode('+JSON.stringify(obj)+',callback)', module.filename));
|
||||
methods.setAuthCode = async (obj) => {
|
||||
if(typeof obj !== 'object') return {err: new TypeError('obj is not an object::database.setAuthCode('+JSON.stringify(obj)+')', module.filename)};
|
||||
|
||||
|
||||
var AuthCode = models.authCode;
|
||||
|
@ -275,74 +298,80 @@ methods.setAuthCode = (obj, callback) => {
|
|||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
AuthCode.findOneAndUpdate(query, change, {upsert: true}, (err1, data) => {
|
||||
if(err1) callback(err1);
|
||||
return callback(null, {
|
||||
try {
|
||||
data = await AuthCode.findOneAndUpdate(query, change, {upsert: true}).exec();
|
||||
return {reply: {
|
||||
timestamp: change.timestamp,
|
||||
token: change.token
|
||||
});
|
||||
});
|
||||
}};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* return auth obj
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @param {Object} obj data obj (aId, aSecret, uId, token)
|
||||
* @param {Function} callback Callback function (err, bool)
|
||||
* @return {Array} async(bool, err)
|
||||
*/
|
||||
methods.getAuth = (obj, callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
if(typeof obj !== 'object') return callback(new TypeError('obj is not an object::database.getAuthCode('+JSON.stringify(obj)+',callback)', module.filename));
|
||||
methods.getAuth = async (obj) => {
|
||||
if(typeof obj !== 'object') return {err: new TypeError('obj is not an object::database.getAuthCode('+JSON.stringify(obj)+')', module.filename)};
|
||||
|
||||
var AuthCode = models.authCode;
|
||||
AuthCode.findOne({
|
||||
$and: [
|
||||
{applicationId: mongoose.Types.ObjectId(obj.aId)},
|
||||
{userId: mongoose.Types.ObjectId(obj.uId)},
|
||||
{token: obj.token}
|
||||
]
|
||||
}, (err, data) => {
|
||||
if(err) callback(err);
|
||||
else {
|
||||
if(typeof data === "object") {
|
||||
if(data === null || data === []) return callback(null, false);
|
||||
var Application = models.application;
|
||||
|
||||
Application.findOne({
|
||||
try {
|
||||
data = await AuthCode.findOne({
|
||||
$and: [
|
||||
{applicationId: mongoose.Types.ObjectId(obj.aId)},
|
||||
{userId: mongoose.Types.ObjectId(obj.uId)},
|
||||
{token: obj.token}
|
||||
]
|
||||
}).exec();
|
||||
|
||||
if(typeof data === "object") {
|
||||
if(data === null || data === []) return {reply: false};
|
||||
var Application = models.application;
|
||||
|
||||
try {
|
||||
data1 = await Application.findOne({
|
||||
$and: [
|
||||
{_id: mongoose.Types.ObjectId(obj.aId)},
|
||||
{secret: obj.aSecret}
|
||||
]
|
||||
}, (err1, data1) => {
|
||||
if(err1) callback(err1);
|
||||
else {
|
||||
if(obj.token == data.token
|
||||
&& obj.aId == String(data.applicationId)
|
||||
&& obj.uId == String(data.userId)
|
||||
&& obj.aSecret == data1.secret) {
|
||||
callback(null, true);
|
||||
//functions.setAuthCode({
|
||||
// aId: obj.aId,
|
||||
// uId: obj.uId
|
||||
//}, () => {});
|
||||
}
|
||||
else callback(null, false);
|
||||
}
|
||||
});
|
||||
} else callback(null, false);
|
||||
}
|
||||
});
|
||||
}).exec();
|
||||
|
||||
if(obj.token == data.token
|
||||
&& obj.aId == String(data.applicationId)
|
||||
&& obj.uId == String(data.userId)
|
||||
&& obj.aSecret == data1.secret) {
|
||||
return {reply: true};
|
||||
//methods.setAuthCode({
|
||||
// aId: obj.aId,
|
||||
// uId: obj.uId
|
||||
//});
|
||||
}
|
||||
else return{reply: false};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
} else return {reply: false};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* return if app is permitted to do access call
|
||||
* @author Ruben Meyer
|
||||
* @async
|
||||
* @param {Object} obj data obj (aId, redirectUrl)
|
||||
* @param {Function} callback Callback function (err, bool)
|
||||
* @return {Array} async(bool, err)
|
||||
*/
|
||||
methods.verifyAppCall = (obj, callback) => {
|
||||
|
||||
methods.verifyAppCall = async (obj) => {
|
||||
return {};
|
||||
};
|
||||
|
||||
// //////// //////// //////// //////// ////////
|
||||
|
@ -354,17 +383,20 @@ methods.verifyAppCall = (obj, callback) => {
|
|||
////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* callback with user count
|
||||
* returns user count
|
||||
* @author Ruben Meyer
|
||||
* @param {Function} callback Callback function (reply -> int)
|
||||
* @async
|
||||
* @return {Array} async(int, err)
|
||||
*/
|
||||
methods.userCount = (callback) => {
|
||||
if(typeof callback !== 'function') callback = function() {};
|
||||
|
||||
methods.userCount = async () => {
|
||||
let userModel = models.user;
|
||||
userModel.countDocuments({}, (err, count) => {
|
||||
callback((err) ? err : count);
|
||||
});
|
||||
|
||||
try {
|
||||
count = await userModel.countDocuments({}).exec();
|
||||
return {reply: count};
|
||||
} catch(err) {
|
||||
return {err: err};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
// GCS: Global Communication System
|
||||
let EventEmitter = require('events');
|
||||
global['gcs'] = new EventEmitter.EventEmitter();
|
||||
global['event'] = new EventEmitter.EventEmitter();
|
||||
|
||||
/**
|
||||
* Error Message Handler
|
||||
|
@ -16,7 +16,7 @@ global['gcs'] = new EventEmitter.EventEmitter();
|
|||
* @param {String} message data: "MODULE SEPARATOR MESSAGE"
|
||||
* @return {void}
|
||||
*/
|
||||
global['gcs'].on('err', (data) => {
|
||||
global['event'].on('err', (data) => {
|
||||
separator = "->";
|
||||
i = data.indexOf(separator);
|
||||
parts = [data.slice(0, i), data.slice(i+separator.length)];
|
||||
|
|
|
@ -2,12 +2,13 @@ var methods = {};
|
|||
let fs = require('fs');
|
||||
let util = require('util');
|
||||
|
||||
var cfg = require(global['__dirname']+'/bin/config');
|
||||
|
||||
// save new line to file
|
||||
newLine = (prefix, obj) => {
|
||||
let date = new Date(); // current date
|
||||
let filename = global['gds'].cfg.log.filename(); // filename
|
||||
let dir = global['gds'].cfg.log.directory(); // directory
|
||||
let filename = cfg.log.filename(); // filename
|
||||
let dir = cfg.log.directory(); // directory
|
||||
let path = dir + filename; // filepath
|
||||
let fs_options = { // fs options for encoding, file mode and file flag
|
||||
encoding: "utf8",
|
||||
|
@ -46,7 +47,7 @@ newLine = (prefix, obj) => {
|
|||
}
|
||||
};
|
||||
|
||||
fallback = (fn, ...data) => {
|
||||
log = (fn, ...data) => {
|
||||
if(data.length == 1) data = data[0];
|
||||
|
||||
fn.apply(null, data);
|
||||
|
@ -55,8 +56,7 @@ fallback = (fn, ...data) => {
|
|||
|
||||
// LOG | INFO
|
||||
methods.log = (...data) => {
|
||||
if(global['modules'].cli) global['modules'].cli.log.apply(global['modules'].cli, data);
|
||||
else fallback(console.log, data);
|
||||
log(console.log, data);
|
||||
|
||||
if(data.length == 1) data = data[0];
|
||||
newLine(" [LOG]", data);
|
||||
|
@ -65,8 +65,7 @@ methods.info = methods.log;
|
|||
|
||||
// WARNING
|
||||
methods.warn = (...data) => {
|
||||
if(global['modules'].cli) global['modules'].cli.log.apply(global['modules'].cli, data);
|
||||
else fallback(console.warn, data);
|
||||
log(console.warn, data);
|
||||
|
||||
if(data.length == 1) data = data[0];
|
||||
newLine(" [WARN]", data);
|
||||
|
@ -74,8 +73,7 @@ methods.warn = (...data) => {
|
|||
|
||||
// ERROR
|
||||
methods.error = (...data) => {
|
||||
if(global['modules'].cli) global['modules'].cli.log.apply(global['modules'].cli, data);
|
||||
else fallback(console.error, data);
|
||||
log(console.error, data);
|
||||
|
||||
if(data.length == 1) data = data[0];
|
||||
newLine("[ERROR]", data);
|
||||
|
@ -85,8 +83,7 @@ methods.err = methods.error;
|
|||
// DEBUG
|
||||
methods.debug = (...data) => {
|
||||
if(global['gds'].debug) {
|
||||
if(global['modules'].cli) global['modules'].cli.log.apply(global['modules'].cli, data);
|
||||
else fallback(console.log, data);
|
||||
log(console.log, data);
|
||||
|
||||
if(data.length == 1) data = data[0];
|
||||
newLine("[DEBUG]", data);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
// init
|
||||
var methods = {};
|
||||
|
||||
var cfg = require(global['__dirname']+'/bin/config');
|
||||
|
||||
/**
|
||||
* start web server
|
||||
* @author Ruben Meyer
|
||||
|
@ -33,7 +35,7 @@ methods.start = () => {
|
|||
// Access Control Headers
|
||||
app.use( (req, res, next) => {
|
||||
res.set({
|
||||
'X-Powered-By': global['gds'].cfg.web.poweredBy
|
||||
'X-Powered-By': cfg.web.poweredBy
|
||||
});
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||
|
@ -50,6 +52,7 @@ methods.start = () => {
|
|||
// path already cached; not exist
|
||||
if(global['gds'].cache.web[joined_path] == false) {
|
||||
res.status(404).end();
|
||||
global['logs'].info("[web] (404) path not found: "+joined_path);
|
||||
// path already cached; exist
|
||||
} else if(global['gds'].cache.web[joined_path] == true){
|
||||
let contentType = mime.contentType(path.extname(joined_path));
|
||||
|
@ -66,6 +69,7 @@ methods.start = () => {
|
|||
fs.createReadStream(joined_path).pipe(res);
|
||||
} else {
|
||||
res.status(404).end();
|
||||
global['logs'].info("[web] (404) path not found: "+joined_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -76,7 +80,7 @@ methods.start = () => {
|
|||
app.use(bp.urlencoded({
|
||||
extended: true
|
||||
}));
|
||||
app.use(cp(global['gds'].cfg.web.cookieKey));
|
||||
app.use(cp(cfg.web.cookieKey));
|
||||
|
||||
// Pretty print
|
||||
if(app.get('env') === 'debug')
|
||||
|
@ -84,7 +88,7 @@ methods.start = () => {
|
|||
|
||||
// Sessions
|
||||
session_options = {
|
||||
secret: global['gds'].cfg.web.sessionKey,
|
||||
secret: cfg.web.sessionKey,
|
||||
resave: false,
|
||||
saveUninitialized: false, cookie: {}};
|
||||
if(app.get('env') === 'production') {
|
||||
|
@ -93,13 +97,19 @@ methods.start = () => {
|
|||
app.use(session_handler(session_options));
|
||||
|
||||
// web routes
|
||||
app.use('/', require(global['__dirname']+'/bin/web/routes/static'));
|
||||
app.use('/api', require(global['__dirname']+'/bin/web/routes/api'));
|
||||
(async function() {
|
||||
let mRoutes = require(global['__dirname']+'/bin/web/routes/static');
|
||||
let mainRoutes = await mRoutes.getRoutes();
|
||||
app.use('/', mainRoutes);
|
||||
let rAPI = require(global['__dirname']+'/bin/web/routes/api');
|
||||
let restAPI = await rAPI.getRoutes();
|
||||
app.use('/api', restAPI);
|
||||
|
||||
// start server
|
||||
app.listen(global['gds'].cfg.web.port, () => {
|
||||
global['modules'].logs.log("Server is listening on port: "+global['gds'].cfg.web.port);
|
||||
});
|
||||
// start server
|
||||
app.listen(cfg.web.port, () => {
|
||||
global['logs'].log("Server is listening on port: "+cfg.web.port);
|
||||
});
|
||||
})();
|
||||
};
|
||||
|
||||
module.exports = methods;
|
||||
|
|
|
@ -6,57 +6,64 @@
|
|||
|
||||
var express = require('express');
|
||||
var route = express.Router();
|
||||
asyncer = require('express-async-handler');
|
||||
|
||||
/**
|
||||
* register a user; currently not implemented
|
||||
* @url /register
|
||||
* @method POST
|
||||
*/
|
||||
route.post('/register', (req, res) => {
|
||||
// if registration is disabled
|
||||
if(!global['app'].cfg.web.registration) {
|
||||
return res.type('json').status(400).end(JSON.stringify({status: 400, message: "msg.auth.registration.deactivated"}));
|
||||
} else {
|
||||
// am i rite?
|
||||
return res.type('json').status(200).end(JSON.stringify({}));
|
||||
}
|
||||
});
|
||||
getRoutes = async () => {
|
||||
let db = global['requireModule']('database');
|
||||
await db.connect();
|
||||
|
||||
/**
|
||||
* login a user
|
||||
* @url /api/login
|
||||
* @method POST
|
||||
* @POST ['email', 'password']
|
||||
* @TODO add new activity 'action.user.login'
|
||||
*/
|
||||
route.post('/login', (req, res) => {
|
||||
// if user is logged in (existing session); FAIL
|
||||
if(req.session.user) {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.logout.required'
|
||||
}));
|
||||
}
|
||||
|
||||
// check body variables
|
||||
if(!req.body.email || !req.body.password) {
|
||||
return res.type('json').status(401).end(JSON.stringify({
|
||||
status: 401,
|
||||
message: [
|
||||
'msg.request.data.missing',
|
||||
'msg.auth.login.failed'
|
||||
]
|
||||
}));
|
||||
}
|
||||
let email = req.body.email;
|
||||
let pass = req.body.password;
|
||||
/**
|
||||
* register a user; currently not implemented
|
||||
* @url /register
|
||||
* @method POST
|
||||
*/
|
||||
route.post('/register', (req, res) => {
|
||||
// if registration is disabled
|
||||
if(!global['app'].cfg.web.registration) {
|
||||
return res.type('json').status(400).end(JSON.stringify({status: 400, message: "msg.auth.registration.deactivated"}));
|
||||
} else {
|
||||
// am i rite?
|
||||
return res.type('json').status(200).end(JSON.stringify({}));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* login a user
|
||||
* @url /api/login
|
||||
* @method POST
|
||||
* @POST ['email', 'password']
|
||||
* @TODO add new activity 'action.user.login'
|
||||
*/
|
||||
route.post('/login', asyncer(async (req, res) => {
|
||||
// if user is logged in (existing session); FAIL
|
||||
if(req.session.user) {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.logout.required'
|
||||
}));
|
||||
}
|
||||
|
||||
// check body variables
|
||||
if(!req.body.email || !req.body.password) {
|
||||
return res.type('json').status(401).end(JSON.stringify({
|
||||
status: 401,
|
||||
message: [
|
||||
'msg.request.data.missing',
|
||||
'msg.auth.login.failed'
|
||||
]
|
||||
}));
|
||||
}
|
||||
let email = req.body.email;
|
||||
let pass = req.body.password;
|
||||
|
||||
// database query: get user by email
|
||||
user = await db.getUser(email);
|
||||
|
||||
// database query: get user by email
|
||||
global['modules'].database.getUser(email, (err, rep) => {
|
||||
// if database error
|
||||
if(err) {
|
||||
if(user.err) {
|
||||
// log error while debugging
|
||||
global['logs'].debug(err);
|
||||
global['logs'].debug(user.err);
|
||||
|
||||
// login failed because of database error
|
||||
return res.type('json').status(500).end(JSON.stringify({
|
||||
|
@ -69,7 +76,7 @@ route.post('/login', (req, res) => {
|
|||
}
|
||||
|
||||
// no reply (user does not exist) or password is wrong
|
||||
if(!rep || rep === null || rep.length == 0 || rep.length > 1 || !global['modules'].auth.validateHash(rep[0].passhash, pass)) {
|
||||
if(!user.reply || user.reply === null || user.reply.length == 0 || user.reply.length > 1 || !global['requireModule']('auth').validateHash(user.reply[0].passhash, pass)) {
|
||||
return res.type('json').status(401).end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.failed'
|
||||
|
@ -81,8 +88,8 @@ route.post('/login', (req, res) => {
|
|||
|
||||
// add session data
|
||||
req.session.user = {
|
||||
'id': rep[0]._id,
|
||||
'group': rep[0].group
|
||||
'id': user.reply[0]._id,
|
||||
'group': user.reply[0].group
|
||||
};
|
||||
|
||||
return res.type('json').end(JSON.stringify({
|
||||
|
@ -91,71 +98,72 @@ route.post('/login', (req, res) => {
|
|||
type: 'form' // TODO: types - { form, access_app}
|
||||
}));
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
/**
|
||||
* apps verify token
|
||||
* @url /api/authenticate
|
||||
* @method POST
|
||||
* @POST ['applicationId', 'applicationSecret', 'userId', 'token']
|
||||
* @TODO add implementation
|
||||
*/
|
||||
route.post('/authenticate', (req, res) => {
|
||||
// TODO: authenticate
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* apps verify token
|
||||
* @url /api/authenticate
|
||||
* @method POST
|
||||
* @POST ['applicationId', 'applicationSecret', 'userId', 'token']
|
||||
* @TODO add implementation
|
||||
*/
|
||||
route.post('/authenticate', (req, res) => {
|
||||
// TODO: authenticate
|
||||
});
|
||||
/**
|
||||
* cancel app request and clear it
|
||||
* @url /api/cancel
|
||||
* @method GET
|
||||
*/
|
||||
route.get('/cancel', (req, res) => {
|
||||
// if user is logged in
|
||||
if(req.session && req.session.user) {
|
||||
req.session.appRequest = {};
|
||||
|
||||
/**
|
||||
* cancel app request and clear it
|
||||
* @url /api/cancel
|
||||
* @method GET
|
||||
*/
|
||||
route.get('/cancel', (req, res) => {
|
||||
// if user is logged in
|
||||
if(req.session && req.session.user) {
|
||||
req.session.appRequest = {};
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 200,
|
||||
message: 'msg.request.operation.cancel.successful'
|
||||
}));
|
||||
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 200,
|
||||
message: 'msg.request.operation.cancel.successful'
|
||||
}));
|
||||
|
||||
// user isnt logged in
|
||||
} else {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.required'
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* redirect user to app
|
||||
* @url /api/redirect
|
||||
* @method GET
|
||||
* @GET ['id']
|
||||
*/
|
||||
route.get('/redirect', (req, res) => {
|
||||
// if user is logged in
|
||||
if(req.session && req.session.user) {
|
||||
// missing query data to retrieve app
|
||||
if(!req.query || !req.query.id) {
|
||||
return res.type('json').status(500).end(JSON.stringify({
|
||||
status: 500,
|
||||
message: [
|
||||
'msg.request.data.missing'
|
||||
]
|
||||
// user isnt logged in
|
||||
} else {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.required'
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* redirect user to app
|
||||
* @url /api/redirect
|
||||
* @method GET
|
||||
* @GET ['id']
|
||||
*/
|
||||
route.get('/redirect', asyncer(async (req, res) => {
|
||||
// if user is logged in
|
||||
if(req.session && req.session.user) {
|
||||
// missing query data to retrieve app
|
||||
if(!req.query || !req.query.id) {
|
||||
return res.type('json').status(500).end(JSON.stringify({
|
||||
status: 500,
|
||||
message: [
|
||||
'msg.request.data.missing'
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
// set auth code
|
||||
authCode = await db.setAuthCode({
|
||||
aId: req.query.id,
|
||||
uId: req.session.user.id
|
||||
});
|
||||
|
||||
// set auth code
|
||||
global['modules'].database.setAuthCode({
|
||||
aId: req.query.id,
|
||||
uId: req.session.user.id
|
||||
}, (err, rep) => {
|
||||
// database error
|
||||
if(err) {
|
||||
global['logs'].debug(err);
|
||||
if(authCode.err) {
|
||||
global['logs'].debug(authCode[1]);
|
||||
return res.type('json').status(500).end(JSON.stringify({
|
||||
status: 500,
|
||||
message: [
|
||||
|
@ -165,25 +173,24 @@ route.get('/redirect', (req, res) => {
|
|||
}
|
||||
else if(rep) {
|
||||
// retrieve apps
|
||||
global['modules'].database.getApps((err2, rep2) => {
|
||||
// database error
|
||||
if(err2) {
|
||||
global['logs'].debug(err2);
|
||||
return res.type('json').status(500).end(JSON.stringify({
|
||||
status: 500,
|
||||
message: [
|
||||
'msg.database.error'
|
||||
]
|
||||
}));
|
||||
apps = await db.getApps();
|
||||
// database error
|
||||
if(apps.reply) {
|
||||
global['logs'].debug(apps.err);
|
||||
return res.type('json').status(500).end(JSON.stringify({
|
||||
status: 500,
|
||||
message: [
|
||||
'msg.database.error'
|
||||
]
|
||||
}));
|
||||
}
|
||||
// for each app
|
||||
apps.reply.forEach((app) => {
|
||||
// if app.id is equal to queried app
|
||||
if(app.id == req.query.id) {
|
||||
// redirect to app
|
||||
return res.redirect(app.access+"?uid="+req.session.user.id+"&token="+rep.token);
|
||||
}
|
||||
// for each app
|
||||
rep2.forEach((app) => {
|
||||
// if app.id is equal to queried app
|
||||
if(app.id == req.query.id) {
|
||||
// redirect to app
|
||||
return res.redirect(app.access+"?uid="+req.session.user.id+"&token="+rep.token);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// database error
|
||||
|
@ -194,47 +201,51 @@ route.get('/redirect', (req, res) => {
|
|||
]
|
||||
}));
|
||||
}
|
||||
});
|
||||
// user isnt logged in
|
||||
} else {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.required'
|
||||
}));
|
||||
}
|
||||
});
|
||||
// user isnt logged in
|
||||
} else {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.required'
|
||||
}));
|
||||
}
|
||||
}));
|
||||
|
||||
/**
|
||||
* logout user
|
||||
* @url /api/logout
|
||||
* @method GET
|
||||
*/
|
||||
route.get('/logout', (req, res) => {
|
||||
// user needs to be logged in
|
||||
if(!req.session || !req.session.user) {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.required'
|
||||
}));
|
||||
// logout user
|
||||
} else {
|
||||
res.clearCookie('RememberMe');
|
||||
req.session.destroy();
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 200,
|
||||
message: 'msg.auth.logout.successful'
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
if(global['gds'].debug) {
|
||||
// DEBUG info
|
||||
route.get('/info', (req, res) => {
|
||||
let obj = {};
|
||||
if(req.session) obj.session = req.session;
|
||||
if(req.cookies) obj.cookie = req.cookies;
|
||||
res.type('json').end(JSON.stringify(obj));
|
||||
/**
|
||||
* logout user
|
||||
* @url /api/logout
|
||||
* @method GET
|
||||
*/
|
||||
route.get('/logout', (req, res) => {
|
||||
// user needs to be logged in
|
||||
if(!req.session || !req.session.user) {
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 401,
|
||||
message: 'msg.auth.login.required'
|
||||
}));
|
||||
// logout user
|
||||
} else {
|
||||
res.clearCookie('RememberMe');
|
||||
req.session.destroy();
|
||||
return res.type('json').end(JSON.stringify({
|
||||
status: 200,
|
||||
message: 'msg.auth.logout.successful'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = route;
|
||||
if(global['gds'].debug) {
|
||||
// DEBUG info
|
||||
route.get('/info', (req, res) => {
|
||||
let obj = {};
|
||||
if(req.session) obj.session = req.session;
|
||||
if(req.cookies) obj.cookie = req.cookies;
|
||||
res.type('json').end(JSON.stringify(obj));
|
||||
});
|
||||
}
|
||||
|
||||
return route;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getRoutes: getRoutes
|
||||
};
|
||||
|
|
|
@ -4,12 +4,16 @@
|
|||
* (c) Ruben Meyer <contact@rxbn.de>
|
||||
*/
|
||||
|
||||
var express = require('express');
|
||||
var route = express.Router();
|
||||
express = require('express');
|
||||
route = express.Router();
|
||||
asyncer = require('express-async-handler');
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
|
||||
|
||||
|
||||
// reduce IO file checks - save file state in cache
|
||||
var fileCheck = (file) => {
|
||||
if(typeof global['gds'].cache.web == 'undefined') global['gds'].cache.web = {};
|
||||
let dir = global['__dirname'] + '/bin/web/views';
|
||||
|
@ -29,37 +33,41 @@ var fileCheck = (file) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* main page
|
||||
* @url /
|
||||
* @method all
|
||||
*/
|
||||
route.all('/', function(req, res, next) {
|
||||
// TODO: show login page or dashboard
|
||||
// res.end('login or dashboard');
|
||||
global['modules'].database.getApps((err, rep) => {
|
||||
let getRoutes = async () => {
|
||||
let db = global['requireModule']('database');
|
||||
await db.connect();
|
||||
|
||||
/**
|
||||
* main page
|
||||
* @url /
|
||||
* @method all
|
||||
*/
|
||||
route.all('/', asyncer(async (req, res, next) => {
|
||||
// TODO: show login page or dashboard
|
||||
// res.end('login or dashboard');
|
||||
apps = await db.getApps();
|
||||
res.render('index', {
|
||||
session: req.session,
|
||||
apps: rep
|
||||
apps: apps.reply
|
||||
});
|
||||
})
|
||||
});
|
||||
}));
|
||||
|
||||
/**
|
||||
* login page or apprequest page
|
||||
* @url /
|
||||
* @method GET
|
||||
*/
|
||||
route.get('/authenticate', (req, res) => {
|
||||
/**
|
||||
* login page or apprequest page
|
||||
* @url /
|
||||
* @method GET
|
||||
*/
|
||||
route.get('/authenticate', asyncer(async (req, res) => {
|
||||
|
||||
if(req.session) {
|
||||
// if there isnt an apprequest
|
||||
if(!req.session.appRequest)
|
||||
req.session.appRequest = {}; // TODO: data
|
||||
}
|
||||
if(req.session) {
|
||||
// if there isnt an apprequest
|
||||
if(!req.session.appRequest)
|
||||
req.session.appRequest = {}; // TODO: data
|
||||
}
|
||||
|
||||
// query apps
|
||||
apps = await db.getApps();
|
||||
|
||||
// query apps
|
||||
global['modules'].database.getApps((err, rep) => {
|
||||
// set appId in appRequest
|
||||
if(req.query.appId) {
|
||||
if(req.query.appId && typeof req.query.appId == "string") {
|
||||
|
@ -77,7 +85,7 @@ route.get('/authenticate', (req, res) => {
|
|||
res.render('request', {
|
||||
session: req.session,
|
||||
appRequest: req.session.appRequest,
|
||||
apps: rep
|
||||
apps: apps.reply
|
||||
});
|
||||
// if user isnt logged in, show login page
|
||||
} else {
|
||||
|
@ -85,7 +93,7 @@ route.get('/authenticate', (req, res) => {
|
|||
|
||||
let view_obj = { session: req.session };
|
||||
if(req.query.appId) {
|
||||
rep.forEach((app) => {
|
||||
apps.reply.forEach((app) => {
|
||||
if(app._id == req.query.appId)
|
||||
view_obj["login_title"] = "Login to use "+app.name+" via authRxbn"; // appRequest app name
|
||||
})
|
||||
|
@ -94,78 +102,84 @@ route.get('/authenticate', (req, res) => {
|
|||
|
||||
res.render('login', view_obj);
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
/**
|
||||
* all other routes
|
||||
* @url /*
|
||||
* @method all
|
||||
* @TODO comments
|
||||
*/
|
||||
route.all('/*', (req, res, next) => {
|
||||
// passthrough to next route
|
||||
if(req.path.startsWith('/api'))
|
||||
return next();
|
||||
/**
|
||||
* all other routes
|
||||
* @url /*
|
||||
* @method all
|
||||
* @TODO comments
|
||||
*/
|
||||
route.all('/*', (req, res, next) => {
|
||||
// passthrough to next route
|
||||
if(req.path.startsWith('/api'))
|
||||
return next();
|
||||
|
||||
if(req.path == "/request") return res.render('error/404');
|
||||
if(req.path == "/request") return res.render('error/404');
|
||||
|
||||
let pathRules = require("./rules");
|
||||
let pathRules = require("./rules");
|
||||
|
||||
let group = "anon";
|
||||
if(req.session && req.session.user) {
|
||||
group = "user";
|
||||
if(req.session.user.group == 999) group = "admin";
|
||||
}
|
||||
let group = "anon";
|
||||
if(req.session && req.session.user) {
|
||||
group = "user";
|
||||
if(req.session.user.group == 999) group = "admin";
|
||||
}
|
||||
|
||||
pathRules.forEach((rule) => {
|
||||
if(rule.rule == "block") {
|
||||
if(group == rule.group) {
|
||||
let regex = new RegExp(rule.expression, "g");
|
||||
if(regex.test(req.path)) {
|
||||
if(rule.type == "404") {
|
||||
return res.status(404).render('error/404', {
|
||||
error_code: 404,
|
||||
error_msg: 'msg.request.file.not_found',
|
||||
session: req.session
|
||||
});
|
||||
} else if(rule.type == "missing_permission") {
|
||||
return res.status(401).render('error/permission', {
|
||||
error_code: 401,
|
||||
session: req.session
|
||||
});
|
||||
} else if(rule.type == "login") {
|
||||
return res.status(401).render('error/login', {
|
||||
error_code: 401,
|
||||
session: req.session
|
||||
});
|
||||
} else {
|
||||
return res.status(401).render('error/error', {
|
||||
error_code: 401,
|
||||
session: req.session
|
||||
});
|
||||
pathRules.forEach((rule) => {
|
||||
if(rule.rule == "block") {
|
||||
if(group == rule.group) {
|
||||
let regex = new RegExp(rule.expression, "g");
|
||||
if(regex.test(req.path)) {
|
||||
if(rule.type == "404") {
|
||||
global['logs'].info("[web] (404) path not found: "+req.path);
|
||||
return res.status(404).render('error/404', {
|
||||
error_code: 404,
|
||||
error_msg: 'msg.request.file.not_found',
|
||||
session: req.session
|
||||
});
|
||||
} else if(rule.type == "missing_permission") {
|
||||
return res.status(401).render('error/permission', {
|
||||
error_code: 401,
|
||||
session: req.session
|
||||
});
|
||||
} else if(rule.type == "login") {
|
||||
return res.status(401).render('error/login', {
|
||||
error_code: 401,
|
||||
session: req.session
|
||||
});
|
||||
} else {
|
||||
return res.status(401).render('error/error', {
|
||||
error_code: 401,
|
||||
session: req.session
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(fileCheck(req.path)) {
|
||||
return res.render(req.path.replace(/^\//, ''), {
|
||||
session: req.session,
|
||||
cfg: global['gds'].cfg
|
||||
});
|
||||
} else {
|
||||
global['logs'].info("[web] (404) path not found: "+req.path);
|
||||
return res.status(404).render('error/404', {
|
||||
error_code: 404,
|
||||
error_msg: 'msg.request.file.not_found',
|
||||
session: req.session
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: try to login
|
||||
// TODO: role-based authorization
|
||||
// TODO: show login page or page
|
||||
});
|
||||
|
||||
if(fileCheck(req.path)) {
|
||||
return res.render(req.path.replace(/^\//, ''), {
|
||||
session: req.session,
|
||||
cfg: global['gds'].cfg
|
||||
});
|
||||
} else {
|
||||
return res.status(404).render('error/404', {
|
||||
error_code: 404,
|
||||
error_msg: 'msg.request.file.not_found',
|
||||
session: req.session
|
||||
});
|
||||
}
|
||||
return route;
|
||||
};
|
||||
|
||||
// TODO: try to login
|
||||
// TODO: role-based authorization
|
||||
// TODO: show login page or page
|
||||
});
|
||||
|
||||
module.exports = route;
|
||||
module.exports = {
|
||||
getRoutes: getRoutes
|
||||
};
|
||||
|
|
13
package.json
13
package.json
|
@ -7,13 +7,12 @@
|
|||
"license": "",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cookie-parser": "^1.4.4",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.16.1",
|
||||
"mongo-sanitize": "^1.0.1",
|
||||
"mongoose": "^5.5.12",
|
||||
"pug": "^2.0.3",
|
||||
"vorpal": "^1.12.0"
|
||||
"express-async-handler": "^1.1.4",
|
||||
"express-session": "^1.17.1",
|
||||
"mongo-sanitize": "^1.1.0",
|
||||
"mongoose": "^5.9.28",
|
||||
"pug": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue