@abtnode/rbac 1.16.8-beta-186fd5aa → 1.16.8-next-d1e52353

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/core/rbac.js CHANGED
@@ -32,7 +32,7 @@ module.exports = class RBAC {
32
32
  * RBAC constructor
33
33
  * @constructor RBAC
34
34
  * @param {Object} options Options for RBAC
35
- * @param {Storage} [options.storage] Storage of grants
35
+ * @param {import('./storage')} [options.storage] Storage of grants
36
36
  * @param {Array} [options.roles] List of role names (String)
37
37
  * @param {Object} [options.permissions] List of permissions
38
38
  * @param {Object} [options.grants] List of grants
@@ -179,6 +179,7 @@ module.exports = class RBAC {
179
179
  * @method RBAC#createRole
180
180
  * @param {String} roleName Name of new Role
181
181
  * @param {Boolean} [add] True if you need to add it to the storage
182
+ * @param {object} opt
182
183
  * @param {String} opt.title Title of new Role
183
184
  * @param {String} opt.description Description of new Role
184
185
  * @param {String} opt.extra Extra info of new Role
@@ -199,6 +200,7 @@ module.exports = class RBAC {
199
200
  * @param {String} action Name of action
200
201
  * @param {String} resource Name of resource
201
202
  * @param {Boolean} [add] True if you need to add it to the storage
203
+ * @param {object} opt
202
204
  * @param {String} opt.title Title of permission
203
205
  * @param {String} opt.description Description of permission
204
206
  * @param {String} opt.extra Extra info of permission
@@ -540,6 +542,7 @@ module.exports = class RBAC {
540
542
  * Update role or permission from RBAC
541
543
  * @method RBAC#updateByName
542
544
  * @param {String} name Name of role or permission
545
+ * @param {object} opt
543
546
  * @param {String} opt.title Title of role or permission
544
547
  * @param {String} opt.description Description of role or permission
545
548
  * @param {String} opt.extra Extra Info of role or permission
@@ -72,6 +72,10 @@ module.exports = class Storage {
72
72
  throw new Error('Storage method getRoles is not implemented');
73
73
  }
74
74
 
75
+ async updateGrants() {
76
+ throw new Error('Storage method updateGrants is not implemented');
77
+ }
78
+
75
79
  /**
76
80
  * Get all instances of Permissions
77
81
  * @method Storage#getPermissions
package/lib/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  const { RBAC } = require('./core');
2
2
 
3
3
  const NedbStorage = require('./store/nedb');
4
+ const SequelizeStorage = require('./store/sequelize');
4
5
  const MemoryStorage = require('./store/memory');
5
6
 
6
7
  /**
7
8
  * @param {object} options
8
- * @param {rbac.Storage} options.storage
9
- * @param {object} options.data
10
- * @param {array<string>} options.data.roles
9
+ * @param {import('./core/storage')} options.storage
10
+ * @param {object} [options.data]
11
+ * @param {Array<string>} options.data.roles
11
12
  * @param {object} options.data.permissions
12
13
  * @param {object} options.data.grant
13
14
  */
@@ -78,5 +79,6 @@ const createRBAC = async ({ storage, data = {} } = {}) => {
78
79
  module.exports = {
79
80
  NedbStorage,
80
81
  MemoryStorage,
82
+ SequelizeStorage,
81
83
  createRBAC,
82
84
  };
@@ -0,0 +1,218 @@
1
+ const pick = require('lodash/pick');
2
+
3
+ const Storage = require('../core/storage');
4
+ const Permission = require('../core/permission');
5
+ const Role = require('../core/role');
6
+
7
+ const ItemTypes = Object.freeze({
8
+ Role: 'role',
9
+ Permission: 'permission',
10
+ });
11
+
12
+ class SequelizeStorage extends Storage {
13
+ constructor(db) {
14
+ super();
15
+ this.db = db;
16
+ }
17
+
18
+ async add(item) {
19
+ const { name } = item;
20
+
21
+ if (await this.db.count({ name })) {
22
+ throw new Error(`Item ${name} already exists`);
23
+ }
24
+
25
+ const doc = {
26
+ name: item.name,
27
+ title: item.title,
28
+ description: item.description,
29
+ extra: item.extra,
30
+ };
31
+
32
+ if (item instanceof Role) {
33
+ doc.type = ItemTypes.Role;
34
+ doc.grants = [];
35
+ }
36
+
37
+ if (item instanceof Permission) {
38
+ doc.type = ItemTypes.Permission;
39
+ }
40
+
41
+ await this.db.insert(doc);
42
+
43
+ return true;
44
+ }
45
+
46
+ async remove(item) {
47
+ const { name } = item;
48
+
49
+ if (!(await this.db.count({ name }))) {
50
+ throw new Error(`Item ${name} is not presented in storage`);
51
+ }
52
+
53
+ await this.db.remove({ name });
54
+ const docs = await this.db.find({ type: ItemTypes.Role });
55
+ await Promise.all(
56
+ docs.map((doc) => this.db.update({ id: doc.id }, { $set: { grants: doc.grants.filter((x) => x !== name) } }))
57
+ );
58
+ return true;
59
+ }
60
+
61
+ async update(item, { title, description, extra } = {}) {
62
+ const { name } = item;
63
+
64
+ if (!(await this.db.count({ name }))) {
65
+ throw new Error(`Item ${name} is not presented in storage`);
66
+ }
67
+
68
+ await this.db.update({ name }, pick({ title, description, extra }, 'title', 'description', 'extra'));
69
+ return this.get(name);
70
+ }
71
+
72
+ async grant(role, child) {
73
+ const { name } = role;
74
+ const { name: childName } = child;
75
+
76
+ if (!(await this.db.count({ name }))) {
77
+ throw new Error(`Role ${name} is not exist`);
78
+ }
79
+
80
+ if (!(await this.db.count({ name: childName }))) {
81
+ throw new Error(`Base ${childName} is not exist`);
82
+ }
83
+
84
+ if (!(role instanceof Role)) {
85
+ throw new Error('Role is not instance of Role');
86
+ }
87
+
88
+ if (name === childName) {
89
+ throw new Error(`You can grant yourself ${name}`);
90
+ }
91
+
92
+ const docs = await this.db.find({ name });
93
+ await Promise.all(
94
+ docs.map((doc) =>
95
+ this.db.update({ id: doc.id }, { grants: [...doc.grants.filter((x) => x !== childName), childName] })
96
+ )
97
+ );
98
+
99
+ return true;
100
+ }
101
+
102
+ async revoke(role, child) {
103
+ const { name } = role;
104
+ const { name: childName } = child;
105
+
106
+ if (!(await this.db.count({ name })) || !(await this.db.count({ name: childName }))) {
107
+ throw new Error('Role is not exist');
108
+ }
109
+
110
+ const docs = await this.db.find({ name });
111
+ await Promise.all(
112
+ docs.map((doc) => this.db.update({ id: doc.id }, { grants: doc.grants.filter((x) => x !== childName) }))
113
+ );
114
+
115
+ return true;
116
+ }
117
+
118
+ async get(name) {
119
+ const item = await this.db.findOne({ name });
120
+
121
+ if (!item) {
122
+ return undefined;
123
+ }
124
+
125
+ if (item.type === ItemTypes.Role) {
126
+ return this.resolveRole(item);
127
+ }
128
+
129
+ if (item.type === ItemTypes.Permission) {
130
+ return this.resolvePermission(item);
131
+ }
132
+
133
+ return undefined;
134
+ }
135
+
136
+ async getRoles() {
137
+ const roles = await this.db.find({ type: ItemTypes.Role }, {}, { createdAt: -1 });
138
+ return roles.map((item) => this.resolveRole(item));
139
+ }
140
+
141
+ async getPermissions() {
142
+ const permissions = await this.db.find({ type: ItemTypes.Permission }, {}, { createdAt: -1 });
143
+ return permissions.map((item) => this.resolvePermission(item));
144
+ }
145
+
146
+ async getGrants(name) {
147
+ const item = await this.db.findOne({ name });
148
+
149
+ if (item) {
150
+ const grants = await Promise.all((item.grants || []).map((x) => this.get(x)));
151
+ return grants;
152
+ }
153
+
154
+ return [];
155
+ }
156
+
157
+ // custom
158
+
159
+ async updateGrants(roleName, grantNames = []) {
160
+ const role = await this.db.findOne({ name: roleName });
161
+
162
+ if (!role) {
163
+ throw new Error(`Role ${roleName} is not exist`);
164
+ }
165
+
166
+ if (role.type !== ItemTypes.Role) {
167
+ throw new Error(`${roleName} is not a role`);
168
+ }
169
+
170
+ const names = await this.db.find({}, { name: 1 });
171
+ const namesMap = names.reduce((o, { name }) => {
172
+ o[name] = true;
173
+ return o;
174
+ }, {});
175
+
176
+ grantNames.forEach((grantName) => {
177
+ if (!namesMap[grantName]) {
178
+ throw new Error(`${grantName} is not exist`);
179
+ }
180
+
181
+ if (roleName === grantName) {
182
+ throw new Error(`You can grant yourself ${roleName}`);
183
+ }
184
+ });
185
+
186
+ await this.db.update({ name: roleName }, { grants: grantNames });
187
+ return this.get(roleName);
188
+ }
189
+
190
+ // private
191
+
192
+ /**
193
+ * @param {Object} item
194
+ * name: string
195
+ * type: ItemTypes
196
+ * grants: string[]
197
+ */
198
+ resolveRole(item) {
199
+ const { name, title, description, extra } = item;
200
+ const role = new Role(this.rbac, name, { title, description, extra });
201
+ role.grants = item.grants;
202
+ return role;
203
+ }
204
+
205
+ /**
206
+ * @param {Object} item
207
+ * name: string
208
+ * type: ItemTypes
209
+ */
210
+ resolvePermission(item) {
211
+ const { name, title, description, extra } = item;
212
+ const { action, resource } = Permission.decodeName(name, this.rbac.options.delimiter);
213
+ const permission = new Permission(this.rbac, action, resource, { title, description, extra });
214
+ return permission;
215
+ }
216
+ }
217
+
218
+ module.exports = SequelizeStorage;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.8-beta-186fd5aa",
6
+ "version": "1.16.8-next-d1e52353",
7
7
  "description": "Simple lib to manage access controls in ABT Node",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,12 +19,12 @@
19
19
  "author": "linchen1987 <linchen.1987@foxmail.com> (http://github.com/linchen1987)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/db": "1.16.8-beta-186fd5aa",
22
+ "@abtnode/db": "1.16.8-next-d1e52353",
23
23
  "fs-extra": "^10.1.0",
24
24
  "lodash": "^4.17.21"
25
25
  },
26
26
  "devDependencies": {
27
27
  "jest": "^27.5.1"
28
28
  },
29
- "gitHead": "3150c3a5c3e041fe7f5a3902418d9d62adee3173"
29
+ "gitHead": "d357376aa3df9ef789befc7f548629deecb04d96"
30
30
  }