Backend
This commit is contained in:
82
src/backend/models/auth.js
Normal file
82
src/backend/models/auth.js
Normal file
@ -0,0 +1,82 @@
|
||||
// Objection Docs:
|
||||
// http://vincit.github.io/objection.js/
|
||||
|
||||
'use strict';
|
||||
|
||||
const bcrypt = require('bcrypt-then');
|
||||
const db = require('../db');
|
||||
const Model = require('objection').Model;
|
||||
const User = require('./user');
|
||||
|
||||
Model.knex(db);
|
||||
|
||||
function encryptPassword () {
|
||||
/* jshint -W040 */
|
||||
let _this = this;
|
||||
|
||||
if (_this.type === 'password' && _this.secret) {
|
||||
return bcrypt.hash(_this.secret, 13)
|
||||
.then(function (hash) {
|
||||
_this.secret = hash;
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class Auth extends Model {
|
||||
$beforeInsert (queryContext) {
|
||||
this.created_on = Model.raw('NOW()');
|
||||
this.modified_on = Model.raw('NOW()');
|
||||
|
||||
return encryptPassword.apply(this, queryContext);
|
||||
}
|
||||
|
||||
$beforeUpdate (queryContext) {
|
||||
this.modified_on = Model.raw('NOW()');
|
||||
return encryptPassword.apply(this, queryContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a plain password against the encrypted password
|
||||
*
|
||||
* @param {String} password
|
||||
* @returns {Promise}
|
||||
*/
|
||||
verifyPassword (password) {
|
||||
return bcrypt.compare(password, this.secret);
|
||||
}
|
||||
|
||||
static get name () {
|
||||
return 'Auth';
|
||||
}
|
||||
|
||||
static get tableName () {
|
||||
return 'auth';
|
||||
}
|
||||
|
||||
static get jsonAttributes () {
|
||||
return ['meta'];
|
||||
}
|
||||
|
||||
static get relationMappings () {
|
||||
return {
|
||||
user: {
|
||||
relation: Model.HasOneRelation,
|
||||
modelClass: User,
|
||||
join: {
|
||||
from: 'auth.user_id',
|
||||
to: 'user.id'
|
||||
},
|
||||
filter: {
|
||||
is_deleted: 0
|
||||
},
|
||||
modify: function (qb) {
|
||||
qb.omit(['is_deleted']);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Auth;
|
133
src/backend/models/token.js
Normal file
133
src/backend/models/token.js
Normal file
@ -0,0 +1,133 @@
|
||||
/**
|
||||
NOTE: This is not a database table, this is a model of a Token object that can be created/loaded
|
||||
and then has abilities after that.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const config = require('config');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const crypto = require('crypto');
|
||||
const error = require('../lib/error');
|
||||
const ALGO = 'RS256';
|
||||
|
||||
module.exports = function () {
|
||||
const public_key = config.get('jwt.pub');
|
||||
const private_key = config.get('jwt.key');
|
||||
|
||||
let token_data = {};
|
||||
|
||||
return {
|
||||
/**
|
||||
* @param {Object} payload
|
||||
* @param {Object} [user_options]
|
||||
* @param {Integer} [user_options.expires]
|
||||
* @returns {Promise}
|
||||
*/
|
||||
create: (payload, user_options) => {
|
||||
|
||||
user_options = user_options || {};
|
||||
|
||||
// sign with RSA SHA256
|
||||
let options = {
|
||||
algorithm: ALGO
|
||||
};
|
||||
|
||||
if (typeof user_options.expires !== 'undefined' && user_options.expires) {
|
||||
options.expiresIn = user_options.expires;
|
||||
}
|
||||
|
||||
payload.jti = crypto.randomBytes(12)
|
||||
.toString('base64')
|
||||
.substr(-8);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
jwt.sign(payload, private_key, options, (err, token) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
token_data = payload;
|
||||
resolve({
|
||||
token: token,
|
||||
payload: payload
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} token
|
||||
* @returns {Promise}
|
||||
*/
|
||||
load: function (token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
if (!token || token === null || token === 'null') {
|
||||
reject('Empty token');
|
||||
} else {
|
||||
jwt.verify(token, public_key, {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => {
|
||||
if (err) {
|
||||
|
||||
if (err.name === 'TokenExpiredError') {
|
||||
reject(new error.AuthError('Token has expired', err));
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
} else {
|
||||
token_data = result;
|
||||
|
||||
// Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
|
||||
// For 30 days at least, we need to replace 'all' with user.
|
||||
if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
|
||||
//console.log('Warning! Replacing "all" scope with "user"');
|
||||
|
||||
token_data.scope = ['user'];
|
||||
}
|
||||
|
||||
resolve(token_data);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the token have the specified scope?
|
||||
*
|
||||
* @param {String} scope
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
hasScope: function (scope) {
|
||||
return typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, scope) !== -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
* @return {*}
|
||||
*/
|
||||
get: function (key) {
|
||||
if (typeof token_data[key] !== 'undefined') {
|
||||
return token_data[key];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
* @param {*} value
|
||||
*/
|
||||
set: function (key, value) {
|
||||
token_data[key] = value;
|
||||
}
|
||||
};
|
||||
};
|
35
src/backend/models/user.js
Normal file
35
src/backend/models/user.js
Normal file
@ -0,0 +1,35 @@
|
||||
// Objection Docs:
|
||||
// http://vincit.github.io/objection.js/
|
||||
|
||||
'use strict';
|
||||
|
||||
const db = require('../db');
|
||||
const Model = require('objection').Model;
|
||||
|
||||
Model.knex(db);
|
||||
|
||||
class User extends Model {
|
||||
$beforeInsert () {
|
||||
this.created_on = Model.raw('NOW()');
|
||||
this.modified_on = Model.raw('NOW()');
|
||||
}
|
||||
|
||||
$beforeUpdate () {
|
||||
this.modified_on = Model.raw('NOW()');
|
||||
}
|
||||
|
||||
static get name () {
|
||||
return 'User';
|
||||
}
|
||||
|
||||
static get tableName () {
|
||||
return 'user';
|
||||
}
|
||||
|
||||
static get jsonAttributes () {
|
||||
return ['roles'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = User;
|
Reference in New Issue
Block a user