UNPKG

umpack-express

Version:

user management pack for express framework app

763 lines (632 loc) 19.4 kB
[![npm version](https://badge.fury.io/js/umpack-express.svg)](https://badge.fury.io/js/umpack-express) [![Dependency Status](https://david-dm.org/liz4rdcom/umpack-express.svg)](https://david-dm.org/liz4rdcom/umpack-express) [![devDependency Status](https://david-dm.org/liz4rdcom/umpack-express/dev-status.svg)](https://david-dm.org/liz4rdcom/umpack-express?type=dev) # umpack user management pack for express framework app. you can use this package in typescript too. ## Install Guide ### Install npm package ```sh npm install umpack-express -S -E ``` ### Set Options and Router(express app) * accessTokenExpiresIn [time span string description](https://github.com/zeit/ms) ```js var umpack = require('umpack-express')({ mongodbConnectionString: 'mongodb://172.17.7.92:27017/umpack', accessTokenSecret: 'myrandomstring', passwordHashSecret: 'mypasswordsecret', accessTokenExpiresIn: '1m', cookieAccessTokenName: 'accessToken', passwordResetData: { smtpData: { host: 'smtp host', port: 'smtp port. optional', user: 'username for logging into smtp', password: 'password for logging into smtp', timeout: 5000, // number of milliseconds to wait. default 5000 ssl: false //boolean or object with fields: key, ca, cert. default false }, senderEmail: 'sender@email.com', resetKeyExpiresIn: '2h', //password reset key expiration passwordMessageFunction: function (key /*password reset key*/) { return 'message to send. use key. for example: http://example.com?key=' + key; }, passwordWrongEmailInstruction: function (clientIp) { return 'someone with ip: ' + clientIp + ' requested password reset on the site example.com'; //message to send to input email, when user with input email does not exist } }, passwordResetPhoneData: { resetKeyExpiresIn: '2h', sendResetKey: function (phone, resetKey) { // send sms to the phone. // return promise or nothing. } }, deviceControl: false, // default false. if it is true, user's devices access is controlled userNameCaseSensitive: false, // if it is true, userName is case sensitive, if false - it is not. logger: loggerObject, // loggerObject should have methods: error, warn, info, debug and trace. it should have logging level restriction itself. // by default logger field is logger object that logs only warnings and errors. activateOnSignup: false, // if true, when user signs up account doesn't need to activate userDefaultRole: 'user' //not works if activateOnSignup is false. on signup user has this role }); //..... app.use('/um', umpack.router); //..... ``` ### umpack API Methods ### This methods should be called without authorization header ### Login ```js POST : {baseurl}/login request - data/body : { userName: 'user', email: 'user@test.com', // userName or email is required password: 'userpassword', deviceToken: 'device token' //required if device control is enabled } response - 'user access token' ``` ### Signup ```js POST : {baseurl}/signup request - data/body : { userName: 'user', //required password: 'userpassword', //required firstName: 'first name', lastName: 'last name', email: 'user@test.com', phone: '123456', address: 'usa/de', additionalInfo: 'user additional info', } response - { success: true, message: 'Thanks for signUp' } ``` ### Next methods requires authorization header (access token). ```js headers:{'authorization': 'user access token'} ``` ### Password Reset ```js POST : {baseurl}/resetpass request - data/body : { userName: 'admin', oldPassword: 'admin', newPassword: '123456789' } response - { success: true, message: 'Password Reset Done' } ``` ### Get all users ```js GET : {baseurl}/users response - { id: '34jhb5jh45b6', userName: 'user name', isActivated: 'true/false', roles: ['admin','provider','root','etc.'] } ``` ### Get all roles ```js GET : {baseurl}/roles response - [{name:'admin', description: ''},{name:'user', description: ''},{name:'provider', description: ''},{name:'root', description: ''},{name:'organizationUser', description: ''}] ``` ### Update user status (Activate / Deactivate) ```js POST : {baseurl}/updateUserStatus request - data/body : { id: 'user id', isActivated: true/false, } response - { id: 'user id', isActivated: 'true/false', userName: 'user name', roles: ['admin','provider','root','sys','etc.'] } ``` ### Update user roles (assigne or remove role from user) ```js POST : {baseurl}/updateUserRoles request - data/body : { userId: 'user id', roleName: 'admin', enable: 'true/false' } response - { id: 'user id', isActivated: 'true/false', userName: 'user name', roles: ['admin','provider','root','sys','etc.'] } ``` ### Get User Object ```js GET : {baseurl}/users/{userId} response - { id: '', userName: 'name', firstName: 'firstName', lastName: 'lastName', email: 'test@email.com', phone: '', address: '', additionalInfo: '', isActivated: true/false, roles: ['user', 'admin'], metaData: {} } ``` ### Get User Object By userName ```js GET : {baseurl}/users/{userName}/full response - { id: '', userName: 'name', firstName: 'firstName', lastName: 'lastName', email: 'test@email.com', phone: '', address: '', additionalInfo: '', isActivated: true/false, roles: ['user', 'admin'], metaData: {} } ``` ### Change User's userName ```js PUT : {baseurl}/users/{userId}/username request - data/body : { userName: 'userName' } response - {success : true} ``` ### Change User Info ```js PUT : {baseurl}/users/{userId}/info request - data/body : { firstName: '', lastName: '', email: '', phone: '', address: '', additionalInfo: '' } response - {success : true} ``` ### Delete User ```js DELETE : {baseurl}/users/{userId} response - { success: true } ``` ### Lost Password Reset Request ```js POST : {baseurl}/users/passwordResetRequest request - data/body : { email: 'test@email.com' } response - {success : true} instructions are sent to the email ``` ### Lost Password Reset ```js POST : {baseurl}/users/passwordReset request - data/body : { resetKey: '', //password reset key sent to the email newPassword: 'password' } response - {success : true} ``` ### Lost Password Reset By Phone Request ```js POST : {baseurl}/users/{userName}/passwordResetRequestByPhone request - data/body : {} //empty object response - {success : true} password reset key is sent to the user phone ``` ### Lost Password Reset By Phone ```js POST : {baseurl}/users/{userName}/passwordResetByPhone request - data/body : { resetKey: '', //key sent to the phone newPassword: 'password' } response - {success : true} ``` ### Get User's All Registered Devices ```js GET : {baseurl}/users/{userName}/devices response - [ { deviceToken: 'token', canAccess: true/false, lastUsageDate: new Date() //last usage date } ] ``` ### Get User's All Permitted Devices ```js GET : {baseurl}/users/{userName}/devices/permitted response - [ { deviceToken: 'token', canAccess: true, lastUsageDate: new Date() //last usage date } ] ``` ### Grant User's Device Access ```js POST : {baseurl}/users/{userName}/devices/access request - data/body : { deviceToken: 'device token' } response - { success: true } ``` ### Restrict User's Device From Access ```js POST : {baseurl}/users/{userName}/devices/restriction request - data/body : { deviceToken: 'token' } response - { success: true } ``` ### Get metadata ```js GET : {baseurl}/metadata response - metadata object ``` ### Update metadata ```js PUT : {baseurl}/metadata request - data/body : metadata object response - { success: true, message: 'metadata updated' } ``` ### Set metadata field ```js PUT : {baseurl}/metadata/{fieldName} request - data/body : { value: 'some value of any type' } response - { success: true, message: 'metadata key: {fieldName} updated' } ``` ### Create New Role ```js POST : {baseurl}/roles request - data/body : { name: 'admin', description: 'description' } response - { success: true } ``` ### Get Role Full Object ```js GET : {baseurl}/roles/{roleName} response - { name: 'admin', description: 'description', actions: [{ id: '464sadfsdf6', pattern: '/api/*', name: 'action name', verbGet: true, verbPost: true, verbPut: true, verbDelete: true, verbHead: true }] } ``` ### Change Role's name and description ```js PUT : {baseurl}/roles/{roleName} request - data/body : { name: 'role name', description: 'role description' } response - { success: true } ``` ### Delete Role ```js DELETE : {baseurl}/roles/{roleName} response: { success: true } ``` ### Permit Action to Role ```js POST : {baseurl}/roles/{roleName}/actions request - data/body : { pattern: '/api/*', name: 'name', verbGet: true, verbPost: true, verbPut: true, verbDelete: true, verbHead: true } response - { success: true, actionId: 'action id' } ``` ### Edit Role's Action ```js PUT : {baseurl}/roles/{roleName}/actions/{actionId} request - data/body : { pattern: '/api/something', name: 'name', verbGet: true, verbPost: true, verbPut: true, verbDelete: false, verbHead: false } response - { success : true } ``` ### Remove Permitted Action From Role ```js DELETE : {baseurl}/roles/{roleName}/actions/{actionId} response - { success: true } ``` ### Umpack Initialization. * saves root user and admin role if they do not exist. * if device control is enabled, it saves one permitted device of the root for administration. ```js POST : {baseurl}/initialization request - data/body : { umBaseUrl: '/um', deviceToken: 'token', //not required if device control is disabled password: '123' // password for root user. optional. if it isn't passed new password is generated randomly. } response - { success: true, password: 'password' //generated or parameter password for root user } ``` ### Authorization Route it is used for validating access token ```js HEAD : {baseurl}/authorization ``` ### API Response Internal Statuses * Every response with status 400/401 has also internal status for example : ```js {message:User Is Not Activated, internalStatus:601} ``` * All internal status ```js { code: 601, message: 'User Is Not Activated' } { code: 602, message: 'User Name Or Email Already Exists' } { code: 603, message: 'Wrong User Name Or Password' } { code: 604, message: 'Wrong Password' } { code: 605, message: 'User Does Not Exists' } { code: 606, message: 'Can\'t Find JWT Token Inside The Request Header' } { code: 607, message: 'Invalid JWT Token' } { code: 608, message: 'Token Expired' } { code: 609, message: 'Access Denied' } { code: 701, message: 'Wrong Role Name' } { code: 702, message: 'Role Already Exists'} { code: 703, message: 'Invalid Action Pattern'} { code: 704, message: 'Action Pattern Already Exists'} { code: 800, message: 'password reset key is expired' } { code: 801, message: 'password reset key is invalid' } { code: 802, message: 'password reset by email is not supported' } { code: 803, message: 'password reset by phone is not supported' } { code: 804, message: 'invalid phone number' } { code: 805, message: 'invalid device token' } { code: 806, message: 'access is denied for your device' } { code: 807, message: 'devices control is not supported' } { code: 900, message: 'invalid userName' } { code: 901, message: 'invalid email' } ``` ### Use Authorization Middleware * if user is not authorized then response status is 401 * if user has no access right then response status is 403 * if device control is enabled and user's device has no access right then response status is 403 too * if response status is 401 or 403 response body is object with error message and internalStatus ```{ message: err.message, internalStatus: err.internalStatus }``` ```js var umpack = require('./umpack')(); router.get('/', umpack.isAuthorized, function(req, res, next) { return res.send('your resources'); }); ``` ### User's Metadata Management * if you need to add additional info, attribute, etc. you can use user's metadata to manage it. * metadata is custom field/subdocument of user doc which can contains any kind of object. * example : ### assigne/update user metadata ```js var organizationInfo = { organizationId: '2222', organiationName: 'bbbbb', organizationTaxCode: '777777' }; umpack.updateUserMetaData('admin', organizationInfo) .then(function(result) { console.log(result); }) .catch(function(err) { console.log(err.message); }); ``` ### get user metadata by user name ```js router.get('/usermetadata', function(req, res, next) { umpack.getUserMetaDataByUserName('admin') .then(function(result) { return res.send(result); }) .catch(function(err) { console.log(err.message); return res.send({ message: err.message }); }); }); ``` ### get user metadata by request ```js router.get('/usermetadata', function(req, res, next) { umpack.getUserMetaDataByRequest(req) .then(function(result) { return res.send(result); }) .catch(function(err) { //console.log(err.message); return res.status(400).send({ message: err.message }); }); }); ``` ### Filter users by metadata param ```js router.get('/usersbymeta', function(req, res, next) { umpack.filterUsersByMetaData('organizationId', '2222') .then(function(users) { res.send(users); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Get User Full Name ```js router.get('/userFullName', function(req, res, next) { umpack.getFullName('admin') .then(function(fullName) { res.send(fullName); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Get User Roles By User Name ```js router.get('/userRoles', function(req, res, next) { umpack.getUserRolesByUserName('admin') .then(function(result) { res.send(result); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Get User Roles From Request ```js router.get('/userRoles', function(req, res, next) { umpack.getUserRolesFromRequest(req) .then(function(result) { res.send(result); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Filter users by role ```js router.get('/usersbyrole', function(req, res, next) { umpack.filterUsersByRole('user') .then(function(result) { res.send(result); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Get Full User Object ```js router.get('/fullUserObject', function(req, res, next) { umpack.getFullUserObject('admin') .then(function(result) { res.send(result); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Get Full User Object From Request ```js router.get('/fullUserObject', function(req, res, next) { umpack.getFullUserObjectFromRequest(req) .then(function(result) { res.send(result); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Initialize Umpack * saves root user and admin role if they do not exist. * if device control is enabled, it saves one permitted device of the root for administration. ```js router.get('/initialization', function(req, res, next) { //password is optional umpack.init(req.body.umBaseUrl, req.body.password, req.body.deviceToken) // if deviceControl is disabled deviceToken is not required else it is required .then(function(password) { // randomly generated password or passed parameter password for the root user is returned res.send(password); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Initialize Umpack With Full Api Access to admin Role * saves root user and admin role if they do not exist. * saved admin role has permission of everything. * if device control is enabled, it saves one permitted device of the root for administration. ```js router.get('/initialization', function(req, res, next) { //password is optional umpack.initWithFullAccess(req.body.password, req.body.deviceToken) // if deviceControl is disabled deviceToken is not required else it is required .then(function(password) { // randomly generated password or passed parameter password for the root user is returned res.send(password); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Get UserName From Request ```js router.get('/userRoles', isAuthorized, function(req, res, next) { // Request Must Have authorization Header umpack.getUserNameFromRequest(req) .then(function(userName) { res.send(userName); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ``` ### Signup method ```js router.get('/signup', function(req, res, next) { // { // userName: 'user', // password: 'userpassword', // firstName: 'first name', // lastName: 'last name', // email: 'user@test.com', // phone: '123456', // address: 'usa/de', // additionalInfo: 'user additional info', // } // parameters are exactly same as in /{baseurl}/signup umpack.signup(req.body) .then(function() { res.send({success: true}); }) .catch(function(err) { return res.status(400).send({ message: err.message }); }); }); ```