Added user permissions, delete user

This commit is contained in:
Jamie Curnow
2018-07-05 08:27:25 +10:00
parent 4a59ef9925
commit 30924a6922
22 changed files with 690 additions and 51 deletions

View File

@ -1,11 +1,12 @@
'use strict';
const _ = require('lodash');
const error = require('../lib/error');
const userModel = require('../models/user');
const authModel = require('../models/auth');
const gravatar = require('gravatar');
const internalToken = require('./token');
const _ = require('lodash');
const error = require('../lib/error');
const userModel = require('../models/user');
const userPermissionModel = require('../models/user_permission');
const authModel = require('../models/auth');
const gravatar = require('gravatar');
const internalToken = require('./token');
function omissions () {
return ['is_deleted'];
@ -56,7 +57,23 @@ const internalUser = {
}
})
.then(user => {
return internalUser.get(access, {id: user.id});
// Create permissions row as well
let is_admin = data.roles.indexOf('admin') !== -1;
return userPermissionModel
.query()
.insert({
user_id: user.id,
visibility: is_admin ? 'all' : 'user',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage'
})
.then(() => {
return internalUser.get(access, {id: user.id, expand: ['permissions']});
});
});
},
@ -145,6 +162,7 @@ const internalUser = {
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[permissions]')
.first();
// Custom omissions
@ -377,6 +395,50 @@ const internalUser = {
});
},
/**
* @param {Access} access
* @param {Object} data
* @return {Promise}
*/
setPermissions: (access, data) => {
return access.can('users:permissions', data.id)
.then(() => {
return internalUser.get(access, {id: data.id});
})
.then(user => {
if (user.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
}
return user;
})
.then(user => {
// Get perms row, patch if it exists
return userPermissionModel
.query()
.where('user_id', user.id)
.first()
.then(existing_auth => {
if (existing_auth) {
// patch
return userPermissionModel
.query()
.where('user_id', user.id)
.patchAndFetchById(existing_auth.id, _.assign({user_id: user.id}, data));
} else {
// insert
return userPermissionModel
.query()
.insertAndFetch(_.assign({user_id: user.id}, data));
}
})
.then(permissions => {
return true;
});
});
},
/**
* @param {Access} access
* @param {Object} data

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -43,6 +43,124 @@ exports.up = function (knex/*, Promise*/) {
})
.then(() => {
logger.info('[' + migrate_name + '] user Table created');
return knex.schema.createTable('user_permission', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('user_id').notNull().unsigned();
table.string('visibility').notNull();
table.string('proxy_hosts').notNull();
table.string('redirection_hosts').notNull();
table.string('dead_hosts').notNull();
table.string('streams').notNull();
table.string('access_lists').notNull();
table.unique('user_id');
});
})
.then(() => {
logger.info('[' + migrate_name + '] user_permission Table created');
return knex.schema.createTable('proxy_host', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.string('domain_name').notNull();
table.string('forward_ip').notNull();
table.integer('forward_port').notNull().unsigned();
table.integer('access_list_id').notNull().unsigned().defaultTo(0);
table.integer('ssl_enabled').notNull().unsigned().defaultTo(0);
table.string('ssl_provider').notNull().defaultTo('');
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.integer('caching_enabled').notNull().unsigned().defaultTo(0);
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
table.json('meta').notNull();
table.unique(['domain_name', 'is_deleted']);
});
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table created');
return knex.schema.createTable('redirection_host', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.string('domain_name').notNull();
table.string('forward_domain_name').notNull();
table.integer('preserve_path').notNull().unsigned().defaultTo(0);
table.integer('ssl_enabled').notNull().unsigned().defaultTo(0);
table.string('ssl_provider').notNull().defaultTo('');
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
table.json('meta').notNull();
table.unique(['domain_name', 'is_deleted']);
});
})
.then(() => {
logger.info('[' + migrate_name + '] redirection_host Table created');
return knex.schema.createTable('dead_host', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.string('domain_name').notNull();
table.integer('ssl_enabled').notNull().unsigned().defaultTo(0);
table.string('ssl_provider').notNull().defaultTo('');
table.json('meta').notNull();
table.unique(['domain_name', 'is_deleted']);
});
})
.then(() => {
logger.info('[' + migrate_name + '] dead_host Table created');
return knex.schema.createTable('stream', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.integer('incoming_port').notNull().unsigned();
table.string('forward_ip').notNull();
table.integer('forwarding_port').notNull().unsigned();
table.integer('tcp_forwarding').notNull().unsigned().defaultTo(0);
table.integer('udp_forwarding').notNull().unsigned().defaultTo(0);
table.json('meta').notNull();
table.unique(['incoming_port', 'is_deleted']);
});
})
.then(() => {
logger.info('[' + migrate_name + '] stream Table created');
return knex.schema.createTable('access_list', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.string('name').notNull();
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] access_list Table created');
return knex.schema.createTable('access_list_auth', table => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('access_list_id').notNull().unsigned();
table.string('username').notNull();
table.string('password').notNull();
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] access_list_auth Table created');
});
};

