2019-06-23 21:27:52 +00:00
/ *
* This file is part of the authRxbn eco - system .
*
* ( c ) Ruben Meyer < contact @ rxbn . de >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
* /
// init
var mongoose = require ( 'mongoose' ) ;
2020-02-29 20:16:48 +00:00
var sanitize = require ( 'mongo-sanitize' ) ;
2019-06-23 21:27:52 +00:00
var crypto = require ( 'crypto' ) ;
var methods = { } ;
2020-08-14 11:20:19 +00:00
var log = require ( global [ '__dirname' ] + '/bin/logs/module' ) ;
var cfg = require ( global [ '__dirname' ] + '/bin/config' ) ;
2019-06-23 21:27:52 +00:00
2020-08-14 11:20:19 +00:00
var db ;
2019-06-23 21:27:52 +00:00
var mdls = require ( './models.js' ) ;
2020-08-14 11:20:19 +00:00
var models ;
2019-06-23 21:27:52 +00:00
2020-08-14 11:20:19 +00:00
/ * *
* connects to db
* @ author Ruben Meyer
* @ async
* /
methods . connect = async ( ) => {
if ( typeof db !== "undefined" ) return ;
// connect
mongoose . connect ( cfg . mongoose . uri , {
useNewUrlParser : true ,
useUnifiedTopology : true ,
useFindAndModify : false
} ) ;
2019-06-23 21:27:52 +00:00
2020-08-14 11:20:19 +00:00
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
} ) ;
}
2019-06-23 21:27:52 +00:00
2020-08-17 11:57:10 +00:00
/ * *
* returns db instance
* @ author Ruben Meyer
* @ return { Object } mongoose
* /
methods . getConnection = ( ) => {
return db ;
}
2019-06-23 21:27:52 +00:00
// // // //////// //////// ///////
// // // // // // //
// // // ////// ////// //////
// // // // // // //
// //////// ////// //////// // //
//
/////////////////////////////////////////////
/ * *
* Adds User to Database
2020-08-14 11:20:19 +00:00
* @ 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 )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
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 ) } ;
2019-06-23 21:27:52 +00:00
2019-09-01 19:29:36 +00:00
let userModel = models . user ;
2019-06-23 21:27:52 +00:00
2019-09-01 19:29:36 +00:00
let user = new userModel ( ) ;
2020-02-29 20:16:48 +00:00
user . nickname = sanitize ( nick ) ;
user . email = sanitize ( email ) ;
user . passhash = sanitize ( passhash ) ;
user . group = sanitize ( group ) ;
2019-06-23 21:27:52 +00:00
2020-08-14 11:20:19 +00:00
try {
reply = await user . save ( ) ;
return { reply : 1 } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
2020-08-14 11:20:19 +00:00
* deletes user identified by haystack from database
2019-06-23 21:27:52 +00:00
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
* @ TODO add functionality
2019-06-23 21:27:52 +00:00
* @ param { String } haystack email or nick
2020-08-14 11:20:19 +00:00
* @ return { Array } async ( reply , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . delUser = async ( haystack ) => {
if ( typeof haystack !== 'string' ) return { err : new TypeError ( 'haystack is not a string::database.delUser(' + haystack + ')' , module . filename ) } ;
2019-06-23 21:27:52 +00:00
2019-09-01 19:29:36 +00:00
let userModel = models . user ;
2019-06-23 21:27:52 +00:00
2020-02-29 20:16:48 +00:00
// sanitize input
haystack = sanitize ( haystack ) ;
2020-08-14 11:20:19 +00:00
try {
reply = await userModel . findOneAndDelete ( ) . or ( [ { nickname : haystack } , { email : haystack } ] ) . exec ( ) ;
log . debug ( 'deleted user: ' + haystack ) ;
return { reply : 1 } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
2019-09-01 19:29:36 +00:00
* get all users
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
* @ return { Array } async ( reply , err )
2019-09-01 19:29:36 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . getUsers = async ( ) => {
2019-09-01 19:29:36 +00:00
let userModel = models . user ;
2020-08-14 11:20:19 +00:00
try {
users = await userModel . find ( { } ) . exec ( ) ;
2019-09-01 19:29:36 +00:00
if ( users . length > 0 )
2020-08-14 11:20:19 +00:00
return { reply : users } ;
2019-09-01 19:29:36 +00:00
else
2020-08-14 11:20:19 +00:00
return { reply : false } ;
} catch ( err ) {
return { err : err } ;
}
2019-09-01 19:29:36 +00:00
} ;
/ * *
2020-08-14 11:20:19 +00:00
* query users by UUID , email , nickname or rememberme token
2019-06-23 21:27:52 +00:00
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
2019-06-23 21:27:52 +00:00
* @ param { String | String [ ] } haystack email or nick
2020-08-14 11:20:19 +00:00
* @ return async ( reply , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
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 ) } ;
2019-06-23 21:27:52 +00:00
2019-09-01 19:29:36 +00:00
let userModel = models . user ;
2019-06-23 21:27:52 +00:00
2020-02-29 20:16:48 +00:00
// sanitize input
haystack = sanitize ( haystack ) ;
2019-06-23 21:27:52 +00:00
let or = [ ] ;
if ( typeof haystack === 'string' ) {
or = [ { nickname : haystack } , { email : haystack } , { token : haystack } ] ;
if ( haystack . match ( /^[0-9a-fA-F]{24}$/ ) ) or . push ( { _id : haystack } ) ;
}
else {
or = [ ] ;
for ( let i = 0 ; i < haystack . length ; i ++ ) {
if ( haystack [ i ] . match ( /^[0-9a-fA-F]{24}$/ ) ) or . push ( { _id : haystack [ i ] } ) ;
or . push ( { nickname : haystack [ i ] } ) ;
or . push ( { email : haystack [ i ] } ) ;
or . push ( { token : haystack [ i ] } ) ;
}
}
2020-08-14 11:20:19 +00:00
try {
users = await userModel . find ( ) . or ( or ) . exec ( ) ;
2019-06-23 21:27:52 +00:00
if ( users . length > 0 )
2020-08-14 11:20:19 +00:00
return { reply : users } ;
2019-06-23 21:27:52 +00:00
else
2020-08-14 11:20:19 +00:00
return { reply : false } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
* updates obj keys in user entry
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
2019-06-23 21:27:52 +00:00
* @ param { Number } id User ID
* @ param { Object } obj data
2020-08-14 11:20:19 +00:00
* @ return { Array } async ( reply , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
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 ) } ;
2019-06-23 21:27:52 +00:00
2019-09-01 19:29:36 +00:00
let userModel = models . user ;
2020-08-14 11:20:19 +00:00
try {
data = await userModel . findByIdAndUpdate ( id , obj ) . exec ( ) ;
return { data : data } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
* updates data based on login
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
2019-09-01 19:29:36 +00:00
* @ TODO UPDATE METHOD ; PROBABLY OUTDATED
2019-06-23 21:27:52 +00:00
* @ param { Number } id User ID
2019-09-01 19:29:36 +00:00
* @ param { Object } data data JSON - > remember
2020-08-14 11:20:19 +00:00
* @ return { Array } async ( { date => 'Login Date' , token => 'RememberMe Cookie Token' } , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
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 ) } ;
2019-06-23 21:27:52 +00:00
let date = new Date ( ) . toISOString ( ) ;
let timestamp = new Date ( date ) . getTime ( ) ;
2020-08-14 11:20:19 +00:00
try {
reply = await methods . updateUser ( id , {
last _action : date
} ) ;
2019-06-23 21:27:52 +00:00
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 ;
2020-08-14 11:20:19 +00:00
try {
data = await Remember . findOneAndUpdate ( { userId : id } , { token : token , timestamp : Date . now ( ) } , { upsert : true } ) . exec ( ) ;
return { reply : {
2019-06-23 21:27:52 +00:00
date : date ,
timestamp : timestamp ,
token : token
2020-08-14 11:20:19 +00:00
} } ;
}
catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} else {
2020-08-14 11:20:19 +00:00
return { reply : {
2019-06-23 21:27:52 +00:00
date : date ,
timestamp : timestamp ,
token : options . old _token
2020-08-14 11:20:19 +00:00
} } ;
2019-06-23 21:27:52 +00:00
}
2020-08-14 11:20:19 +00:00
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
// //////// //////// //////// //////
// // // // // // // //
// //////// /////// //////// //////
// // // // // //
// // // // // //////
//
//////////////////////////////////////////////
/ * *
* get Applications
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
* @ return { Array } async ( apps , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . getApps = async ( ) => {
2019-06-23 21:27:52 +00:00
var Application = models . application ;
2020-08-14 11:20:19 +00:00
try {
apps = await Application . find ( { } ) . exec ( ) ;
return { reply : apps } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
* return auth obj
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
2019-06-23 21:27:52 +00:00
* @ param { Object } obj data obj ( aId , uId )
2020-08-14 11:20:19 +00:00
* @ return { Array } async ( { timestamp , token } , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . setAuthCode = async ( obj ) => {
if ( typeof obj !== 'object' ) return { err : new TypeError ( 'obj is not an object::database.setAuthCode(' + JSON . stringify ( obj ) + ')' , module . filename ) } ;
2019-06-23 21:27:52 +00:00
var AuthCode = models . authCode ;
let query = {
applicationId : obj . aId ,
userId : obj . uId
} ;
let change = {
token : ( [ 1e7 ] + - 1e3 + - 4e3 + - 8e3 + - 1e11 ) . replace ( /[018]/g , ( c ) => ( c ^ crypto . randomBytes ( new Uint8Array ( 1 ) . length ) [ 0 ] & 15 >> c / 4 ) . toString ( 16 ) ) ,
timestamp : Date . now ( )
} ;
2020-08-14 11:20:19 +00:00
try {
data = await AuthCode . findOneAndUpdate ( query , change , { upsert : true } ) . exec ( ) ;
return { reply : {
2019-06-23 21:27:52 +00:00
timestamp : change . timestamp ,
token : change . token
2020-08-14 11:20:19 +00:00
} } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
* return auth obj
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
2019-06-23 21:27:52 +00:00
* @ param { Object } obj data obj ( aId , aSecret , uId , token )
2020-08-14 11:20:19 +00:00
* @ return { Array } async ( bool , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . getAuth = async ( obj ) => {
if ( typeof obj !== 'object' ) return { err : new TypeError ( 'obj is not an object::database.getAuthCode(' + JSON . stringify ( obj ) + ')' , module . filename ) } ;
2019-06-23 21:27:52 +00:00
var AuthCode = models . authCode ;
2020-08-14 11:20:19 +00:00
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 ( {
2019-06-23 21:27:52 +00:00
$and : [
{ _id : mongoose . Types . ObjectId ( obj . aId ) } ,
{ secret : obj . aSecret }
]
2020-08-14 11:20:19 +00:00
} ) . 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 } ;
}
2019-06-23 21:27:52 +00:00
} ;
/ * *
* return if app is permitted to do access call
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
2019-06-23 21:27:52 +00:00
* @ param { Object } obj data obj ( aId , redirectUrl )
2020-08-14 11:20:19 +00:00
* @ return { Array } async ( bool , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . verifyAppCall = async ( obj ) => {
return { } ;
2019-06-23 21:27:52 +00:00
} ;
// //////// //////// //////// //////// ////////
// // // // // // //
// //////// // // // // ////////
// // // //////// // //
// //////// // // // // ////////
//
////////////////////////////////////////////////////////
/ * *
2020-08-14 11:20:19 +00:00
* returns user count
2019-06-23 21:27:52 +00:00
* @ author Ruben Meyer
2020-08-14 11:20:19 +00:00
* @ async
* @ return { Array } async ( int , err )
2019-06-23 21:27:52 +00:00
* /
2020-08-14 11:20:19 +00:00
methods . userCount = async ( ) => {
2019-09-01 19:29:36 +00:00
let userModel = models . user ;
2020-08-14 11:20:19 +00:00
try {
count = await userModel . countDocuments ( { } ) . exec ( ) ;
return { reply : count } ;
} catch ( err ) {
return { err : err } ;
}
2019-06-23 21:27:52 +00:00
} ;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module . exports = methods ;