@nu-art/permissions-backend 0.401.9 → 0.500.6
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/RequirePermission.d.ts +33 -0
- package/RequirePermission.js +56 -0
- package/_entity/access-group/ModuleBE_AccessGroupDB.d.ts +13 -0
- package/_entity/access-group/ModuleBE_AccessGroupDB.js +36 -0
- package/_entity/access-group/module-pack.d.ts +1 -0
- package/_entity/access-group/module-pack.js +3 -0
- package/_entity/permission-scope/ModuleBE_PermissionScopeDB.d.ts +6 -0
- package/_entity/permission-scope/ModuleBE_PermissionScopeDB.js +8 -0
- package/_entity/permission-scope/module-pack.d.ts +1 -0
- package/_entity/permission-scope/module-pack.js +3 -0
- package/_entity/user-permissions/ModuleBE_UserPermissionsAPI.d.ts +9 -0
- package/_entity/user-permissions/ModuleBE_UserPermissionsAPI.js +67 -0
- package/_entity/user-permissions/ModuleBE_UserPermissionsDB.d.ts +6 -0
- package/_entity/user-permissions/ModuleBE_UserPermissionsDB.js +8 -0
- package/_entity/user-permissions/module-pack.d.ts +2 -0
- package/_entity/user-permissions/module-pack.js +3 -0
- package/assertion-types.d.ts +9 -0
- package/consts.d.ts +7 -4
- package/consts.js +4 -2
- package/core/function-permission-registry.d.ts +24 -0
- package/core/function-permission-registry.js +60 -0
- package/core/module-pack.js +6 -7
- package/document-access-api.d.ts +6 -0
- package/document-access-api.js +49 -0
- package/document-access-enforcement.d.ts +9 -0
- package/document-access-enforcement.js +137 -0
- package/index.d.ts +14 -3
- package/index.js +14 -3
- package/modules/ModuleBE_Permissions.d.ts +63 -72
- package/modules/ModuleBE_Permissions.js +493 -339
- package/modules/ModuleBE_PermissionsAssert.d.ts +7 -38
- package/modules/ModuleBE_PermissionsAssert.js +53 -212
- package/package.json +16 -12
- package/PermissionKey_BE.d.ts +0 -13
- package/PermissionKey_BE.js +0 -48
- package/_entity/permission-access-level/ModuleBE_PermissionAccessLevelDB.d.ts +0 -17
- package/_entity/permission-access-level/ModuleBE_PermissionAccessLevelDB.js +0 -55
- package/_entity/permission-access-level/index.d.ts +0 -2
- package/_entity/permission-access-level/index.js +0 -2
- package/_entity/permission-access-level/module-pack.d.ts +0 -1
- package/_entity/permission-access-level/module-pack.js +0 -3
- package/_entity/permission-api/ModuleBE_PermissionAPIDB.d.ts +0 -12
- package/_entity/permission-api/ModuleBE_PermissionAPIDB.js +0 -62
- package/_entity/permission-api/index.d.ts +0 -2
- package/_entity/permission-api/index.js +0 -2
- package/_entity/permission-api/module-pack.d.ts +0 -1
- package/_entity/permission-api/module-pack.js +0 -3
- package/_entity/permission-domain/ModuleBE_PermissionDomainDB.d.ts +0 -15
- package/_entity/permission-domain/ModuleBE_PermissionDomainDB.js +0 -25
- package/_entity/permission-domain/index.d.ts +0 -2
- package/_entity/permission-domain/index.js +0 -2
- package/_entity/permission-domain/module-pack.d.ts +0 -1
- package/_entity/permission-domain/module-pack.js +0 -3
- package/_entity/permission-group/ModuleBE_PermissionGroupDB.d.ts +0 -14
- package/_entity/permission-group/ModuleBE_PermissionGroupDB.js +0 -62
- package/_entity/permission-group/index.d.ts +0 -2
- package/_entity/permission-group/index.js +0 -2
- package/_entity/permission-group/module-pack.d.ts +0 -1
- package/_entity/permission-group/module-pack.js +0 -3
- package/_entity/permission-project/ModuleBE_PermissionProjectDB.d.ts +0 -10
- package/_entity/permission-project/ModuleBE_PermissionProjectDB.js +0 -12
- package/_entity/permission-project/index.d.ts +0 -2
- package/_entity/permission-project/index.js +0 -2
- package/_entity/permission-project/module-pack.d.ts +0 -1
- package/_entity/permission-project/module-pack.js +0 -3
- package/_entity/permission-user/ModuleBE_PermissionUserAPI.d.ts +0 -8
- package/_entity/permission-user/ModuleBE_PermissionUserAPI.js +0 -13
- package/_entity/permission-user/ModuleBE_PermissionUserDB.d.ts +0 -37
- package/_entity/permission-user/ModuleBE_PermissionUserDB.js +0 -228
- package/_entity/permission-user/index.d.ts +0 -3
- package/_entity/permission-user/index.js +0 -3
- package/_entity/permission-user/module-pack.d.ts +0 -2
- package/_entity/permission-user/module-pack.js +0 -3
- package/_entity.d.ts +0 -12
- package/_entity.js +0 -18
- package/core/utils.d.ts +0 -25
- package/core/utils.js +0 -85
- package/modules/consts.d.ts +0 -11
- package/modules/consts.js +0 -29
- package/modules/index.d.ts +0 -1
- package/modules/index.js +0 -19
- package/permissions.d.ts +0 -23
- package/permissions.js +0 -159
- package/types.d.ts +0 -28
- /package/{types.js → assertion-types.js} +0 -0
|
@@ -1,48 +1,17 @@
|
|
|
1
|
-
import { Module
|
|
2
|
-
import { ServerApi_Middleware } from '@nu-art/
|
|
1
|
+
import { Module } from '@nu-art/ts-common';
|
|
2
|
+
import type { ServerApi_Middleware } from '@nu-art/http-server';
|
|
3
3
|
import { CollectSessionData } from '@nu-art/user-account-backend';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
[domainId: string]: number;
|
|
8
|
-
};
|
|
9
|
-
export type GroupPairWithBaseLevelsObj = {
|
|
10
|
-
accessLevels: Base_AccessLevel[];
|
|
11
|
-
};
|
|
12
|
-
export type RequestPairWithLevelsObj = {
|
|
13
|
-
accessLevels: DB_PermissionAccessLevel[];
|
|
14
|
-
};
|
|
4
|
+
import { SessionData_StrictMode } from '@nu-art/permissions-shared';
|
|
5
|
+
import type { PermissionScope } from '@nu-art/permissions-shared';
|
|
6
|
+
import type { PermissionAssertionContext } from '../assertion-types.js';
|
|
15
7
|
type Config = {
|
|
16
8
|
strictMode?: boolean;
|
|
17
9
|
};
|
|
18
|
-
/**
|
|
19
|
-
* [DomainId uniqueString]: accessLevel's numerical value
|
|
20
|
-
*/
|
|
21
10
|
export declare class ModuleBE_PermissionsAssert_Class extends Module<Config> implements CollectSessionData<SessionData_StrictMode> {
|
|
22
|
-
private projectId;
|
|
23
|
-
_keys: TypedMap<boolean>;
|
|
24
|
-
permissionKeys: TypedMap<PermissionKey_BE<any>>;
|
|
25
|
-
readonly Middleware: (keys?: string[]) => ServerApi_Middleware;
|
|
26
11
|
readonly LoadPermissionsMiddleware: ServerApi_Middleware;
|
|
27
|
-
readonly CustomMiddleware: (keys: string[], action: (projectId: string, customFields: StringMap) => Promise<void>) => ServerApi_Middleware;
|
|
28
12
|
__collectSessionData(): Promise<SessionData_StrictMode>;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
assertUserPermissions(projectId: string, path: string): Promise<void>;
|
|
32
|
-
assertUserPassesAccessLevels(domainToLevelValueMap: DomainToLevelValueMap, userPermissions: TypedMap<number>): void;
|
|
33
|
-
getApiDetails(_path: string, projectId: string): Promise<{
|
|
34
|
-
dbApi: DB_PermissionAPI;
|
|
35
|
-
requestPermissions: DB_PermissionAccessLevel[];
|
|
36
|
-
} | undefined>;
|
|
37
|
-
getApisDetails(urls: string[], projectId: string): Promise<({
|
|
38
|
-
apiDb: DB_PermissionAPI;
|
|
39
|
-
requestPermissions: DB_PermissionAccessLevel[];
|
|
40
|
-
} | undefined)[]>;
|
|
41
|
-
private getAccessLevels;
|
|
42
|
-
setProjectId: (projectId: string) => void;
|
|
43
|
-
getRegEx(value: string): RegExp;
|
|
44
|
-
registerPermissionKeys(keys: string[]): void;
|
|
45
|
-
private isStrictMode;
|
|
13
|
+
assertScopePermission(scope: PermissionScope, requiredValue: string): void;
|
|
14
|
+
createAssertionContext(): PermissionAssertionContext;
|
|
46
15
|
}
|
|
47
16
|
export declare const ModuleBE_PermissionsAssert: ModuleBE_PermissionsAssert_Class;
|
|
48
17
|
export {};
|
|
@@ -16,227 +16,68 @@
|
|
|
16
16
|
* See the License for the specific language governing permissions and
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import { MemKey_UserPermissions, SessionKey_Permissions_BE } from '../consts.js';
|
|
26
|
-
import { PermissionKey_BE } from '../PermissionKey_BE.js';
|
|
27
|
-
import { ModuleBE_PermissionAccessLevelDB, ModuleBE_PermissionAPIDB } from '../_entity.js';
|
|
28
|
-
/**
|
|
29
|
-
* [DomainId uniqueString]: accessLevel's numerical value
|
|
30
|
-
*/
|
|
19
|
+
import { ApiException, Module } from '@nu-art/ts-common';
|
|
20
|
+
import { stringToUniqueId } from '@nu-art/db-api-shared';
|
|
21
|
+
import { SessionKey_Account_BE } from '@nu-art/user-account-backend';
|
|
22
|
+
import { AccessScope_Self } from '@nu-art/permissions-shared';
|
|
23
|
+
import { MemKey_UserAccessIds, MemKey_UserEntityContexts, MemKey_UserScopePermissions } from '../consts.js';
|
|
24
|
+
import { ModuleBE_UserPermissionsDB } from '../_entity/user-permissions/ModuleBE_UserPermissionsDB.js';
|
|
31
25
|
export class ModuleBE_PermissionsAssert_Class extends Module {
|
|
32
|
-
projectId;
|
|
33
|
-
_keys = {};
|
|
34
|
-
permissionKeys = {};
|
|
35
|
-
// constructor() {
|
|
36
|
-
// super();
|
|
37
|
-
// this.setMinLevel(LogLevel.Debug);
|
|
38
|
-
// }
|
|
39
|
-
Middleware = (keys = []) => async () => {
|
|
40
|
-
await this.CustomMiddleware(keys, async (projectId) => {
|
|
41
|
-
return this.assertUserPermissions(projectId, MemKey_HttpRequestUrl.get());
|
|
42
|
-
})();
|
|
43
|
-
};
|
|
44
26
|
LoadPermissionsMiddleware = async () => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
CustomMiddleware = (keys, action) => async () => {
|
|
53
|
-
const customFields = {};
|
|
54
|
-
let object;
|
|
55
|
-
const reqMethod = MemKey_HttpRequestMethod.get();
|
|
56
|
-
switch (reqMethod) {
|
|
57
|
-
case HttpMethod.POST:
|
|
58
|
-
case HttpMethod.PATCH:
|
|
59
|
-
case HttpMethod.PUT:
|
|
60
|
-
object = MemKey_HttpRequestBody.get();
|
|
61
|
-
break;
|
|
62
|
-
case HttpMethod.GET:
|
|
63
|
-
case HttpMethod.DELETE:
|
|
64
|
-
object = MemKey_HttpRequestQuery.get();
|
|
65
|
-
break;
|
|
66
|
-
default:
|
|
67
|
-
throw new BadImplementationException(`Generic custom fields cannot be extracted on api with method: ${reqMethod}`);
|
|
68
|
-
}
|
|
69
|
-
_keys(object).filter(key => keys.includes(key)).forEach(key => {
|
|
70
|
-
const oElement = object[key];
|
|
71
|
-
if (oElement === undefined || oElement === null)
|
|
72
|
-
return;
|
|
73
|
-
if (typeof oElement !== 'string')
|
|
74
|
-
return;
|
|
75
|
-
customFields[key] = oElement;
|
|
76
|
-
});
|
|
77
|
-
const projectId = this.projectId;
|
|
78
|
-
await action(projectId, customFields);
|
|
27
|
+
const account = SessionKey_Account_BE.get();
|
|
28
|
+
const permissionsId = stringToUniqueId(account._id);
|
|
29
|
+
const entity = await ModuleBE_UserPermissionsDB.query.unique(permissionsId);
|
|
30
|
+
MemKey_UserScopePermissions.set(entity?.scopeEntries ?? []);
|
|
31
|
+
const personalGroupId = stringToUniqueId(account._id);
|
|
32
|
+
MemKey_UserAccessIds.set(entity?.accessIds ?? { [AccessScope_Self]: [personalGroupId] });
|
|
79
33
|
};
|
|
80
34
|
async __collectSessionData() {
|
|
81
|
-
return { key: 'strictMode', value: { isStrictMode: this.
|
|
82
|
-
}
|
|
83
|
-
init() {
|
|
84
|
-
super.init();
|
|
85
|
-
addRoutes([createBodyServerApi(ApiDef_PermissionsAssert.vv1.assertUserPermissions, this.assertPermission)]);
|
|
86
|
-
_keys(this._keys).forEach(key => this.permissionKeys[key] = new PermissionKey_BE(key));
|
|
87
|
-
ModuleBE_SyncManager.setModuleFilter(async (dbModules) => {
|
|
88
|
-
// return dbModules;
|
|
89
|
-
//Filter out any module we don't have permission to sync
|
|
90
|
-
const userPermissions = MemKey_UserPermissions.get();
|
|
91
|
-
const mapDbNameToApiModules = arrayToMap(RuntimeModules()
|
|
92
|
-
.filter((module) => !!module.apiDef && !!module.dbModule?.dbDef?.dbKey), item => item.dbModule.dbDef.dbKey);
|
|
93
|
-
const paths = dbModules.map(module => {
|
|
94
|
-
const mapDbNameToApiModule = mapDbNameToApiModules[module.dbDef.dbKey];
|
|
95
|
-
if (!mapDbNameToApiModule) {
|
|
96
|
-
// this.logWarning(`no module found for ${module.dbDef.dbKey}`);
|
|
97
|
-
return undefined;
|
|
98
|
-
}
|
|
99
|
-
return mapDbNameToApiModule.apiDef?.['v1']?.['query'].path;
|
|
100
|
-
});
|
|
101
|
-
// this.logWarning(`Paths(${paths.length}):`, paths);
|
|
102
|
-
const _allApis = await ModuleBE_PermissionAPIDB.query.where({});
|
|
103
|
-
const apis = _allApis.filter(_api => paths.includes(_api.path));
|
|
104
|
-
const mapPathToDBApi = arrayToMap(apis, api => api.path);
|
|
105
|
-
return dbModules.filter((dbModule, index) => {
|
|
106
|
-
const path = paths[index];
|
|
107
|
-
if (!path) {
|
|
108
|
-
// this.logWarningBold('no path');
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
const dbApi = mapPathToDBApi[path];
|
|
112
|
-
if (!dbApi) {
|
|
113
|
-
// this.logWarningBold(`no dbApi ${path}`);
|
|
114
|
-
return !ModuleBE_PermissionsAssert.isStrictMode();
|
|
115
|
-
}
|
|
116
|
-
const accessLevels = dbApi._accessLevels;
|
|
117
|
-
return _keys(accessLevels).reduce((hasAccess, domainId) => {
|
|
118
|
-
if (!hasAccess)
|
|
119
|
-
return false;
|
|
120
|
-
const userDomainAccessValue = userPermissions[domainId];
|
|
121
|
-
const apiRequiredAccessValue = accessLevels[domainId];
|
|
122
|
-
if (!userDomainAccessValue)
|
|
123
|
-
return false;
|
|
124
|
-
if (!exists(userDomainAccessValue) || userDomainAccessValue < apiRequiredAccessValue) {
|
|
125
|
-
this.logErrorBold(`${(userDomainAccessValue ?? 0)} < ${apiRequiredAccessValue} === ${(userDomainAccessValue ?? 0) < apiRequiredAccessValue}`);
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
return hasAccess;
|
|
129
|
-
}, true);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
35
|
+
return { key: 'strictMode', value: { isStrictMode: !!this.config?.strictMode } };
|
|
132
36
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!this.config.strictMode)
|
|
148
|
-
return;
|
|
149
|
-
throw new ApiException(403, `No permissions configuration specified for api: ${projectId ? `${projectId}--` : ''}${path}`);
|
|
37
|
+
assertScopePermission(scope, requiredValue) {
|
|
38
|
+
const userPerms = MemKey_UserScopePermissions.get();
|
|
39
|
+
const prefix = scope.key + ':';
|
|
40
|
+
const entry = userPerms.find(p => p.startsWith(prefix));
|
|
41
|
+
if (!entry)
|
|
42
|
+
throw new ApiException(403, `No access for scope: ${scope.key}`);
|
|
43
|
+
const userValue = entry.substring(prefix.length);
|
|
44
|
+
const requiredIdx = scope.values.indexOf(requiredValue);
|
|
45
|
+
if (requiredIdx === -1)
|
|
46
|
+
throw new ApiException(503, `Unknown permission value '${requiredValue}' for scope '${scope.key}'`);
|
|
47
|
+
const userIdx = scope.values.indexOf(userValue);
|
|
48
|
+
if (userIdx === -1 || userIdx < requiredIdx) {
|
|
49
|
+
this.logErrorBold(`scope permission denied: ${scope.key} (has: ${userValue}, needs: ${requiredValue})`);
|
|
50
|
+
throw new ApiException(403, `Insufficient access for scope: ${scope.key}`);
|
|
150
51
|
}
|
|
151
|
-
//_accessLevels is a map[domain id <> access level numeric value]
|
|
152
|
-
this.assertUserPassesAccessLevels(apiDetails.dbApi._accessLevels, userPermissions);
|
|
153
52
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (!exists(userDomainPermission))
|
|
158
|
-
throw new ApiException(403, 'Missing Access For This Domain');
|
|
159
|
-
if (userDomainPermission < domainToLevelValueMap[domainId]) {
|
|
160
|
-
this.logErrorBold(`for domain - userAccessLevel <> expectedAccessLevel: "${domainId}" ${(userDomainPermission ?? 0)} <> ${domainToLevelValueMap[domainId]}`);
|
|
161
|
-
throw new ApiException(403, 'Action Forbidden');
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
async getApiDetails(_path, projectId) {
|
|
166
|
-
let path = _path.substring(0, (_path + '?').indexOf('?')); //Get raw path without query
|
|
167
|
-
if (path.at(0) === '/')
|
|
168
|
-
path = path.substring(1);
|
|
169
|
-
this.logDebug(`Fetching Permission API for path: ${path} and project id: ${projectId}`);
|
|
170
|
-
const dbApi = (await ModuleBE_PermissionAPIDB.query.custom({
|
|
171
|
-
where: {
|
|
172
|
-
path,
|
|
173
|
-
projectId
|
|
174
|
-
}
|
|
175
|
-
}))[0];
|
|
176
|
-
if (!dbApi)
|
|
177
|
-
return undefined;
|
|
178
|
-
const requestPermissions = await this.getAccessLevels(dbApi.accessLevelIds || []);
|
|
53
|
+
createAssertionContext() {
|
|
54
|
+
const userPerms = MemKey_UserScopePermissions.get();
|
|
55
|
+
const entityContexts = MemKey_UserEntityContexts.get();
|
|
179
56
|
return {
|
|
180
|
-
|
|
181
|
-
|
|
57
|
+
hasScope: (scope, value) => {
|
|
58
|
+
const prefix = scope.key + ':';
|
|
59
|
+
const entry = userPerms.find(p => p.startsWith(prefix));
|
|
60
|
+
if (!entry)
|
|
61
|
+
return false;
|
|
62
|
+
const userValue = entry.substring(prefix.length);
|
|
63
|
+
const requiredIdx = scope.values.indexOf(value);
|
|
64
|
+
if (requiredIdx === -1)
|
|
65
|
+
return false;
|
|
66
|
+
const userIdx = scope.values.indexOf(userValue);
|
|
67
|
+
return userIdx >= requiredIdx;
|
|
68
|
+
},
|
|
69
|
+
ownsEntity: async (pointer) => {
|
|
70
|
+
return entityContexts.some(ctx => ctx.dbKey === pointer.dbKey && ctx.id === pointer.id);
|
|
71
|
+
},
|
|
72
|
+
and: async (...predicates) => {
|
|
73
|
+
const results = await Promise.all(predicates);
|
|
74
|
+
return results.every(r => r);
|
|
75
|
+
},
|
|
76
|
+
or: async (...predicates) => {
|
|
77
|
+
const results = await Promise.all(predicates);
|
|
78
|
+
return results.some(r => r);
|
|
79
|
+
},
|
|
182
80
|
};
|
|
183
81
|
}
|
|
184
|
-
async getApisDetails(urls, projectId) {
|
|
185
|
-
const paths = urls.map(_path => _path.substring(0, (_path + '?').indexOf('?')));
|
|
186
|
-
const apiDbs = await batchActionParallel(paths, 10, elements => ModuleBE_PermissionAPIDB.query.custom({
|
|
187
|
-
where: {
|
|
188
|
-
projectId,
|
|
189
|
-
path: { $in: elements }
|
|
190
|
-
}
|
|
191
|
-
}));
|
|
192
|
-
return Promise.all(paths.map(async (path) => {
|
|
193
|
-
const apiDb = apiDbs.find(_apiDb => _apiDb.path === path);
|
|
194
|
-
if (!apiDb)
|
|
195
|
-
return;
|
|
196
|
-
try {
|
|
197
|
-
const requestPermissions = await this.getAccessLevels(apiDb.accessLevelIds);
|
|
198
|
-
return ({
|
|
199
|
-
apiDb,
|
|
200
|
-
requestPermissions
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
catch (e) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
}));
|
|
207
|
-
}
|
|
208
|
-
async getAccessLevels(_accessLevelIds) {
|
|
209
|
-
const accessLevelIds = filterDuplicates(_accessLevelIds || []);
|
|
210
|
-
const requestPermissions = filterInstances(await ModuleBE_PermissionAccessLevelDB.query.all(accessLevelIds));
|
|
211
|
-
const idNotFound = accessLevelIds.find(lId => !requestPermissions.find(r => r._id === lId));
|
|
212
|
-
if (idNotFound)
|
|
213
|
-
throw new ApiException(404, `Could not find api level with _id: ${idNotFound}`);
|
|
214
|
-
return requestPermissions;
|
|
215
|
-
}
|
|
216
|
-
setProjectId = (projectId) => {
|
|
217
|
-
this.projectId = projectId;
|
|
218
|
-
};
|
|
219
|
-
getRegEx(value) {
|
|
220
|
-
if (!value)
|
|
221
|
-
return new RegExp(`^${value}$`, 'g');
|
|
222
|
-
let regExValue = value;
|
|
223
|
-
const startRegEx = '^';
|
|
224
|
-
const endRegEx = '$';
|
|
225
|
-
if (value[0] !== startRegEx)
|
|
226
|
-
regExValue = startRegEx + regExValue;
|
|
227
|
-
if (value[value.length - 1] !== endRegEx)
|
|
228
|
-
regExValue = regExValue + endRegEx;
|
|
229
|
-
return new RegExp(regExValue, 'g');
|
|
230
|
-
}
|
|
231
|
-
registerPermissionKeys(keys) {
|
|
232
|
-
keys.forEach(key => {
|
|
233
|
-
if (this._keys[key])
|
|
234
|
-
throw new ImplementationMissingException(`Registered PermissionKey '${key}' more than once!`);
|
|
235
|
-
this._keys[key] = true;
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
isStrictMode() {
|
|
239
|
-
return !!this.config.strictMode;
|
|
240
|
-
}
|
|
241
82
|
}
|
|
242
83
|
export const ModuleBE_PermissionsAssert = new ModuleBE_PermissionsAssert_Class();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nu-art/permissions-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.500.6",
|
|
4
4
|
"description": "Permissions Backend",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"TacB0sS",
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"nu-art",
|
|
12
12
|
"permissions",
|
|
13
13
|
"saml",
|
|
14
|
-
"thunderstorm",
|
|
15
14
|
"typescript",
|
|
16
15
|
"user-account"
|
|
17
16
|
],
|
|
@@ -35,15 +34,14 @@
|
|
|
35
34
|
"test": "ts-mocha -w -p src/test/tsconfig.json --timeout 0 --inspect=8107 --watch-files '**/*.ts' src/test/__all-tests.ts"
|
|
36
35
|
},
|
|
37
36
|
"dependencies": {
|
|
38
|
-
"@nu-art/
|
|
39
|
-
"@nu-art/
|
|
40
|
-
"@nu-art/firebase-
|
|
41
|
-
"@nu-art/
|
|
42
|
-
"@nu-art/
|
|
43
|
-
"@nu-art/
|
|
44
|
-
"@nu-art/
|
|
45
|
-
"@nu-art/user-account-
|
|
46
|
-
"@nu-art/user-account-shared": "0.401.9",
|
|
37
|
+
"@nu-art/action-processor-backend": "0.500.6",
|
|
38
|
+
"@nu-art/permissions-shared": "0.500.6",
|
|
39
|
+
"@nu-art/firebase-backend": "0.500.6",
|
|
40
|
+
"@nu-art/firebase-shared": "0.500.6",
|
|
41
|
+
"@nu-art/google-services-backend": "0.500.6",
|
|
42
|
+
"@nu-art/ts-common": "0.500.6",
|
|
43
|
+
"@nu-art/user-account-backend": "0.500.6",
|
|
44
|
+
"@nu-art/user-account-shared": "0.500.6",
|
|
47
45
|
"express": "^4.18.2",
|
|
48
46
|
"firebase": "^11.9.0",
|
|
49
47
|
"firebase-admin": "13.4.0",
|
|
@@ -52,9 +50,14 @@
|
|
|
52
50
|
"react": "^18.0.0",
|
|
53
51
|
"react-dom": "^18.0.0",
|
|
54
52
|
"react-router-dom": "^6.9.0",
|
|
55
|
-
"saml2-js": "^4.0.1"
|
|
53
|
+
"saml2-js": "^4.0.1",
|
|
54
|
+
"@nu-art/http-server": "0.500.6",
|
|
55
|
+
"@nu-art/api-types": "0.500.6",
|
|
56
|
+
"@nu-art/db-api-backend": "0.500.6",
|
|
57
|
+
"@nu-art/db-api-shared": "0.500.6"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
60
|
+
"@nu-art/testalot": "0.500.6",
|
|
58
61
|
"@types/react": "^18.0.0",
|
|
59
62
|
"@types/express": "^4.17.17",
|
|
60
63
|
"@types/react-dom": "^18.0.0",
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
"@types/chai": "^4.3.4",
|
|
64
67
|
"@types/mocha": "^10.0.1",
|
|
65
68
|
"@types/history": "^4.7.2",
|
|
69
|
+
"@types/request": "^2.48.1",
|
|
66
70
|
"@types/saml2-js": "^1.6.8"
|
|
67
71
|
},
|
|
68
72
|
"unitConfig": {
|
package/PermissionKey_BE.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { TypedKeyValue } from '@nu-art/ts-common';
|
|
2
|
-
import { AppConfigKey_BE } from '@nu-art/thunderstorm-backend';
|
|
3
|
-
import { DB_PermissionKeyData } from '@nu-art/permissions-shared';
|
|
4
|
-
type Resolver = () => Promise<DB_PermissionKeyData>;
|
|
5
|
-
export declare class PermissionKey_BE<K extends string> extends AppConfigKey_BE<TypedKeyValue<K, DB_PermissionKeyData>> {
|
|
6
|
-
static _resolver: Resolver;
|
|
7
|
-
static buildData: (data: DB_PermissionKeyData) => Promise<DB_PermissionKeyData>;
|
|
8
|
-
constructor(key: K, initialDataResolver?: Resolver);
|
|
9
|
-
set(value: DB_PermissionKeyData): Promise<void>;
|
|
10
|
-
}
|
|
11
|
-
export declare const defaultValueResolverV2: (domainId: string, accessLevelName: string) => Promise<DB_PermissionKeyData>;
|
|
12
|
-
export declare const defaultValueResolver: (domainNamespace: string, accessLevelValue: number) => Promise<DB_PermissionKeyData>;
|
|
13
|
-
export {};
|
package/PermissionKey_BE.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { filterInstances } from '@nu-art/ts-common';
|
|
2
|
-
import { ModuleBE_PermissionAccessLevelDB, ModuleBE_PermissionDomainDB } from './_entity.js';
|
|
3
|
-
import { AppConfigKey_BE, ModuleBE_AppConfigDB } from '@nu-art/thunderstorm-backend';
|
|
4
|
-
import { Const_PermissionKeyType } from '@nu-art/permissions-shared';
|
|
5
|
-
export class PermissionKey_BE extends AppConfigKey_BE {
|
|
6
|
-
static _resolver = async () => {
|
|
7
|
-
return { type: Const_PermissionKeyType, accessLevelIds: [], _accessLevels: {} };
|
|
8
|
-
};
|
|
9
|
-
static buildData = async (data) => {
|
|
10
|
-
ModuleBE_AppConfigDB.logVerbose('**************** Building Data ****************');
|
|
11
|
-
const accessLevels = filterInstances(await ModuleBE_PermissionAccessLevelDB.query.all(data.accessLevelIds));
|
|
12
|
-
const _data = {
|
|
13
|
-
type: 'permission-key',
|
|
14
|
-
accessLevelIds: data.accessLevelIds,
|
|
15
|
-
_accessLevels: accessLevels.reduce((acc, level) => {
|
|
16
|
-
acc[level.domainId] = level.value;
|
|
17
|
-
return acc;
|
|
18
|
-
}, {})
|
|
19
|
-
};
|
|
20
|
-
ModuleBE_AppConfigDB.logVerbose('**************** Data ****************');
|
|
21
|
-
ModuleBE_AppConfigDB.logVerbose(_data);
|
|
22
|
-
return _data;
|
|
23
|
-
};
|
|
24
|
-
constructor(key, initialDataResolver) {
|
|
25
|
-
super(key, initialDataResolver ?? PermissionKey_BE._resolver, PermissionKey_BE.buildData);
|
|
26
|
-
}
|
|
27
|
-
async set(value) {
|
|
28
|
-
const dbValue = await PermissionKey_BE.buildData(value);
|
|
29
|
-
await super.set(dbValue);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export const defaultValueResolverV2 = async (domainId, accessLevelName) => {
|
|
33
|
-
const accessLevel = await ModuleBE_PermissionAccessLevelDB.query.uniqueCustom({ where: { domainId, name: accessLevelName } });
|
|
34
|
-
return {
|
|
35
|
-
type: Const_PermissionKeyType,
|
|
36
|
-
accessLevelIds: [accessLevel._id],
|
|
37
|
-
_accessLevels: { [accessLevel._id]: accessLevel.value }
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
export const defaultValueResolver = async (domainNamespace, accessLevelValue) => {
|
|
41
|
-
const domain = await ModuleBE_PermissionDomainDB.query.uniqueCustom({ where: { namespace: domainNamespace } });
|
|
42
|
-
const accessLevel = await ModuleBE_PermissionAccessLevelDB.query.uniqueCustom({ where: { domainId: domain._id, value: accessLevelValue } });
|
|
43
|
-
return {
|
|
44
|
-
type: Const_PermissionKeyType,
|
|
45
|
-
accessLevelIds: [accessLevel._id],
|
|
46
|
-
_accessLevels: { [accessLevel._id]: accessLevel.value }
|
|
47
|
-
};
|
|
48
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { DBApiConfigV3, ModuleBE_BaseDB } from '@nu-art/thunderstorm-backend';
|
|
2
|
-
import { Clause_Where } from '@nu-art/firebase-shared';
|
|
3
|
-
import { Transaction } from 'firebase-admin/firestore';
|
|
4
|
-
import { CollectionActionType, PostWriteProcessingData } from '@nu-art/firebase-backend/firestore-v3/FirestoreCollectionV3';
|
|
5
|
-
import { DB_PermissionAccessLevel, DBProto_PermissionAccessLevel } from '@nu-art/permissions-shared';
|
|
6
|
-
type Config = DBApiConfigV3<DBProto_PermissionAccessLevel> & {};
|
|
7
|
-
export declare class ModuleBE_PermissionAccessLevelDB_Class extends ModuleBE_BaseDB<DBProto_PermissionAccessLevel, Config> {
|
|
8
|
-
constructor();
|
|
9
|
-
protected internalFilter(item: DB_PermissionAccessLevel): Clause_Where<DB_PermissionAccessLevel>[];
|
|
10
|
-
protected preWriteProcessing(dbInstance: DB_PermissionAccessLevel, originalDbInstance: DBProto_PermissionAccessLevel['dbType'], transaction?: Transaction): Promise<void>;
|
|
11
|
-
protected postWriteProcessing(data: PostWriteProcessingData<DBProto_PermissionAccessLevel>, actionType: CollectionActionType, transaction?: Transaction): Promise<void>;
|
|
12
|
-
protected assertDeletion(transaction: Transaction, dbInstance: DB_PermissionAccessLevel): Promise<void>;
|
|
13
|
-
private upgrade_100_101;
|
|
14
|
-
}
|
|
15
|
-
export declare const ModuleBE_PermissionAccessLevelDB: ModuleBE_PermissionAccessLevelDB_Class;
|
|
16
|
-
export declare function checkDuplicateLevelsDomain(levels: DB_PermissionAccessLevel[]): void;
|
|
17
|
-
export {};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { ModuleBE_BaseDB, } from '@nu-art/thunderstorm-backend';
|
|
2
|
-
import { ApiException, batchActionParallel, dbObjectToId, filterDuplicates } from '@nu-art/ts-common';
|
|
3
|
-
import { MemKey_AccountId } from '@nu-art/user-account-backend';
|
|
4
|
-
import { ModuleBE_PermissionAPIDB } from '../permission-api/index.js';
|
|
5
|
-
import { ModuleBE_PermissionDomainDB } from '../permission-domain/index.js';
|
|
6
|
-
import { ModuleBE_PermissionGroupDB } from '../permission-group/index.js';
|
|
7
|
-
import { DBDef_PermissionAccessLevel } from '@nu-art/permissions-shared';
|
|
8
|
-
export class ModuleBE_PermissionAccessLevelDB_Class extends ModuleBE_BaseDB {
|
|
9
|
-
constructor() {
|
|
10
|
-
super(DBDef_PermissionAccessLevel);
|
|
11
|
-
this.registerVersionUpgradeProcessor('1.0.0', this.upgrade_100_101);
|
|
12
|
-
}
|
|
13
|
-
internalFilter(item) {
|
|
14
|
-
const { domainId, name, value } = item;
|
|
15
|
-
return [{ domainId, name }, { domainId, value }];
|
|
16
|
-
}
|
|
17
|
-
async preWriteProcessing(dbInstance, originalDbInstance, transaction) {
|
|
18
|
-
await ModuleBE_PermissionDomainDB.query.uniqueAssert(dbInstance.domainId);
|
|
19
|
-
dbInstance._auditorId = MemKey_AccountId.get();
|
|
20
|
-
}
|
|
21
|
-
async postWriteProcessing(data, actionType, transaction) {
|
|
22
|
-
const deleted = data.deleted ? (Array.isArray(data.deleted) ? data.deleted : [data.deleted]) : [];
|
|
23
|
-
const updated = data.updated ? (Array.isArray(data.updated) ? data.updated : [data.updated]) : [];
|
|
24
|
-
//Collect all apis that hold an access level id in the levels that have changed
|
|
25
|
-
const deletedIds = deleted.map(dbObjectToId);
|
|
26
|
-
const levelIds = [...deletedIds, ...updated.map(dbObjectToId)];
|
|
27
|
-
const _connectedApis = await batchActionParallel(levelIds, 10, async (ids) => await ModuleBE_PermissionAPIDB.query.custom({ where: { accessLevelIds: { $aca: ids } } }));
|
|
28
|
-
const connectedApis = filterDuplicates(_connectedApis, api => api._id);
|
|
29
|
-
deletedIds.forEach(id => {
|
|
30
|
-
//For each deleted level remove it from any api that held it
|
|
31
|
-
connectedApis.forEach(api => {
|
|
32
|
-
api.accessLevelIds = api.accessLevelIds?.filter(i => i !== id);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
//Send all apis to upsert so their _accessLevels update
|
|
36
|
-
await ModuleBE_PermissionAPIDB.set.all(connectedApis);
|
|
37
|
-
return super.postWriteProcessing(data, actionType, transaction);
|
|
38
|
-
}
|
|
39
|
-
async assertDeletion(transaction, dbInstance) {
|
|
40
|
-
const groups = await ModuleBE_PermissionGroupDB.query.custom({ where: { accessLevelIds: { $ac: dbInstance._id } } });
|
|
41
|
-
const apis = await ModuleBE_PermissionAPIDB.query.custom({ where: { accessLevelIds: { $ac: dbInstance._id } } });
|
|
42
|
-
if (groups.length || apis.length)
|
|
43
|
-
throw new ApiException(403, 'You trying delete access level that associated with users/groups/apis, you need delete the associations first');
|
|
44
|
-
}
|
|
45
|
-
upgrade_100_101 = async (items) => {
|
|
46
|
-
items.forEach(accessLevel => accessLevel.uiLabel = accessLevel.name);
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
export const ModuleBE_PermissionAccessLevelDB = new ModuleBE_PermissionAccessLevelDB_Class();
|
|
50
|
-
export function checkDuplicateLevelsDomain(levels) {
|
|
51
|
-
const domainIds = levels.map(level => level.domainId);
|
|
52
|
-
const filteredDomainIds = filterDuplicates(domainIds);
|
|
53
|
-
if (filteredDomainIds.length !== domainIds.length)
|
|
54
|
-
throw new ApiException(422, 'You trying test-add-data duplicate accessLevel with the same domain');
|
|
55
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const ModulePackBE_PermissionAccessLevel: (import("./ModuleBE_PermissionAccessLevelDB.js").ModuleBE_PermissionAccessLevelDB_Class | import("@nu-art/thunderstorm-backend").ModuleBE_BaseApi_Class<import("@nu-art/permissions-shared").DBProto_PermissionAccessLevel>)[];
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { createApisForDBModuleV3 } from '@nu-art/thunderstorm-backend';
|
|
2
|
-
import { ModuleBE_PermissionAccessLevelDB } from './ModuleBE_PermissionAccessLevelDB.js';
|
|
3
|
-
export const ModulePackBE_PermissionAccessLevel = [ModuleBE_PermissionAccessLevelDB, createApisForDBModuleV3(ModuleBE_PermissionAccessLevelDB)];
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { DBApiConfigV3, ModuleBE_BaseDB, ServerApi } from '@nu-art/thunderstorm-backend';
|
|
2
|
-
import { DB_PermissionAPI, DBProto_PermissionAPI } from '@nu-art/permissions-shared';
|
|
3
|
-
import { Transaction } from 'firebase-admin/firestore';
|
|
4
|
-
type Config = DBApiConfigV3<DBProto_PermissionAPI> & {};
|
|
5
|
-
export declare class ModuleBE_PermissionAPIDB_Class extends ModuleBE_BaseDB<DBProto_PermissionAPI, Config> {
|
|
6
|
-
constructor();
|
|
7
|
-
protected preWriteProcessing(instance: DB_PermissionAPI, originalDbInstance: DBProto_PermissionAPI['dbType'], t?: Transaction): Promise<void>;
|
|
8
|
-
registerApis(projectId: string, routes: string[]): Promise<DB_PermissionAPI[]>;
|
|
9
|
-
apiUpsert(): ServerApi<any> | undefined;
|
|
10
|
-
}
|
|
11
|
-
export declare const ModuleBE_PermissionAPIDB: ModuleBE_PermissionAPIDB_Class;
|
|
12
|
-
export {};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { ModuleBE_BaseDB, } from '@nu-art/thunderstorm-backend';
|
|
2
|
-
import { DBDef_PermissionAPI } from '@nu-art/permissions-shared';
|
|
3
|
-
import { dbObjectToId, filterInstances } from '@nu-art/ts-common';
|
|
4
|
-
import { ModuleBE_PermissionAccessLevelDB } from '../permission-access-level/index.js';
|
|
5
|
-
import { MemKey_AccountId } from '@nu-art/user-account-backend';
|
|
6
|
-
import { ModuleBE_PermissionProjectDB } from '../permission-project/index.js';
|
|
7
|
-
import { HttpCodes } from '@nu-art/ts-common/core/exceptions/http-codes';
|
|
8
|
-
import { trimStartingForwardSlash } from '@nu-art/thunderstorm-shared/route-tools';
|
|
9
|
-
export class ModuleBE_PermissionAPIDB_Class extends ModuleBE_BaseDB {
|
|
10
|
-
constructor() {
|
|
11
|
-
super(DBDef_PermissionAPI);
|
|
12
|
-
this.registerVersionUpgradeProcessor('1.0.0', async (instances) => {
|
|
13
|
-
}); // adjustment made in pre-write requires us to do this in order to upgrade the data
|
|
14
|
-
}
|
|
15
|
-
async preWriteProcessing(instance, originalDbInstance, t) {
|
|
16
|
-
await ModuleBE_PermissionProjectDB.query.uniqueAssert(instance.projectId);
|
|
17
|
-
// clean '/' from api path start
|
|
18
|
-
instance.path = trimStartingForwardSlash(instance.path);
|
|
19
|
-
// set who created this
|
|
20
|
-
instance._auditorId = MemKey_AccountId.get();
|
|
21
|
-
const accessLevelIds = new Set();
|
|
22
|
-
const duplicateAccessLevelIds = new Set();
|
|
23
|
-
//Check for duplicated Unique IDs
|
|
24
|
-
instance.accessLevelIds?.forEach(id => {
|
|
25
|
-
const duplicate = accessLevelIds.has(id);
|
|
26
|
-
accessLevelIds.add(id);
|
|
27
|
-
if (duplicate)
|
|
28
|
-
duplicateAccessLevelIds.add(id);
|
|
29
|
-
});
|
|
30
|
-
if (duplicateAccessLevelIds.size)
|
|
31
|
-
throw HttpCodes._4XX.BAD_REQUEST('Could not update permission api', `Trying to create API with duplicate access levels: ${duplicateAccessLevelIds}`);
|
|
32
|
-
// Verify all AccessLevels actually exist, and assign _accessLevels
|
|
33
|
-
if (instance.accessLevelIds?.length) {
|
|
34
|
-
const dbAccessLevels = filterInstances(await ModuleBE_PermissionAccessLevelDB.query.all(instance.accessLevelIds));
|
|
35
|
-
if (dbAccessLevels.length !== instance.accessLevelIds.length) {
|
|
36
|
-
const dbAccessLevelIds = dbAccessLevels.map(dbObjectToId);
|
|
37
|
-
throw HttpCodes._4XX.NOT_FOUND('Could not update permission api', `Asked to assign an api non existing accessLevels: ${instance.accessLevelIds.filter(id => !dbAccessLevelIds.includes(id))}`);
|
|
38
|
-
}
|
|
39
|
-
dbAccessLevels.forEach(accessLevel => {
|
|
40
|
-
if (!instance._accessLevels)
|
|
41
|
-
instance._accessLevels = {};
|
|
42
|
-
instance._accessLevels[accessLevel.domainId] = accessLevel.value;
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
instance._accessLevels = {};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
registerApis(projectId, routes) {
|
|
50
|
-
return this.runTransaction(async (transaction) => {
|
|
51
|
-
const existingProjectApis = await this.query.custom({ where: { projectId: projectId } }, transaction);
|
|
52
|
-
const apisToAdd = routes
|
|
53
|
-
.filter(path => !existingProjectApis.find(api => api.path === path))
|
|
54
|
-
.map(path => ({ path, projectId: projectId, _auditorId: MemKey_AccountId.get() }));
|
|
55
|
-
return this.set.all(apisToAdd, transaction);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
apiUpsert() {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
export const ModuleBE_PermissionAPIDB = new ModuleBE_PermissionAPIDB_Class();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const ModulePackBE_PermissionAPI: (import("./ModuleBE_PermissionAPIDB.js").ModuleBE_PermissionAPIDB_Class | import("@nu-art/thunderstorm-backend").ModuleBE_BaseApi_Class<import("@nu-art/permissions-shared").DBProto_PermissionAPI>)[];
|