View File

@ -3,8 +3,9 @@
'use strict';
const db = require('../db');
const Model = require('objection').Model;
const db = require('../db');
const Model = require('objection').Model;
const UserPermission = require('./user_permission');
Model.knex(db);
@ -30,6 +31,22 @@ class User extends Model {
return ['roles'];
}
static get relationMappings () {
return {
permissions: {
relation: Model.HasOneRelation,
modelClass: UserPermission,
join: {
from: 'user.id',
to: 'user_permission.user_id'
},
modify: function (qb) {
qb.omit(['id', 'created_on', 'modified_on', 'user_id']);
}
}
};
}
}
module.exports = User;

View File

@ -0,0 +1,30 @@
// Objection Docs:
// http://vincit.github.io/objection.js/
'use strict';
const db = require('../db');
const Model = require('objection').Model;
Model.knex(db);
class UserPermission 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 'UserPermission';
}
static get tableName () {
return 'user_permission';
}
}
module.exports = UserPermission;

View File

@ -183,12 +183,12 @@ router
});
/**
* Specific user service settings
* Specific user permissions
*
* /api/users/123/services
* /api/users/123/permissions
*/
router
.route('/:user_id/services')
.route('/:user_id/permissions')
.options((req, res) => {
res.sendStatus(204);
})
@ -196,18 +196,18 @@ router
.all(userIdFromMe)
/**
* POST /api/users/123/services
* PUT /api/users/123/permissions
*
* Sets Service Settings for a user
* Set some or all permissions for a user
*/
.post((req, res, next) => {
.put((req, res, next) => {
apiValidator({$ref: 'endpoints/users#/links/5/schema'}, req.body)
.then(payload => {
payload.id = req.params.user_id;
return internalUser.setServiceSettings(res.locals.access, payload);
return internalUser.setPermissions(res.locals.access, payload);
})
.then(result => {
res.status(200)
res.status(201)
.send(result);
})
.catch(next);

View File

@ -206,6 +206,49 @@
"targetSchema": {
"type": "boolean"
}
},
{
"title": "Set Permissions",
"description": "Sets Permissions for a User",
"href": "/users/{definitions.identity.example}/permissions",
"access": "private",
"method": "PUT",
"rel": "update",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"schema": {
"type": "object",
"properties": {
"visibility": {
"type": "string",
"pattern": "^(all|user)$"
},
"access_lists": {
"type": "string",
"pattern": "^(hidden|view|manage)$"
},
"dead_hosts": {
"type": "string",
"pattern": "^(hidden|view|manage)$"
},
"proxy_hosts": {
"type": "string",
"pattern": "^(hidden|view|manage)$"
},
"redirection_hosts": {
"type": "string",
"pattern": "^(hidden|view|manage)$"
},
"streams": {
"type": "string",
"pattern": "^(hidden|view|manage)$"
}
}
},
"targetSchema": {
"type": "boolean"
}
}
],
"properties": {

View File

@ -1,11 +1,12 @@
'use strict';
const fs = require('fs');
const NodeRSA = require('node-rsa');
const config = require('config');
const logger = require('./logger').global;
const userModel = require('./models/user');
const authModel = require('./models/auth');
const fs = require('fs');
const NodeRSA = require('node-rsa');
const config = require('config');
const logger = require('./logger').global;
const userModel = require('./models/user');
const userPermissionModel = require('./models/user_permission');
const authModel = require('./models/auth');
module.exports = function () {
return new Promise((resolve, reject) => {
@ -54,7 +55,7 @@ module.exports = function () {
.select(userModel.raw('COUNT(`id`) as `count`'))
.where('is_deleted', 0)
.first('count')
.then((row) => {
.then(row => {
if (!row.count) {
// Create a new user and set password
logger.info('Creating a new user: admin@example.com with password: changeme');
@ -79,6 +80,19 @@ module.exports = function () {
type: 'password',
secret: 'changeme',
meta: {}
})
.then(() => {
return userPermissionModel
.query()
.insert({
user_id: user.id,
visibility: 'all',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage'
});
});
});
}