This commit is contained in:
Jamie Curnow
2018-06-20 08:47:26 +10:00
parent 9e919c3c24
commit 80d78cbf25
39 changed files with 2837 additions and 0 deletions

View 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
View 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;
}
};
};

View 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;