Browse Source

add access list clients to back-end

Kyle Klaus 5 years ago
parent
commit
f990d3f674

+ 64 - 17
backend/internal/access-list.js

@@ -1,14 +1,15 @@
-const _                   = require('lodash');
-const fs                  = require('fs');
-const batchflow           = require('batchflow');
-const logger              = require('../logger').access;
-const error               = require('../lib/error');
-const accessListModel     = require('../models/access_list');
-const accessListAuthModel = require('../models/access_list_auth');
-const proxyHostModel      = require('../models/proxy_host');
-const internalAuditLog    = require('./audit-log');
-const internalNginx       = require('./nginx');
-const utils               = require('../lib/utils');
+const _                     = require('lodash');
+const fs                    = require('fs');
+const batchflow             = require('batchflow');
+const logger                = require('../logger').access;
+const error                 = require('../lib/error');
+const accessListModel       = require('../models/access_list');
+const accessListAuthModel   = require('../models/access_list_auth');
+const accessListClientModel = require('../models/access_list_client');
+const proxyHostModel        = require('../models/proxy_host');
+const internalAuditLog      = require('./audit-log');
+const internalNginx         = require('./nginx');
+const utils                 = require('../lib/utils');
 
 function omissions () {
 	return ['is_deleted'];
@@ -35,8 +36,9 @@ const internalAccessList = {
 			.then((row) => {
 				data.id = row.id;
 
-				// Now add the items
 				let promises = [];
+
+				// Now add the items
 				data.items.map((item) => {
 					promises.push(accessListAuthModel
 						.query()
@@ -48,13 +50,27 @@ const internalAccessList = {
 					);
 				});
 
+				// Now add the clients
+				if (typeof data.clients !== 'undefined' && data.clients) {
+					data.clients.map((client) => {
+						promises.push(accessListClientModel
+							.query()
+							.insert({
+								access_list_id: row.id,
+								address:        client.address,
+								directive:      client.directive
+							})
+						);
+					});
+				}
+
 				return Promise.all(promises);
 			})
 			.then(() => {
 				// re-fetch with expansions
 				return internalAccessList.get(access, {
 					id:     data.id,
-					expand: ['owner', 'items']
+					expand: ['owner', 'items', 'clients']
 				}, true /* <- skip masking */);
 			})
 			.then((row) => {
@@ -152,6 +168,37 @@ const internalAccessList = {
 							}
 						});
 				}
+
+				// Check for clients and add/update/remove them
+				if (typeof data.clients !== 'undefined' && data.clients) {
+					let promises = [];
+
+					data.clients.map(function (client) {
+						if (client.address) {
+							promises.push(accessListAuthModel
+								.query()
+								.insert({
+									access_list_id: data.id,
+									address:        client.address,
+									directive:      client.directive
+								})
+							);
+						}
+					});
+
+					let query = accessListClientModel
+						.query()
+						.delete()
+						.where('access_list_id', data.id);
+
+					return query
+						.then(() => {
+							// Add new items
+							if (promises.length) {
+								return Promise.all(promises);
+							}
+						});
+				}
 			})
 			.then(() => {
 				// Add to audit log
@@ -166,7 +213,7 @@ const internalAccessList = {
 				// re-fetch with expansions
 				return internalAccessList.get(access, {
 					id:     data.id,
-					expand: ['owner', 'items']
+					expand: ['owner', 'items', 'clients']
 				}, true /* <- skip masking */);
 			})
 			.then((row) => {
@@ -204,7 +251,7 @@ const internalAccessList = {
 					.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
 					.where('access_list.is_deleted', 0)
 					.andWhere('access_list.id', data.id)
-					.allowEager('[owner,items,proxy_hosts]')
+					.allowEager('[owner,items,clients,proxy_hosts]')
 					.omit(['access_list.is_deleted'])
 					.first();
 
@@ -246,7 +293,7 @@ const internalAccessList = {
 	delete: (access, data) => {
 		return access.can('access_lists:delete', data.id)
 			.then(() => {
-				return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items']});
+				return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients']});
 			})
 			.then((row) => {
 				if (!row) {
@@ -330,7 +377,7 @@ const internalAccessList = {
 					.where('access_list.is_deleted', 0)
 					.groupBy('access_list.id')
 					.omit(['access_list.is_deleted'])
-					.allowEager('[owner,items]')
+					.allowEager('[owner,items,clients]')
 					.orderBy('access_list.name', 'ASC');
 
 				if (access_data.permission_visibility !== 'all') {

+ 46 - 0
backend/migrations/20200410143839_access_list_client.js

@@ -0,0 +1,46 @@
+const migrate_name = 'access_list_client';
+const logger       = require('../logger').migrate;
+
+/**
+ * Migrate
+ *
+ * @see http://knexjs.org/#Schema
+ *
+ * @param   {Object}  knex
+ * @param   {Promise} Promise
+ * @returns {Promise}
+ */
+exports.up = function (knex/*, Promise*/) {
+
+	logger.info('[' + migrate_name + '] Migrating Up...');
+
+	return knex.schema.createTable('access_list_client', (table) => {
+		table.increments().primary();
+		table.dateTime('created_on').notNull();
+		table.dateTime('modified_on').notNull();
+		table.integer('access_list_id').notNull().unsigned();
+		table.string('address').notNull();
+		table.string('directive').notNull();
+		table.json('meta').notNull();
+
+	})
+		.then(function () {
+			logger.info('[' + migrate_name + '] access_list_client Table created');
+		});
+};
+
+/**
+ * Undo Migrate
+ *
+ * @param {Object} knex
+ * @param {Promise} Promise
+ * @returns {Promise}
+ */
+exports.down = function (knex/*, Promise*/) {
+	logger.info('[' + migrate_name + '] Migrating Down...');
+
+	return knex.schema.dropTable('access_list_client')
+		.then(() => {
+			logger.info('[' + migrate_name + '] access_list_client Table dropped');
+		});
+};

+ 16 - 4
backend/models/access_list.js

@@ -1,10 +1,11 @@
 // Objection Docs:
 // http://vincit.github.io/objection.js/
 
-const db             = require('../db');
-const Model          = require('objection').Model;
-const User           = require('./user');
-const AccessListAuth = require('./access_list_auth');
+const db               = require('../db');
+const Model            = require('objection').Model;
+const User             = require('./user');
+const AccessListAuth   = require('./access_list_auth');
+const AccessListClient = require('./access_list_client');
 
 Model.knex(db);
 
@@ -62,6 +63,17 @@ class AccessList extends Model {
 					qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
 				}
 			},
+			clients: {
+				relation:   Model.HasManyRelation,
+				modelClass: AccessListClient,
+				join:       {
+					from: 'access_list.id',
+					to:   'access_list_client.access_list_id'
+				},
+				modify: function (qb) {
+					qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
+				}
+			},
 			proxy_hosts: {
 				relation:   Model.HasManyRelation,
 				modelClass: ProxyHost,

+ 54 - 0
backend/models/access_list_client.js

@@ -0,0 +1,54 @@
+// Objection Docs:
+// http://vincit.github.io/objection.js/
+
+const db    = require('../db');
+const Model = require('objection').Model;
+
+Model.knex(db);
+
+class AccessListClient extends Model {
+	$beforeInsert () {
+		this.created_on  = Model.raw('NOW()');
+		this.modified_on = Model.raw('NOW()');
+
+		// Default for meta
+		if (typeof this.meta === 'undefined') {
+			this.meta = {};
+		}
+	}
+
+	$beforeUpdate () {
+		this.modified_on = Model.raw('NOW()');
+	}
+
+	static get name () {
+		return 'AccessListClient';
+	}
+
+	static get tableName () {
+		return 'access_list_client';
+	}
+
+	static get jsonAttributes () {
+		return ['meta'];
+	}
+
+	static get relationMappings () {
+		return {
+			access_list: {
+				relation:   Model.HasOneRelation,
+				modelClass: require('./access_list'),
+				join:       {
+					from: 'access_list_client.access_list_id',
+					to:   'access_list.id'
+				},
+				modify: function (qb) {
+					qb.where('access_list.is_deleted', 0);
+					qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']);
+				}
+			}
+		};
+	}
+}
+
+module.exports = AccessListClient;

+ 40 - 0
backend/schema/endpoints/access-lists.json

@@ -19,6 +19,14 @@
       "type": "string",
       "description": "Name of the Access List"
     },
+    "directive": {
+      "type": "string",
+      "enum": ["allow", "deny"]
+    },
+    "address": {
+      "type": "string",
+      "format": "ipv4"
+    },
     "meta": {
       "type": "object"
     }
@@ -96,6 +104,22 @@
               }
             }
           },
+          "clients": {
+            "type": "array",
+            "minItems": 0,
+            "items": {
+              "type": "object",
+              "additionalProperties": false,
+              "properties": {
+                "address": {
+                  "$ref": "#/definitions/address"
+                },
+                "directive": {
+                  "$ref": "#/definitions/directive"
+                }
+              }
+            }
+          },
           "meta": {
             "$ref": "#/definitions/meta"
           }
@@ -141,6 +165,22 @@
                 }
               }
             }
+          },
+          "clients": {
+            "type": "array",
+            "minItems": 0,
+            "items": {
+              "type": "object",
+              "additionalProperties": false,
+              "properties": {
+                "address": {
+                  "$ref": "#/definitions/address"
+                },
+                "directive": {
+                  "$ref": "#/definitions/directive"
+                }
+              }
+            }
           }
         }
       },