@nu-art/permissions-backend 0.400.5
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/PermissionKey_BE.d.ts +13 -0
- package/PermissionKey_BE.js +48 -0
- package/_entity/permission-access-level/ModuleBE_PermissionAccessLevelDB.d.ts +18 -0
- package/_entity/permission-access-level/ModuleBE_PermissionAccessLevelDB.js +55 -0
- package/_entity/permission-access-level/index.d.ts +2 -0
- package/_entity/permission-access-level/index.js +2 -0
- package/_entity/permission-access-level/module-pack.d.ts +1 -0
- package/_entity/permission-access-level/module-pack.js +3 -0
- package/_entity/permission-api/ModuleBE_PermissionAPIDB.d.ts +12 -0
- package/_entity/permission-api/ModuleBE_PermissionAPIDB.js +62 -0
- package/_entity/permission-api/index.d.ts +2 -0
- package/_entity/permission-api/index.js +2 -0
- package/_entity/permission-api/module-pack.d.ts +1 -0
- package/_entity/permission-api/module-pack.js +3 -0
- package/_entity/permission-domain/ModuleBE_PermissionDomainDB.d.ts +15 -0
- package/_entity/permission-domain/ModuleBE_PermissionDomainDB.js +25 -0
- package/_entity/permission-domain/index.d.ts +2 -0
- package/_entity/permission-domain/index.js +2 -0
- package/_entity/permission-domain/module-pack.d.ts +1 -0
- package/_entity/permission-domain/module-pack.js +3 -0
- package/_entity/permission-group/ModuleBE_PermissionGroupDB.d.ts +14 -0
- package/_entity/permission-group/ModuleBE_PermissionGroupDB.js +62 -0
- package/_entity/permission-group/index.d.ts +2 -0
- package/_entity/permission-group/index.js +2 -0
- package/_entity/permission-group/module-pack.d.ts +1 -0
- package/_entity/permission-group/module-pack.js +3 -0
- package/_entity/permission-project/ModuleBE_PermissionProjectDB.d.ts +10 -0
- package/_entity/permission-project/ModuleBE_PermissionProjectDB.js +12 -0
- package/_entity/permission-project/index.d.ts +2 -0
- package/_entity/permission-project/index.js +2 -0
- package/_entity/permission-project/module-pack.d.ts +1 -0
- package/_entity/permission-project/module-pack.js +3 -0
- package/_entity/permission-user/ModuleBE_PermissionUserAPI.d.ts +8 -0
- package/_entity/permission-user/ModuleBE_PermissionUserAPI.js +13 -0
- package/_entity/permission-user/ModuleBE_PermissionUserDB.d.ts +36 -0
- package/_entity/permission-user/ModuleBE_PermissionUserDB.js +222 -0
- package/_entity/permission-user/index.d.ts +3 -0
- package/_entity/permission-user/index.js +3 -0
- package/_entity/permission-user/module-pack.d.ts +2 -0
- package/_entity/permission-user/module-pack.js +3 -0
- package/_entity.d.ts +12 -0
- package/_entity.js +18 -0
- package/consts.d.ts +7 -0
- package/consts.js +5 -0
- package/core/module-pack.d.ts +3 -0
- package/core/module-pack.js +32 -0
- package/core/utils.d.ts +25 -0
- package/core/utils.js +85 -0
- package/index.d.ts +4 -0
- package/index.js +22 -0
- package/modules/ModuleBE_Permissions.d.ts +77 -0
- package/modules/ModuleBE_Permissions.js +357 -0
- package/modules/ModuleBE_PermissionsAssert.d.ts +48 -0
- package/modules/ModuleBE_PermissionsAssert.js +242 -0
- package/modules/consts.d.ts +11 -0
- package/modules/consts.js +29 -0
- package/modules/index.d.ts +1 -0
- package/modules/index.js +19 -0
- package/package.json +85 -0
- package/permissions.d.ts +22 -0
- package/permissions.js +154 -0
- package/shared.d.ts +1 -0
- package/shared.js +19 -0
- package/types.d.ts +28 -0
- package/types.js +1 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { MemKey_ServerApi, ModuleBE_BaseDB, Storm, } from '@nu-art/thunderstorm-backend';
|
|
2
|
+
import { DBDef_PermissionUser } from '@nu-art/permissions-shared';
|
|
3
|
+
import { _keys, ApiException, asOptionalArray, batchActionParallel, dbObjectToId, exists, filterDuplicates, filterInstances, filterKeys, flatArray, JwtTools, merge, Year } from '@nu-art/ts-common';
|
|
4
|
+
import { ModuleBE_PermissionGroupDB } from '../permission-group/ModuleBE_PermissionGroupDB.js';
|
|
5
|
+
import { MemKey_AccountId, ModuleBE_AccountDB, ModuleBE_SessionDB } from '@nu-art/user-account-backend';
|
|
6
|
+
import { MemKey_UserPermissions } from '../../consts.js';
|
|
7
|
+
import { dispatcher_collectServiceAccounts } from '@nu-art/thunderstorm-backend/modules/_tdb/service-accounts';
|
|
8
|
+
export class ModuleBE_PermissionUserDB_Class extends ModuleBE_BaseDB {
|
|
9
|
+
defaultPermissionGroups;
|
|
10
|
+
constructor() {
|
|
11
|
+
super(DBDef_PermissionUser);
|
|
12
|
+
}
|
|
13
|
+
__performProjectSetup() {
|
|
14
|
+
return {
|
|
15
|
+
priority: 4,
|
|
16
|
+
processor: async () => {
|
|
17
|
+
const accounts = await ModuleBE_AccountDB.query.where({});
|
|
18
|
+
const permissionsUser = await this.query.all(accounts.map(dbObjectToId));
|
|
19
|
+
const usersToUpsert = [];
|
|
20
|
+
const usersToDelete = [];
|
|
21
|
+
permissionsUser.forEach((user, index) => {
|
|
22
|
+
if (exists(user)) {
|
|
23
|
+
if (!exists(accounts.find(account => account._id === user._id)))
|
|
24
|
+
usersToDelete.push(user);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
usersToUpsert.push({
|
|
28
|
+
_id: accounts[index]._id,
|
|
29
|
+
groups: [],
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
await this.set.all(usersToUpsert);
|
|
33
|
+
await this.delete.all(usersToDelete);
|
|
34
|
+
// This stage updates the rtdb's config- which is why it's last. Changing the rtdb's config kills the server.
|
|
35
|
+
const serviceAccounts = flatArray(dispatcher_collectServiceAccounts.dispatchModule());
|
|
36
|
+
await this.createSystemServiceAccount(serviceAccounts);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async __onUserLogin(account, transaction) {
|
|
41
|
+
await this.insertIfNotExist(account, transaction);
|
|
42
|
+
}
|
|
43
|
+
async __onNewUserRegistered(account, transaction) {
|
|
44
|
+
await this.insertIfNotExist(account, transaction);
|
|
45
|
+
}
|
|
46
|
+
// protected async canDeleteDocument(transaction: FirestoreTransaction, dbInstances: DB_PermissionUser[]) {
|
|
47
|
+
// const conflicts: DB_PermissionUser[] = [];
|
|
48
|
+
// const accounts = await ModuleBE_AccountDB.query.custom(_EmptyQuery);
|
|
49
|
+
//
|
|
50
|
+
// for (const item of dbInstances) {
|
|
51
|
+
// const account = accounts.find(acc => acc._id === item.accountId);
|
|
52
|
+
// if (account)
|
|
53
|
+
// conflicts.push(item);
|
|
54
|
+
// }
|
|
55
|
+
//
|
|
56
|
+
// if (conflicts.length)
|
|
57
|
+
// throw new ApiException<DB_EntityDependency<any>[]>(422, 'permission users are connected to accounts').setErrorBody({
|
|
58
|
+
// type: 'has-dependencies',
|
|
59
|
+
// body: conflicts.map(conflict => ({collectionKey: 'User', conflictingIds: [conflict._id]}))
|
|
60
|
+
// });
|
|
61
|
+
// }
|
|
62
|
+
async preWriteProcessing(instance, originalDbInstance, t) {
|
|
63
|
+
instance._auditorId = MemKey_AccountId.get();
|
|
64
|
+
instance.__groupIds = filterDuplicates(instance.groups.map(group => group.groupId) || []);
|
|
65
|
+
if (!instance.__groupIds.length)
|
|
66
|
+
return;
|
|
67
|
+
// Get all groups the user has from the collection
|
|
68
|
+
const dbGroups = filterInstances(await ModuleBE_PermissionGroupDB.query.all(instance.__groupIds, t));
|
|
69
|
+
// Verify all groups actually existing in the collection
|
|
70
|
+
if (instance.__groupIds.length !== dbGroups.length) {
|
|
71
|
+
const dbGroupIds = dbGroups.map(dbObjectToId);
|
|
72
|
+
throw new ApiException(422, `Trying to assign a user to a permission-group that does not exist: ${instance.__groupIds.filter(groupId => !dbGroupIds.includes(groupId))}`);
|
|
73
|
+
}
|
|
74
|
+
//todo check for duplications in data
|
|
75
|
+
}
|
|
76
|
+
async postWriteProcessing(data, actionType) {
|
|
77
|
+
const deleted = asOptionalArray(data.deleted) ?? [];
|
|
78
|
+
const updated = asOptionalArray(data.updated) ?? [];
|
|
79
|
+
const beforeIds = (asOptionalArray(data.before) ?? []).map(before => before?._id);
|
|
80
|
+
const accountIdToInvalidate = filterDuplicates(filterInstances([...deleted, ...updated].map(i => i?._id))).filter(id => beforeIds.includes(id));
|
|
81
|
+
await this.invalidateSession(accountIdToInvalidate);
|
|
82
|
+
}
|
|
83
|
+
insertIfNotExist = async (uiAccount, transaction) => {
|
|
84
|
+
const create = async (transaction) => {
|
|
85
|
+
const defaultPermissionGroups = ModuleBE_PermissionUserDB.defaultPermissionGroups ? await ModuleBE_PermissionUserDB.defaultPermissionGroups() : [];
|
|
86
|
+
const permissionGroups = ModuleBE_PermissionUserDB.defaultPermissionGroups
|
|
87
|
+
? filterInstances(await ModuleBE_PermissionGroupDB.query.all(defaultPermissionGroups.map(item => item.groupId)))
|
|
88
|
+
: [];
|
|
89
|
+
this.logInfo(`Received ${defaultPermissionGroups.length} groups to assign, ${permissionGroups.length} of which exist`);
|
|
90
|
+
const permissionsUserToCreate = {
|
|
91
|
+
_id: uiAccount._id,
|
|
92
|
+
groups: permissionGroups.map(group => ({ groupId: group._id })),
|
|
93
|
+
_auditorId: MemKey_AccountId.get()
|
|
94
|
+
};
|
|
95
|
+
return ModuleBE_PermissionUserDB.create.item(permissionsUserToCreate, transaction);
|
|
96
|
+
};
|
|
97
|
+
return ModuleBE_PermissionUserDB.collection.uniqueGetOrCreate({ _id: uiAccount._id }, create, transaction);
|
|
98
|
+
};
|
|
99
|
+
async assignPermissions(body) {
|
|
100
|
+
if (!body.targetAccountIds.length)
|
|
101
|
+
throw new ApiException(400, `Asked to modify permissions but provided no users to modify permissions of.`);
|
|
102
|
+
const usersToGiveTo = filterInstances(await this.query.all(body.targetAccountIds));
|
|
103
|
+
// console.log('assignPermissions target accounts ');
|
|
104
|
+
// console.log(await this.query.custom(_EmptyQuery));
|
|
105
|
+
if (!usersToGiveTo.length || usersToGiveTo.length !== body.targetAccountIds.length) {
|
|
106
|
+
const dbUserIds = usersToGiveTo.map(dbObjectToId);
|
|
107
|
+
throw new ApiException(404, `Asked to give permissions to non-existent user accounts: ${body.targetAccountIds.filter(id => !dbUserIds.includes(id))}`);
|
|
108
|
+
}
|
|
109
|
+
const dbGroups = filterInstances(await ModuleBE_PermissionGroupDB.query.all(body.permissionGroupIds));
|
|
110
|
+
if (dbGroups.length !== body.permissionGroupIds.length) {
|
|
111
|
+
const dbGroupIds = dbGroups.map(dbObjectToId);
|
|
112
|
+
throw new ApiException(404, `Asked to give users non-existing permission groups: ${body.permissionGroupIds.filter(id => !dbGroupIds.includes(id))}`);
|
|
113
|
+
}
|
|
114
|
+
const myUserPermissions = MemKey_UserPermissions.get();
|
|
115
|
+
const permissionsToGive = dbGroups.reduce((map, group) => {
|
|
116
|
+
// Gather the highest permissions for each domain, from all groups
|
|
117
|
+
_keys(group._levelsMap || []).forEach(domainId => {
|
|
118
|
+
if (map[domainId] === undefined)
|
|
119
|
+
map[domainId] = 0;
|
|
120
|
+
if (map[domainId] < group._levelsMap[domainId])
|
|
121
|
+
map[domainId] = group._levelsMap[domainId];
|
|
122
|
+
});
|
|
123
|
+
return map;
|
|
124
|
+
}, {});
|
|
125
|
+
const failedDomains = _keys(permissionsToGive).filter(domainId => {
|
|
126
|
+
const tooLowPermission = myUserPermissions[domainId] < permissionsToGive[domainId];
|
|
127
|
+
this.logError(`${myUserPermissions[domainId]} < ${permissionsToGive[domainId]} === ${tooLowPermission}`);
|
|
128
|
+
const noPermissionInThisDomain = myUserPermissions[domainId] === undefined;
|
|
129
|
+
return noPermissionInThisDomain || tooLowPermission;
|
|
130
|
+
});
|
|
131
|
+
if (failedDomains.length)
|
|
132
|
+
throw new ApiException(403, `Attempted to give higher permissions than current user has: ${failedDomains}`);
|
|
133
|
+
const groupIds = dbGroups.map(group => ({ groupId: group._id }));
|
|
134
|
+
const usersToUpdate = usersToGiveTo.map(user => {
|
|
135
|
+
user.groups = groupIds;
|
|
136
|
+
return user;
|
|
137
|
+
});
|
|
138
|
+
await this.set.multi(usersToUpdate);
|
|
139
|
+
}
|
|
140
|
+
setDefaultPermissionGroups = (groupsGetter) => {
|
|
141
|
+
this.defaultPermissionGroups = groupsGetter;
|
|
142
|
+
};
|
|
143
|
+
clearDefaultPermissionGroups = () => {
|
|
144
|
+
delete this.defaultPermissionGroups;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* The system requires to perform action, which in other cases can also be done by a human.
|
|
148
|
+
* This requires system features to identify as a bot user, or "Service Account"
|
|
149
|
+
*
|
|
150
|
+
* @param serviceAccounts - List of Accounts to create
|
|
151
|
+
* @private
|
|
152
|
+
*/
|
|
153
|
+
async createSystemServiceAccount(serviceAccounts) {
|
|
154
|
+
this.logInfoBold('Creating Service Accounts: ', serviceAccounts);
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
const tokenCreator = ModuleBE_AccountDB.token.create;
|
|
157
|
+
// @ts-ignore
|
|
158
|
+
const invalidateAccount = ModuleBE_AccountDB.token.invalidateAll;
|
|
159
|
+
const envConfigRef = Storm.getInstance().getGlobalEnvConfigRef();
|
|
160
|
+
const updatedConfig = {};
|
|
161
|
+
//Run over all service accounts
|
|
162
|
+
for (const serviceAccount of serviceAccounts) {
|
|
163
|
+
// Create account if it doesn't already exist
|
|
164
|
+
const accountsToRequest = filterKeys({
|
|
165
|
+
type: 'service',
|
|
166
|
+
email: serviceAccount.email,
|
|
167
|
+
description: serviceAccount.description
|
|
168
|
+
});
|
|
169
|
+
let account;
|
|
170
|
+
//Get or create service account
|
|
171
|
+
try {
|
|
172
|
+
account = await ModuleBE_AccountDB.impl.querySafeAccount({ email: serviceAccount.email });
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
this.logInfo('NOTICE: querySafeAccount failed, creating accounts');
|
|
176
|
+
account = await ModuleBE_AccountDB.account.create(accountsToRequest);
|
|
177
|
+
}
|
|
178
|
+
// Assign permissions groups to service account
|
|
179
|
+
const permissionsUser = await ModuleBE_PermissionUserDB.query.uniqueAssert({ _id: account._id });
|
|
180
|
+
permissionsUser.groups = serviceAccount.groupIds?.map(groupId => ({ groupId })) || [];
|
|
181
|
+
await ModuleBE_PermissionUserDB.set.item(permissionsUser);
|
|
182
|
+
//Service accounts are only allowed to have one session... but this isn't the defined place to be a cop about it
|
|
183
|
+
const sessions = await ModuleBE_AccountDB.account.getSessions(account);
|
|
184
|
+
//If we have a valid session(not expired) we use its JWT instead of creating a new one
|
|
185
|
+
let validSession;
|
|
186
|
+
for (const session of sessions.sessions) {
|
|
187
|
+
if (await JwtTools.isJwtActive(session.sessionIdJwt)) {
|
|
188
|
+
validSession = session;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
this.logError(serviceAccount.ttl);
|
|
193
|
+
const token = validSession?.sessionIdJwt ? { token: validSession?.sessionIdJwt } : await tokenCreator({
|
|
194
|
+
accountId: account._id,
|
|
195
|
+
ttl: serviceAccount.ttl ?? Year
|
|
196
|
+
});
|
|
197
|
+
updatedConfig[serviceAccount.moduleName] = {
|
|
198
|
+
serviceAccount: filterKeys({
|
|
199
|
+
token,
|
|
200
|
+
description: serviceAccount.description,
|
|
201
|
+
accountId: account._id,
|
|
202
|
+
email: account.email
|
|
203
|
+
})
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (_keys(updatedConfig).length > 0)
|
|
207
|
+
MemKey_ServerApi.get().addPostCallAction(async () => {
|
|
208
|
+
const currentConfig = await envConfigRef.get({});
|
|
209
|
+
await envConfigRef.set(merge(currentConfig, updatedConfig));
|
|
210
|
+
this.logInfoBold('Created Service Accounts for', _keys(updatedConfig));
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async invalidateSession(accountIds) {
|
|
214
|
+
if (!accountIds.length)
|
|
215
|
+
return;
|
|
216
|
+
const sessions = await batchActionParallel(accountIds, 10, async (ids) => await ModuleBE_SessionDB.query.custom({ where: { accountId: { $in: ids } } }));
|
|
217
|
+
await this.runTransaction(async (t) => {
|
|
218
|
+
await Promise.all(sessions.map(session => ModuleBE_SessionDB._session.invalidate.bySession(session, t)));
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export const ModuleBE_PermissionUserDB = new ModuleBE_PermissionUserDB_Class();
|
package/_entity.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './_entity/permission-access-level/index.js';
|
|
2
|
+
export * from './_entity/permission-access-level/index.js';
|
|
3
|
+
export * from './_entity/permission-api/index.js';
|
|
4
|
+
export * from './_entity/permission-api/index.js';
|
|
5
|
+
export * from './_entity/permission-project/index.js';
|
|
6
|
+
export * from './_entity/permission-project/index.js';
|
|
7
|
+
export * from './_entity/permission-domain/index.js';
|
|
8
|
+
export * from './_entity/permission-domain/index.js';
|
|
9
|
+
export * from './_entity/permission-group/index.js';
|
|
10
|
+
export * from './_entity/permission-group/index.js';
|
|
11
|
+
export * from './_entity/permission-user/index.js';
|
|
12
|
+
export * from './_entity/permission-user/index.js';
|
package/_entity.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//Access Level
|
|
2
|
+
export * from './_entity/permission-access-level/index.js';
|
|
3
|
+
export * from './_entity/permission-access-level/index.js';
|
|
4
|
+
//API
|
|
5
|
+
export * from './_entity/permission-api/index.js';
|
|
6
|
+
export * from './_entity/permission-api/index.js';
|
|
7
|
+
//Project
|
|
8
|
+
export * from './_entity/permission-project/index.js';
|
|
9
|
+
export * from './_entity/permission-project/index.js';
|
|
10
|
+
//Domain
|
|
11
|
+
export * from './_entity/permission-domain/index.js';
|
|
12
|
+
export * from './_entity/permission-domain/index.js';
|
|
13
|
+
//Group
|
|
14
|
+
export * from './_entity/permission-group/index.js';
|
|
15
|
+
export * from './_entity/permission-group/index.js';
|
|
16
|
+
//User
|
|
17
|
+
export * from './_entity/permission-user/index.js';
|
|
18
|
+
export * from './_entity/permission-user/index.js';
|
package/consts.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SessionKey_BE } from '@nu-art/user-account-backend';
|
|
2
|
+
import { MemKey } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
3
|
+
import { TypedMap } from '@nu-art/ts-common';
|
|
4
|
+
import { SessionData_Permissions, SessionData_StrictMode } from '@nu-art/permissions-shared';
|
|
5
|
+
export declare const SessionKey_Permissions_BE: SessionKey_BE<SessionData_Permissions>;
|
|
6
|
+
export declare const SessionKey_StrictMode_BE: SessionKey_BE<SessionData_StrictMode>;
|
|
7
|
+
export declare const MemKey_UserPermissions: MemKey<TypedMap<number>>;
|
package/consts.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SessionKey_BE } from '@nu-art/user-account-backend';
|
|
2
|
+
import { MemKey } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
3
|
+
export const SessionKey_Permissions_BE = new SessionKey_BE('permissions');
|
|
4
|
+
export const SessionKey_StrictMode_BE = new SessionKey_BE('strictMode');
|
|
5
|
+
export const MemKey_UserPermissions = new MemKey('user-permissions'); //[domainId]: access level numerical value
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Permissions management system, define access level for each of
|
|
3
|
+
* your server apis, and restrict users by giving them access levels
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
import { ModuleBE_PermissionsAssert } from '../modules/ModuleBE_PermissionsAssert.js';
|
|
20
|
+
import { ModuleBE_Permissions } from '../modules/ModuleBE_Permissions.js';
|
|
21
|
+
import { ModulePackBE_PermissionAccessLevel, ModulePackBE_PermissionAPI, ModulePackBE_PermissionDomain, ModulePackBE_PermissionGroup, ModulePackBE_PermissionProject, ModulePackBE_PermissionUser } from '../_entity.js';
|
|
22
|
+
export const ModulePackBE_Permissions = [
|
|
23
|
+
...ModulePackBE_PermissionAccessLevel,
|
|
24
|
+
...ModulePackBE_PermissionAPI,
|
|
25
|
+
...ModulePackBE_PermissionProject,
|
|
26
|
+
...ModulePackBE_PermissionDomain,
|
|
27
|
+
...ModulePackBE_PermissionGroup,
|
|
28
|
+
...ModulePackBE_PermissionUser,
|
|
29
|
+
ModuleBE_PermissionsAssert,
|
|
30
|
+
ModuleBE_Permissions,
|
|
31
|
+
];
|
|
32
|
+
export * from '../modules/ModuleBE_PermissionsAssert.js';
|
package/core/utils.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TypedMap, UniqueId } from '@nu-art/ts-common';
|
|
2
|
+
import { DefaultDef_Group, PreDBAccessLevel } from '@nu-art/permissions-shared';
|
|
3
|
+
import { PermissionKey_BE } from '../PermissionKey_BE.js';
|
|
4
|
+
import { DefaultDef_Domain, DefaultDef_Package } from '../types.js';
|
|
5
|
+
export declare const Permissions_abTest: (seed: UniqueId, namespace: string, permutations: string[]) => DefaultDef_Package;
|
|
6
|
+
/**
|
|
7
|
+
* Generate automatic BE permission keys for a domain
|
|
8
|
+
* @param accessLevels the relevant access levels to generate keys for
|
|
9
|
+
* @param keyByLevelMapper the key name mapper by access level name
|
|
10
|
+
* @param domainId the domain id to apply in the resolver
|
|
11
|
+
*/
|
|
12
|
+
export declare const generatePermissionKeys: <Key extends string | number | symbol>(accessLevels: PreDBAccessLevel[], keyByLevelMapper: TypedMap<string>, domainId: UniqueId) => { [key in Key]: PermissionKey_BE<string>; };
|
|
13
|
+
/**
|
|
14
|
+
* Automatic generator for domain default definitions,
|
|
15
|
+
* @param key MUST NEVER CHANGE! the key is the "key" to uniqueness of the entire permission decleration
|
|
16
|
+
* @param namespace The name space of the current generated domain definitions
|
|
17
|
+
* @param preDBAccessLevels The access levels to create (can be default or custom)
|
|
18
|
+
* @param permissionKeysByLevel The permission key name for each access level
|
|
19
|
+
* @param dbNames List of db names (optional)
|
|
20
|
+
*/
|
|
21
|
+
export declare const generateDomainDefaults: <Key extends string | number | symbol>(key: string, namespace: string, preDBAccessLevels: PreDBAccessLevel[], permissionKeysByLevel: { [key in Key]: string; }, dbNames?: string[]) => {
|
|
22
|
+
domain: DefaultDef_Domain;
|
|
23
|
+
groups: DefaultDef_Group[];
|
|
24
|
+
keys: { [key in Key]: PermissionKey_BE<string>; };
|
|
25
|
+
};
|
package/core/utils.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { _values, md5 } from '@nu-art/ts-common';
|
|
2
|
+
import { CreateDefaultAccessLevels, DefaultAccessLevel_NoAccess, DefaultAccessLevel_Read } from '@nu-art/permissions-shared';
|
|
3
|
+
import { defaultValueResolverV2, PermissionKey_BE } from '../PermissionKey_BE.js';
|
|
4
|
+
export const Permissions_abTest = (seed, namespace, permutations) => {
|
|
5
|
+
const domains = permutations.map(permutation => {
|
|
6
|
+
const name = `${namespace}/${permutation}`;
|
|
7
|
+
const domain = {
|
|
8
|
+
_id: md5(`${seed}${name}`),
|
|
9
|
+
namespace: name,
|
|
10
|
+
permissionKeys: permutations.map(permutation => {
|
|
11
|
+
const initialDataResolver = () => defaultValueResolverV2(domain._id, DefaultAccessLevel_Read.name);
|
|
12
|
+
return new PermissionKey_BE(`${namespace}/${permutation}`, initialDataResolver);
|
|
13
|
+
}),
|
|
14
|
+
levels: CreateDefaultAccessLevels(seed, [DefaultAccessLevel_NoAccess, DefaultAccessLevel_Read]),
|
|
15
|
+
};
|
|
16
|
+
return domain;
|
|
17
|
+
});
|
|
18
|
+
const groups = permutations.map((permutation, index) => {
|
|
19
|
+
const name = `${namespace}/${permutation}`;
|
|
20
|
+
const domain = domains[index];
|
|
21
|
+
const group = {
|
|
22
|
+
_id: md5(`${domain._id}/${name}`),
|
|
23
|
+
name,
|
|
24
|
+
uiLabel: name,
|
|
25
|
+
accessLevels: {
|
|
26
|
+
[domain._id]: DefaultAccessLevel_Read.name,
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return group;
|
|
30
|
+
});
|
|
31
|
+
const Permission_Package = {
|
|
32
|
+
name: namespace,
|
|
33
|
+
domains: domains,
|
|
34
|
+
groups: groups
|
|
35
|
+
};
|
|
36
|
+
return Permission_Package;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Generate automatic BE permission keys for a domain
|
|
40
|
+
* @param accessLevels the relevant access levels to generate keys for
|
|
41
|
+
* @param keyByLevelMapper the key name mapper by access level name
|
|
42
|
+
* @param domainId the domain id to apply in the resolver
|
|
43
|
+
*/
|
|
44
|
+
export const generatePermissionKeys = (accessLevels, keyByLevelMapper, domainId) => {
|
|
45
|
+
return accessLevels.reduce((mapper, currentAccessLevel) => {
|
|
46
|
+
// declare default
|
|
47
|
+
const key = keyByLevelMapper[currentAccessLevel.name];
|
|
48
|
+
// update acc mapper
|
|
49
|
+
mapper[currentAccessLevel.name] = new PermissionKey_BE(key, () => defaultValueResolverV2(domainId, currentAccessLevel.name));
|
|
50
|
+
return mapper;
|
|
51
|
+
}, {});
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Automatic generator for domain default definitions,
|
|
55
|
+
* @param key MUST NEVER CHANGE! the key is the "key" to uniqueness of the entire permission decleration
|
|
56
|
+
* @param namespace The name space of the current generated domain definitions
|
|
57
|
+
* @param preDBAccessLevels The access levels to create (can be default or custom)
|
|
58
|
+
* @param permissionKeysByLevel The permission key name for each access level
|
|
59
|
+
* @param dbNames List of db names (optional)
|
|
60
|
+
*/
|
|
61
|
+
export const generateDomainDefaults = (key, namespace, preDBAccessLevels, permissionKeysByLevel, dbNames) => {
|
|
62
|
+
// Generate the new domain id
|
|
63
|
+
const newDomainId = md5(`domain/${key}`);
|
|
64
|
+
// Get all default db ready access levels using the provided ones
|
|
65
|
+
const accessLevels = CreateDefaultAccessLevels(newDomainId, preDBAccessLevels);
|
|
66
|
+
const keyDefinitions = generatePermissionKeys(preDBAccessLevels, permissionKeysByLevel, newDomainId);
|
|
67
|
+
return {
|
|
68
|
+
domain: {
|
|
69
|
+
_id: newDomainId,
|
|
70
|
+
namespace,
|
|
71
|
+
permissionKeys: _values(keyDefinitions),
|
|
72
|
+
levels: accessLevels,
|
|
73
|
+
dbNames
|
|
74
|
+
},
|
|
75
|
+
groups: accessLevels.map(accessLevel => ({
|
|
76
|
+
_id: md5(`${key}/${accessLevel.name}`),
|
|
77
|
+
name: `${namespace}/${accessLevel.name}`,
|
|
78
|
+
uiLabel: `${namespace}/${accessLevel.name}`,
|
|
79
|
+
accessLevels: {
|
|
80
|
+
[namespace]: accessLevel.name
|
|
81
|
+
}
|
|
82
|
+
})),
|
|
83
|
+
keys: keyDefinitions
|
|
84
|
+
};
|
|
85
|
+
};
|
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Permissions management system, define access level for each of
|
|
3
|
+
* your server apis, and restrict users by giving them access levels
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
export * from './core/module-pack.js';
|
|
20
|
+
export * from './modules/index.js';
|
|
21
|
+
export * from './_entity.js';
|
|
22
|
+
export * from './types.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Module, TypedMap } from '@nu-art/ts-common';
|
|
2
|
+
import { DB_PermissionGroup, DB_PermissionProject, DefaultDef_Group, SessionData_Permissions } from '@nu-art/permissions-shared';
|
|
3
|
+
import { BaseSessionClaims, CollectSessionData } from '@nu-art/user-account-backend';
|
|
4
|
+
import { PerformProjectSetup } from '@nu-art/thunderstorm-backend/modules/action-processor/Action_SetupProject';
|
|
5
|
+
import { DefaultDef_Project } from '../types.js';
|
|
6
|
+
export interface CollectPermissionsProjects {
|
|
7
|
+
__collectPermissionsProjects(): DefaultDef_Project;
|
|
8
|
+
}
|
|
9
|
+
export declare const PermissionGroup_Permissions_SuperAdmin: DefaultDef_Group;
|
|
10
|
+
export declare const PermissionGroup_Permissions_Viewer: DefaultDef_Group;
|
|
11
|
+
export declare const PermissionGroup_Permissions_Editor: DefaultDef_Group;
|
|
12
|
+
export declare const PermissionGroup_Account_Manager: DefaultDef_Group;
|
|
13
|
+
export declare const PermissionGroup_Account_Admin: DefaultDef_Group;
|
|
14
|
+
export declare const PermissionGroup_Account_Viewer: DefaultDef_Group;
|
|
15
|
+
export declare const PermissionGroups_Permissions: DefaultDef_Group[];
|
|
16
|
+
export declare const PermissionProject_Permissions: DefaultDef_Project;
|
|
17
|
+
declare class ModuleBE_Permissions_Class extends Module implements CollectSessionData<SessionData_Permissions>, PerformProjectSetup {
|
|
18
|
+
protected init(): void;
|
|
19
|
+
__collectSessionData(data: BaseSessionClaims): Promise<SessionData_Permissions>;
|
|
20
|
+
getUserPermissionMap: (userGroups: DB_PermissionGroup[]) => Promise<TypedMap<number>>;
|
|
21
|
+
toggleStrictMode: () => Promise<void>;
|
|
22
|
+
__performProjectSetup(): {
|
|
23
|
+
priority: number;
|
|
24
|
+
processor: () => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
createPermissionProjects(projects: DefaultDef_Project[]): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Creates All the DB_PermissionProject
|
|
29
|
+
*
|
|
30
|
+
* @param projects - predefined permissions projects
|
|
31
|
+
*/
|
|
32
|
+
createProjects(projects: DefaultDef_Project[]): Promise<TypedMap<DB_PermissionProject>>;
|
|
33
|
+
/**
|
|
34
|
+
* Creates All the DB_PermissionDomains
|
|
35
|
+
*
|
|
36
|
+
* @param projects - predefined permissions projects
|
|
37
|
+
* @param map_nameToDBProject
|
|
38
|
+
*/
|
|
39
|
+
private createDomains;
|
|
40
|
+
/**
|
|
41
|
+
* Creates All the DB_PermissionAccessLevel
|
|
42
|
+
*
|
|
43
|
+
* @param projects - predefined permissions projects
|
|
44
|
+
* @param map_nameToDbDomain
|
|
45
|
+
*/
|
|
46
|
+
private createAccessLevels;
|
|
47
|
+
/**
|
|
48
|
+
* Creates All the DB_PermissionGroup
|
|
49
|
+
*
|
|
50
|
+
* @param projects - predefined permissions projects
|
|
51
|
+
* @param map_nameToDbDomain
|
|
52
|
+
* @param domainNameToLevelNameToDBAccessLevel
|
|
53
|
+
*/
|
|
54
|
+
private createGroups;
|
|
55
|
+
/**
|
|
56
|
+
* Creates All the DB_PermissionApi
|
|
57
|
+
*
|
|
58
|
+
* @param projects - predefined permissions projects
|
|
59
|
+
* @param domainNameToLevelNameToDBAccessLevel
|
|
60
|
+
*/
|
|
61
|
+
private createApis;
|
|
62
|
+
/**
|
|
63
|
+
* Creates permission keys associated with the given projects.
|
|
64
|
+
*
|
|
65
|
+
* @param projects - An array of projects.
|
|
66
|
+
*/
|
|
67
|
+
private createPermissionsKeys;
|
|
68
|
+
/**
|
|
69
|
+
* If no "Super Admin" user is defined in the system!
|
|
70
|
+
* The first user to press the create project button will become the "Super Admin" of the system
|
|
71
|
+
*
|
|
72
|
+
* If a "Super Admin" already exists in the system, a 403 will be thrown
|
|
73
|
+
*/
|
|
74
|
+
private assignSuperAdmin;
|
|
75
|
+
}
|
|
76
|
+
export declare const ModuleBE_Permissions: ModuleBE_Permissions_Class;
|
|
77
|
+
export {};
|