@transmit-security/rbac 1.0.0-beta
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +18 -0
- package/dist/src/definitions/action.js +31 -0
- package/dist/src/definitions/resources/administration-resources.js +12 -0
- package/dist/src/definitions/resources/app-resources.js +43 -0
- package/dist/src/definitions/resources/drs-resources.js +53 -0
- package/dist/src/definitions/resources/events-resources.js +20 -0
- package/dist/src/definitions/resources/idv-resources.js +32 -0
- package/dist/src/definitions/resources/index.js +30 -0
- package/dist/src/definitions/resources/oidc-resource-resources.js +9 -0
- package/dist/src/definitions/resources/orc-resources.js +26 -0
- package/dist/src/definitions/resources/organization-resources.js +12 -0
- package/dist/src/definitions/resources/service-provider-resources.js +9 -0
- package/dist/src/definitions/resources/user-resources.js +9 -0
- package/dist/src/index.js +53 -0
- package/dist/src/infra/permission-selector-builder.js +50 -0
- package/dist/src/infra/permission.js +83 -0
- package/dist/src/infra/placeHolders.js +7 -0
- package/dist/src/infra/resource-class-builder.js +277 -0
- package/dist/src/infra/resource-registry.js +22 -0
- package/dist/src/infra/resource.js +93 -0
- package/dist/src/infra/wildcard.js +6 -0
- package/dist/src/utils/is-valid-enum-value.js +8 -0
- package/package.json +38 -0
package/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# @transmit-security/rbac
|
2
|
+
|
3
|
+
RBAC impl of Transmt sec
|
4
|
+
|
5
|
+
### Usage
|
6
|
+
|
7
|
+
```js
|
8
|
+
import { Permission, Action, AppResourceDefinition } from '@transmit-security/rbac';
|
9
|
+
|
10
|
+
const userPermission = new Permission(Action.read, AppResourceDefinition);
|
11
|
+
|
12
|
+
if (userPermission.allows([Action.write, AppResourceDefinition.type])) {
|
13
|
+
// perform the operation
|
14
|
+
} else {
|
15
|
+
// return error
|
16
|
+
}
|
17
|
+
|
18
|
+
```
|
@@ -0,0 +1,31 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Action = void 0;
|
4
|
+
var Action;
|
5
|
+
(function (Action) {
|
6
|
+
/** Create a resource. */
|
7
|
+
Action["create"] = "create";
|
8
|
+
/** Read a single resource. This should not allow searching or listing similar resources, only reading a specific one.
|
9
|
+
for example, this can be used for the `/users/:id` endpoint, but not for `/users` (at least not without additional actions).
|
10
|
+
*/
|
11
|
+
Action["read"] = "read";
|
12
|
+
/** Edit a single resource. This should not allow deleting that resource or creating similar resources. */
|
13
|
+
Action["edit"] = "edit";
|
14
|
+
/** Delete resources. This can be used for bulk-delete as well. */
|
15
|
+
Action["delete"] = "delete";
|
16
|
+
/** List resources. This should be used for list and search endpoints, where resource IDs or resource details are returned without
|
17
|
+
* their IDs being known to the caller. for example, if the `/users` endpoint returns a list of all user IDs, this can be used to
|
18
|
+
* guard it. but this should not be used for `/users/:id`.
|
19
|
+
*
|
20
|
+
* If an endpoint returns not just resource IDs but also some details (e.g search users which returns name and email), then the
|
21
|
+
* endpoint should be guarded by the `read` permission as well as `list`.
|
22
|
+
*/
|
23
|
+
Action["list"] = "list";
|
24
|
+
/** Execute a resource. Currently the only resources we can execute are FlexId journeys, but perhaps in the future we'll extend
|
25
|
+
* this capability to users who complain too much.
|
26
|
+
*/
|
27
|
+
Action["execute"] = "execute";
|
28
|
+
/** All actions. This grants the ability to perform any of the other actions. */
|
29
|
+
Action["all"] = "*";
|
30
|
+
})(Action || (exports.Action = Action = {}));
|
31
|
+
//# sourceMappingURL=action.js.map
|
@@ -0,0 +1,12 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.AdministrationResourceDefinition = void 0;
|
4
|
+
exports.AdministrationResourceDefinition = {
|
5
|
+
type: 'simple',
|
6
|
+
id: 'administration',
|
7
|
+
children: {
|
8
|
+
adminUsers: { type: 'collection', id: 'admin-users', key: 'adminId' },
|
9
|
+
adminRoles: { type: 'collection', id: 'admin-roles', key: 'roleId' },
|
10
|
+
},
|
11
|
+
};
|
12
|
+
//# sourceMappingURL=administration-resources.js.map
|
@@ -0,0 +1,43 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.AppResourceDefinition = void 0;
|
4
|
+
exports.AppResourceDefinition = {
|
5
|
+
type: 'collection',
|
6
|
+
id: 'apps',
|
7
|
+
key: 'appId',
|
8
|
+
children: {
|
9
|
+
config: {
|
10
|
+
type: 'simple',
|
11
|
+
id: 'config',
|
12
|
+
children: {
|
13
|
+
idv: {
|
14
|
+
type: 'simple',
|
15
|
+
id: 'idv',
|
16
|
+
children: {
|
17
|
+
identityExperienceManagement: {
|
18
|
+
type: 'simple',
|
19
|
+
id: 'identity-experience-management',
|
20
|
+
children: {
|
21
|
+
settings: { type: 'simple', id: 'settings' },
|
22
|
+
consent: { type: 'simple', id: 'consent' },
|
23
|
+
branding: { type: 'simple', id: 'branding' },
|
24
|
+
},
|
25
|
+
},
|
26
|
+
identityRestrictionCriteria: {
|
27
|
+
type: 'simple',
|
28
|
+
id: 'identity-restriction-criteria',
|
29
|
+
},
|
30
|
+
},
|
31
|
+
},
|
32
|
+
drs: {
|
33
|
+
type: 'simple',
|
34
|
+
id: 'drs',
|
35
|
+
children: {
|
36
|
+
privateIdentifier: { type: 'simple', id: 'private-identifier' },
|
37
|
+
},
|
38
|
+
},
|
39
|
+
},
|
40
|
+
},
|
41
|
+
},
|
42
|
+
};
|
43
|
+
//# sourceMappingURL=app-resources.js.map
|
@@ -0,0 +1,53 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.drsResourceDefinition = void 0;
|
4
|
+
exports.drsResourceDefinition = {
|
5
|
+
type: 'simple',
|
6
|
+
id: 'drs',
|
7
|
+
children: {
|
8
|
+
recommendations: {
|
9
|
+
type: 'simple',
|
10
|
+
id: 'recommendations',
|
11
|
+
children: {
|
12
|
+
export: { type: 'simple', id: 'export' },
|
13
|
+
},
|
14
|
+
},
|
15
|
+
list: {
|
16
|
+
type: 'collection',
|
17
|
+
id: 'list',
|
18
|
+
key: 'listId',
|
19
|
+
children: {
|
20
|
+
items: { type: 'collection', id: 'items', key: 'itemId' },
|
21
|
+
},
|
22
|
+
},
|
23
|
+
label: {
|
24
|
+
type: 'simple',
|
25
|
+
id: 'label',
|
26
|
+
children: {
|
27
|
+
bulk: { type: 'simple', id: 'bulk' },
|
28
|
+
},
|
29
|
+
},
|
30
|
+
customActionType: { type: 'simple', id: 'custom-action-type' },
|
31
|
+
detectionSensitivityConfiguration: {
|
32
|
+
type: 'simple',
|
33
|
+
id: 'detection-sensitivity-configuration',
|
34
|
+
children: {
|
35
|
+
preview: { type: 'simple', id: 'preview' },
|
36
|
+
production: { type: 'simple', id: 'production' },
|
37
|
+
},
|
38
|
+
},
|
39
|
+
rule: {
|
40
|
+
type: 'collection',
|
41
|
+
id: 'rule',
|
42
|
+
key: 'ruleId',
|
43
|
+
children: {
|
44
|
+
preview: { type: 'simple', id: 'preview' },
|
45
|
+
production: { type: 'simple', id: 'production' },
|
46
|
+
},
|
47
|
+
},
|
48
|
+
preview: { type: 'simple', id: 'preview' },
|
49
|
+
securityInsights: { type: 'simple', id: 'security-insights' },
|
50
|
+
automatedWorkflows: { type: 'simple', id: 'automated-workflows' },
|
51
|
+
},
|
52
|
+
};
|
53
|
+
//# sourceMappingURL=drs-resources.js.map
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.EventsResourceDefinition = void 0;
|
4
|
+
exports.EventsResourceDefinition = {
|
5
|
+
type: 'simple',
|
6
|
+
id: 'events',
|
7
|
+
children: {
|
8
|
+
userActivities: {
|
9
|
+
type: 'collection',
|
10
|
+
id: 'user-activities',
|
11
|
+
key: 'userActivityId',
|
12
|
+
},
|
13
|
+
adminActivities: {
|
14
|
+
type: 'collection',
|
15
|
+
id: 'admin-activities',
|
16
|
+
key: 'adminActivityId',
|
17
|
+
},
|
18
|
+
},
|
19
|
+
};
|
20
|
+
//# sourceMappingURL=events-resources.js.map
|
@@ -0,0 +1,32 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.idvResourceDefinition = void 0;
|
4
|
+
exports.idvResourceDefinition = {
|
5
|
+
type: 'simple',
|
6
|
+
id: 'idv',
|
7
|
+
children: {
|
8
|
+
identityVerifications: {
|
9
|
+
type: 'collection',
|
10
|
+
id: 'identity-verifications',
|
11
|
+
key: 'verificationId',
|
12
|
+
children: {
|
13
|
+
status: { type: 'simple', id: 'status' },
|
14
|
+
images: { type: 'collection', id: 'images', key: 'imageId' },
|
15
|
+
result: { type: 'simple', id: 'result' },
|
16
|
+
labels: { type: 'simple', id: 'labels' },
|
17
|
+
},
|
18
|
+
},
|
19
|
+
blocklist: {
|
20
|
+
type: 'simple',
|
21
|
+
id: 'blocklist',
|
22
|
+
children: {
|
23
|
+
faces: { type: 'collection', id: 'faces', key: 'entryId' },
|
24
|
+
},
|
25
|
+
},
|
26
|
+
analytics: {
|
27
|
+
type: 'simple',
|
28
|
+
id: 'analytics',
|
29
|
+
},
|
30
|
+
},
|
31
|
+
};
|
32
|
+
//# sourceMappingURL=idv-resources.js.map
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.oidcResources = exports.serviceProviders = exports.orc = exports.drs = exports.events = exports.idv = exports.users = exports.organization = exports.administration = exports.apps = void 0;
|
4
|
+
const resource_class_builder_1 = require("../../infra/resource-class-builder");
|
5
|
+
const administration_resources_1 = require("./administration-resources");
|
6
|
+
const app_resources_1 = require("./app-resources");
|
7
|
+
const organization_resources_1 = require("./organization-resources");
|
8
|
+
const user_resources_1 = require("./user-resources");
|
9
|
+
const idv_resources_1 = require("./idv-resources");
|
10
|
+
const events_resources_1 = require("./events-resources");
|
11
|
+
const drs_resources_1 = require("./drs-resources");
|
12
|
+
const service_provider_resources_1 = require("./service-provider-resources");
|
13
|
+
const oidc_resource_resources_1 = require("./oidc-resource-resources");
|
14
|
+
const orc_resources_1 = require("./orc-resources");
|
15
|
+
/*
|
16
|
+
Resources definition are split into files for better change isolation. as
|
17
|
+
this project matures, we can consider merging all definitions into a single
|
18
|
+
file for ease of use.
|
19
|
+
*/
|
20
|
+
exports.apps = (0, resource_class_builder_1.buildResourceClass)(app_resources_1.AppResourceDefinition);
|
21
|
+
exports.administration = (0, resource_class_builder_1.buildResourceClass)(administration_resources_1.AdministrationResourceDefinition);
|
22
|
+
exports.organization = (0, resource_class_builder_1.buildResourceClass)(organization_resources_1.organizationsResourceDefinition);
|
23
|
+
exports.users = (0, resource_class_builder_1.buildResourceClass)(user_resources_1.userResourceDefinition);
|
24
|
+
exports.idv = (0, resource_class_builder_1.buildResourceClass)(idv_resources_1.idvResourceDefinition);
|
25
|
+
exports.events = (0, resource_class_builder_1.buildResourceClass)(events_resources_1.EventsResourceDefinition);
|
26
|
+
exports.drs = (0, resource_class_builder_1.buildResourceClass)(drs_resources_1.drsResourceDefinition);
|
27
|
+
exports.orc = (0, resource_class_builder_1.buildResourceClass)(orc_resources_1.orcResourceDefinitions);
|
28
|
+
exports.serviceProviders = (0, resource_class_builder_1.buildResourceClass)(service_provider_resources_1.serviceProviderResourceDefinition);
|
29
|
+
exports.oidcResources = (0, resource_class_builder_1.buildResourceClass)(oidc_resource_resources_1.oidcResourceResourceDefinition);
|
30
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.oidcResourceResourceDefinition = void 0;
|
4
|
+
exports.oidcResourceResourceDefinition = {
|
5
|
+
type: 'collection',
|
6
|
+
id: 'resources',
|
7
|
+
key: 'resourceId',
|
8
|
+
};
|
9
|
+
//# sourceMappingURL=oidc-resource-resources.js.map
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.orcResourceDefinitions = void 0;
|
4
|
+
exports.orcResourceDefinitions = {
|
5
|
+
type: 'simple',
|
6
|
+
id: 'orc',
|
7
|
+
children: {
|
8
|
+
journeys: {
|
9
|
+
type: 'simple',
|
10
|
+
id: 'journeys',
|
11
|
+
},
|
12
|
+
connections: {
|
13
|
+
type: 'simple',
|
14
|
+
id: 'connections',
|
15
|
+
},
|
16
|
+
lists: {
|
17
|
+
type: 'simple',
|
18
|
+
id: 'lists',
|
19
|
+
},
|
20
|
+
identities: {
|
21
|
+
type: 'simple',
|
22
|
+
id: 'identities',
|
23
|
+
},
|
24
|
+
},
|
25
|
+
};
|
26
|
+
//# sourceMappingURL=orc-resources.js.map
|
@@ -0,0 +1,12 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.organizationsResourceDefinition = void 0;
|
4
|
+
exports.organizationsResourceDefinition = {
|
5
|
+
type: 'simple',
|
6
|
+
id: 'organizations',
|
7
|
+
children: {
|
8
|
+
orgs: { type: 'simple', id: 'orgs' },
|
9
|
+
roles: { type: 'simple', id: 'roles' },
|
10
|
+
},
|
11
|
+
};
|
12
|
+
//# sourceMappingURL=organization-resources.js.map
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.serviceProviderResourceDefinition = void 0;
|
4
|
+
exports.serviceProviderResourceDefinition = {
|
5
|
+
type: 'collection',
|
6
|
+
id: 'service-providers',
|
7
|
+
key: 'serviceProviderId',
|
8
|
+
};
|
9
|
+
//# sourceMappingURL=service-provider-resources.js.map
|
@@ -0,0 +1,53 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.wildcardPrimitive = exports.wildcard = exports.resourceClassRegistry = exports.build = exports.Resource = exports.placeholder = exports.Permission = exports.Action = exports.permissions = exports.resources = void 0;
|
27
|
+
const resources = __importStar(require("./definitions/resources"));
|
28
|
+
exports.resources = resources;
|
29
|
+
const permission_selector_builder_1 = require("./infra/permission-selector-builder");
|
30
|
+
/** A reference to all the actions and resources in the RBAC system. You can
|
31
|
+
* use this instead of creating permissions and resource instances
|
32
|
+
* manually.
|
33
|
+
*
|
34
|
+
* example:
|
35
|
+
* ```
|
36
|
+
* permissions.create.Users()
|
37
|
+
* ```*/
|
38
|
+
exports.permissions = (0, permission_selector_builder_1.buildPermissionSelector)(resources);
|
39
|
+
var action_1 = require("./definitions/action");
|
40
|
+
Object.defineProperty(exports, "Action", { enumerable: true, get: function () { return action_1.Action; } });
|
41
|
+
var permission_1 = require("./infra/permission");
|
42
|
+
Object.defineProperty(exports, "Permission", { enumerable: true, get: function () { return permission_1.Permission; } });
|
43
|
+
var placeHolders_1 = require("./infra/placeHolders");
|
44
|
+
Object.defineProperty(exports, "placeholder", { enumerable: true, get: function () { return placeHolders_1.placeholder; } });
|
45
|
+
var resource_1 = require("./infra/resource");
|
46
|
+
Object.defineProperty(exports, "Resource", { enumerable: true, get: function () { return resource_1.Resource; } });
|
47
|
+
exports.build = __importStar(require("./infra/resource-class-builder"));
|
48
|
+
var resource_registry_1 = require("./infra/resource-registry");
|
49
|
+
Object.defineProperty(exports, "resourceClassRegistry", { enumerable: true, get: function () { return resource_registry_1.resourceClassRegistry; } });
|
50
|
+
var wildcard_1 = require("./infra/wildcard");
|
51
|
+
Object.defineProperty(exports, "wildcard", { enumerable: true, get: function () { return wildcard_1.wildcard; } });
|
52
|
+
Object.defineProperty(exports, "wildcardPrimitive", { enumerable: true, get: function () { return wildcard_1.wildcardPrimitive; } });
|
53
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,50 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.buildPermissionSelector = void 0;
|
4
|
+
const action_1 = require("../definitions/action");
|
5
|
+
const permission_1 = require("./permission");
|
6
|
+
const placeHolders_1 = require("./placeHolders");
|
7
|
+
const wildcard_1 = require("./wildcard");
|
8
|
+
function buildPermissionTree(resourceClass, action, parentKeys, keyValues) {
|
9
|
+
const result = {};
|
10
|
+
let childKeys = { ...parentKeys };
|
11
|
+
let entityKeys = { ...parentKeys };
|
12
|
+
if (resourceClass.definition.type === 'collection') {
|
13
|
+
let keyValue = keyValues
|
14
|
+
? keyValues[resourceClass.definition.key]
|
15
|
+
: undefined;
|
16
|
+
if (keyValue === placeHolders_1.placeholder) {
|
17
|
+
keyValue = (0, placeHolders_1.getPlaceHolderString)(resourceClass.definition.key);
|
18
|
+
}
|
19
|
+
childKeys[resourceClass.definition.key] = keyValue || wildcard_1.wildcard;
|
20
|
+
entityKeys[resourceClass.definition.key] = keyValue || undefined;
|
21
|
+
}
|
22
|
+
Object.getOwnPropertyNames(resourceClass).forEach((propName) => {
|
23
|
+
const value = resourceClass[propName];
|
24
|
+
if (typeof value === 'function') {
|
25
|
+
if ('definition' in value) {
|
26
|
+
result[propName] = buildPermissionTree(value, action, childKeys, keyValues);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
});
|
30
|
+
childKeys['childPermission'] = resourceClass.definition.id;
|
31
|
+
const selectable = {
|
32
|
+
permission: new permission_1.Permission(action, new resourceClass(entityKeys)),
|
33
|
+
childPermission: new permission_1.Permission(action, new resourceClass(childKeys)),
|
34
|
+
};
|
35
|
+
Object.assign(result, selectable);
|
36
|
+
return result;
|
37
|
+
}
|
38
|
+
function buildPermissionSelector(resourceTree, keyValues) {
|
39
|
+
return Object.entries(action_1.Action).reduce((selector, [actionName, actionValue]) => {
|
40
|
+
const resources = Object.entries(resourceTree).reduce((acc, [key, value]) => {
|
41
|
+
const tree = buildPermissionTree(value, actionValue, {}, keyValues);
|
42
|
+
acc[key] = tree;
|
43
|
+
return acc;
|
44
|
+
}, {});
|
45
|
+
selector[actionName] = resources;
|
46
|
+
return selector;
|
47
|
+
}, {});
|
48
|
+
}
|
49
|
+
exports.buildPermissionSelector = buildPermissionSelector;
|
50
|
+
//# sourceMappingURL=permission-selector-builder.js.map
|
@@ -0,0 +1,83 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Permission = void 0;
|
4
|
+
const action_1 = require("../definitions/action");
|
5
|
+
const is_valid_enum_value_1 = require("../utils/is-valid-enum-value");
|
6
|
+
const resource_1 = require("./resource");
|
7
|
+
class Permission {
|
8
|
+
constructor(action, resource) {
|
9
|
+
this.action = action;
|
10
|
+
this.resource = resource;
|
11
|
+
}
|
12
|
+
static parse(permissionString) {
|
13
|
+
const segments = permissionString.split(':');
|
14
|
+
if (segments.length !== 2 || segments.some((s) => s.length === 0))
|
15
|
+
return {
|
16
|
+
success: false,
|
17
|
+
error: `Invalid format - should be 'action:resource'`,
|
18
|
+
};
|
19
|
+
const action = segments[0];
|
20
|
+
if (!(0, is_valid_enum_value_1.isValidEnumValue)(action_1.Action, action))
|
21
|
+
return { success: false, error: `Invalid action: '${segments[0]}'` };
|
22
|
+
const parseRes = resource_1.Resource.parse(segments[1]);
|
23
|
+
if (!parseRes.success)
|
24
|
+
return {
|
25
|
+
success: false,
|
26
|
+
error: `Cannot parse resource: ${parseRes.error}`,
|
27
|
+
};
|
28
|
+
const { resource } = parseRes;
|
29
|
+
return {
|
30
|
+
success: true,
|
31
|
+
permission: new Permission(action, resource),
|
32
|
+
};
|
33
|
+
}
|
34
|
+
/** Checks if this permission is granted by any of the provided permissions.
|
35
|
+
*
|
36
|
+
* When permission validation fails, it's recommended to log the required and provided permissions for easy debugging.
|
37
|
+
*
|
38
|
+
* note: by default, invalid permissions are ignored. you can adjust this behavior using the options parameter, or
|
39
|
+
* parse and check the permissions yourself using `Permission.parse`.
|
40
|
+
*/
|
41
|
+
isAllowedBy(providedPermissions, options) {
|
42
|
+
for (const permission of providedPermissions) {
|
43
|
+
if (typeof permission === 'string') {
|
44
|
+
const parseRes = Permission.parse(permission);
|
45
|
+
if (!parseRes.success) {
|
46
|
+
if (options.onParsingError === 'throw') {
|
47
|
+
throw new Error(parseRes.error);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
else if (parseRes.permission.allows(this)) {
|
51
|
+
return true;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
else if (permission.allows(this)) {
|
55
|
+
return true;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return false;
|
59
|
+
}
|
60
|
+
/** Checks if this permission allows the operation described by the other permission.
|
61
|
+
*
|
62
|
+
* example:
|
63
|
+
* ```
|
64
|
+
* if (tokenPermission.allows(requiredPermission)) {
|
65
|
+
* // perform the operation
|
66
|
+
* } else {
|
67
|
+
* // return error
|
68
|
+
* }
|
69
|
+
* ```
|
70
|
+
*/
|
71
|
+
allows(other) {
|
72
|
+
if (this.action !== action_1.Action.all && this.action !== other.action)
|
73
|
+
return false;
|
74
|
+
if (!this.resource.owns(other.resource))
|
75
|
+
return false;
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
toString() {
|
79
|
+
return `${this.action}:${this.resource.toString()}`;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
exports.Permission = Permission;
|
83
|
+
//# sourceMappingURL=permission.js.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getPlaceHolderString = exports.placeholder = void 0;
|
4
|
+
exports.placeholder = 'PLACEHOLDER';
|
5
|
+
const getPlaceHolderString = (key) => `[${key}]`;
|
6
|
+
exports.getPlaceHolderString = getPlaceHolderString;
|
7
|
+
//# sourceMappingURL=placeHolders.js.map
|
@@ -0,0 +1,277 @@
|
|
1
|
+
"use strict";
|
2
|
+
/*
|
3
|
+
|
4
|
+
The purpose of this file is to provide a way to build resource classes, from a
|
5
|
+
data structure that's as simple as possible.
|
6
|
+
|
7
|
+
## General idea
|
8
|
+
|
9
|
+
recommended reading:
|
10
|
+
https://cloud.google.com/apis/design/resource_names
|
11
|
+
|
12
|
+
Resource classes are typescript classes which represent a specific type of resources,
|
13
|
+
and are used to create instances of those resources for things like permission checks
|
14
|
+
or data access. At the lowest level a resource is just a string, but we want to provide
|
15
|
+
a move convenient mechanism to work with them.
|
16
|
+
|
17
|
+
Resource classes have several requirements:
|
18
|
+
|
19
|
+
1. provide a string that represents the resource
|
20
|
+
2. ensure all placeholder values are filled in when creating an instance
|
21
|
+
e.g if the resource is `apps/$appId/users/$userId`, then when creating an instance,
|
22
|
+
both `appId` and `userId` must be provided.
|
23
|
+
3. provide a way to reference a resource class (not instance) via a string
|
24
|
+
i.e if a client tells a server "I want to access the `users` resource", the server
|
25
|
+
should be able to understand which resource class that is.
|
26
|
+
4. provide a convenient way to create child resources from a parent resource
|
27
|
+
|
28
|
+
|
29
|
+
The end result is a bunch of classes that look kinda like this:
|
30
|
+
```
|
31
|
+
class Apps {
|
32
|
+
constructor(public appId: string) { }
|
33
|
+
toString() { return `apps/${this.appId}` }
|
34
|
+
|
35
|
+
users(userId: string) { return new AppUsers(this.appId, userId); }
|
36
|
+
}
|
37
|
+
|
38
|
+
class AppUsers {
|
39
|
+
constructor(public appId: string, public userId: string) { }
|
40
|
+
toString() { return `apps/${this.appId}/users/${this.userId}` }
|
41
|
+
}
|
42
|
+
```
|
43
|
+
|
44
|
+
the ONLY thing that matters is that end result. the implementation of the
|
45
|
+
builder is free to change and evolve - we can even generate the classes
|
46
|
+
at build time using a code generator, or even remove automatic generation
|
47
|
+
entirely and just write the classes manually.
|
48
|
+
|
49
|
+
## Implementation
|
50
|
+
|
51
|
+
The implementation is based on a recursive function that builds the classes
|
52
|
+
from a data structure that represents the resource.
|
53
|
+
|
54
|
+
Due to all the type manipulation, the implementation is a bit complex -
|
55
|
+
we have the types which facilitate the type manipulation, and the actual code
|
56
|
+
that builds the classes. That's 2 parallel flows of data. We try to use them
|
57
|
+
together as much as possible to get type safety, but in some cases it's
|
58
|
+
technically impossible to get type info, so we resort to `any` and make sure
|
59
|
+
that area covered by tests.
|
60
|
+
|
61
|
+
The entry point for the type definitions is the `ResourceClassFromDef` type,
|
62
|
+
which takes in a `ResourceDefNode` type and builds a class from it, with the
|
63
|
+
the collections keys and child resource if any. see the jsdoc on the type
|
64
|
+
itself for details.
|
65
|
+
|
66
|
+
The entry point for the actual code is the `buildResourceClass` function,
|
67
|
+
which takes in a `ResourceDefNode` instance and returns a class built from it,
|
68
|
+
also with the correct collection keys and child resources. here too, see the
|
69
|
+
jsdoc for details.
|
70
|
+
|
71
|
+
## Some future ideas
|
72
|
+
|
73
|
+
### non-class references
|
74
|
+
|
75
|
+
there's no real reason that `Apps.Users` (for example) has to be the users
|
76
|
+
class - all we need from it is the template, since we can build an instance
|
77
|
+
using `new Apps().users()`. Populating those props with something that holds
|
78
|
+
a template string and child objects, instead of a class, will make them easier
|
79
|
+
to explore since they won't have the other methods that functions have.
|
80
|
+
|
81
|
+
### inherently type-checked collection keys
|
82
|
+
|
83
|
+
when building the type of an anon object (`{a:"str"}`), typescript sets the
|
84
|
+
type of primitive properties to their full type even when a fixed value is
|
85
|
+
provided. so the example's type would be `{a: string}` and not `{a:"str"}`.
|
86
|
+
for this reason, users of the builder have to add `as const` to their
|
87
|
+
definitions - without it, collection keys would be just any string and not
|
88
|
+
specifically the provided key.
|
89
|
+
we could instead change the api to get collection keys as object keys, not as
|
90
|
+
strings: `{key: {userId: string}}` instead of `{key: "userId"}`. with this,
|
91
|
+
there's no need to `as const` since string fields are not used for type
|
92
|
+
inference.
|
93
|
+
|
94
|
+
|
95
|
+
### id-based resource types
|
96
|
+
|
97
|
+
instead of simple and collection resource definitions, we can use ids like
|
98
|
+
`apps` and `apps/$appId` and automatically determine if it's a collection.
|
99
|
+
see https://www.typescriptlang.org/play/?#code/C4TwDgpgBAyglgWzAGwgSQCZQLxQM7ABOcAdgOYBQokUAwgPbKoDGwc9JmAPAHICGCaBAAewCCQx58RUmQA0UANIQQ-QVBFiJUgsXIA+HFAAGAEgDeaiAF8A9KYvLVAm8YruAZgFcSrdiSgyCGAuABUNUXFJOkYWNg5uPhIQBSSQQwAfWEQUdAx9AAoKKBLpQgAuKFCKAEpK8M0oqQYmCD8EjC5SDwhCKCsFbt6lFStDYtKAfihzaghKgCJmWLb4kgWFEhdKgagAa1HtkedBaygJksrzKDnFvBzUDagtwXqzinMLqEJgr0IA8xnPhSNIUazuCjLEgEfAPaC4ILAAoLLx4Xp4BY1Ci2WylPEAPUmkI4MOWrXaAQRwWRqPR9lphEwmOxuIJRIhQA
|
100
|
+
this will make the definitions a lot simpler, but is also a bit less discoverable -
|
101
|
+
the type system won't tell you that you can create a collection that way.
|
102
|
+
can consider this when there are more resources to use as reference.
|
103
|
+
|
104
|
+
### fluent builder
|
105
|
+
|
106
|
+
instead of passing an object to the constructor, we can use a fluent builder.
|
107
|
+
this will allow greater flexibility in the future, and will avoid the need for `as const`.
|
108
|
+
downside is that it can get pretty verbose, and will require a lot of boilerplate.
|
109
|
+
|
110
|
+
|
111
|
+
*/
|
112
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
113
|
+
exports.InvalidKeyForCollection = exports.MissingKeyForCollection = exports.buildResourceClass = void 0;
|
114
|
+
const resource_1 = require("./resource");
|
115
|
+
const resource_registry_1 = require("./resource-registry");
|
116
|
+
const wildcard_1 = require("./wildcard");
|
117
|
+
function getTemplatePath(res) {
|
118
|
+
return res.type === 'simple' ? [res.id] : [res.id, `$${res.key}`];
|
119
|
+
}
|
120
|
+
function buildResourceClassCommon(source, parentDefinitions) {
|
121
|
+
const parentPath = parentDefinitions.map(getTemplatePath).flat();
|
122
|
+
const fullPath = [...parentPath, ...getTemplatePath(source)];
|
123
|
+
return {
|
124
|
+
template: fullPath,
|
125
|
+
templateStr: fullPath.join(resource_1.Resource.separator),
|
126
|
+
definition: source,
|
127
|
+
};
|
128
|
+
}
|
129
|
+
function buildResourceConstructor(source, parents) {
|
130
|
+
switch (source.type) {
|
131
|
+
case 'simple':
|
132
|
+
return class SimpleResource extends resource_1.Resource {
|
133
|
+
constructor(input) {
|
134
|
+
super(buildResourcePath([...parents, source], input));
|
135
|
+
}
|
136
|
+
};
|
137
|
+
case 'collection':
|
138
|
+
return class CollectionResource extends resource_1.Resource {
|
139
|
+
constructor(input) {
|
140
|
+
super(buildResourcePath([...parents, source], input));
|
141
|
+
}
|
142
|
+
};
|
143
|
+
}
|
144
|
+
}
|
145
|
+
/** Builds the properties that provide the child resource.
|
146
|
+
*
|
147
|
+
* e.g with `new Apps.Users({appId:"123", userId:"456"})` - this function
|
148
|
+
* had built the `Users` static property on the `Apps` class.
|
149
|
+
*
|
150
|
+
* The returned object should be merged with the parent class.
|
151
|
+
*/
|
152
|
+
function buildChildResourceStaticProperties(childClasses) {
|
153
|
+
const propMap = {};
|
154
|
+
for (const [key, childClass] of Object.entries(childClasses)) {
|
155
|
+
propMap[key] = { get: () => childClass };
|
156
|
+
}
|
157
|
+
return propMap;
|
158
|
+
}
|
159
|
+
/** Builds the methods that create child resource from a parent resource.
|
160
|
+
*
|
161
|
+
* e.g with `new Apps("someAppId").users("someUserId")` - this function
|
162
|
+
* had built the `users` method on the `Apps` class.
|
163
|
+
*
|
164
|
+
* The returned object should be merged with the parent class prototype.
|
165
|
+
*/
|
166
|
+
function buildChildResourceInstanceMethods(childClasses, definitions) {
|
167
|
+
const propMap = {};
|
168
|
+
for (const [key, childClass] of Object.entries(childClasses)) {
|
169
|
+
const childDefinition = childClass.definition;
|
170
|
+
propMap[key] = {
|
171
|
+
get() {
|
172
|
+
let input = gatherInput(this, definitions);
|
173
|
+
return childDefinition.type == 'simple'
|
174
|
+
? (childResource) => new childClass({ ...input, childResource })
|
175
|
+
: (id, childResource) => new childClass({
|
176
|
+
...input,
|
177
|
+
[childDefinition.key]: id,
|
178
|
+
childResource,
|
179
|
+
});
|
180
|
+
},
|
181
|
+
};
|
182
|
+
}
|
183
|
+
return propMap;
|
184
|
+
}
|
185
|
+
function build(source, parentDefinitions) {
|
186
|
+
/*
|
187
|
+
we're gonna do dynamic stuff here, so to maintain type safety as much as possible,
|
188
|
+
we'll create the components of a resource class separately, and then combine them.
|
189
|
+
*/
|
190
|
+
const resourceClass = buildResourceConstructor(source, parentDefinitions);
|
191
|
+
Object.assign(resourceClass, buildResourceClassCommon(source, parentDefinitions));
|
192
|
+
if (source.children) {
|
193
|
+
const childParents = [...parentDefinitions, source];
|
194
|
+
const childClassesRecord = Object.entries(source.children).reduce((acc, [key, childDefinition]) => {
|
195
|
+
acc[key] = build(childDefinition, childParents);
|
196
|
+
return acc;
|
197
|
+
}, {});
|
198
|
+
Object.defineProperties(resourceClass, buildChildResourceStaticProperties(childClassesRecord));
|
199
|
+
Object.defineProperties(resourceClass.prototype, buildChildResourceInstanceMethods(childClassesRecord, childParents));
|
200
|
+
}
|
201
|
+
resource_registry_1.resourceClassRegistry.register(resourceClass.templateStr);
|
202
|
+
return resourceClass;
|
203
|
+
}
|
204
|
+
/** returns an object with the inputs used to build it and each parent.
|
205
|
+
* simple (non-collection) resources are not included in the output since they don't have inputs.
|
206
|
+
*
|
207
|
+
* example -
|
208
|
+
* for resource `apps/123/users/456` (assuming template `apps/$appId/users/$userId`),
|
209
|
+
* this will return `{appId: "123", userId: "456"}`
|
210
|
+
*/
|
211
|
+
function gatherInput(source, definitions) {
|
212
|
+
const remainingPath = [...source.path];
|
213
|
+
return definitions.reduce((acc, def) => {
|
214
|
+
remainingPath.shift();
|
215
|
+
if (def.type === 'collection') {
|
216
|
+
const key = remainingPath.shift();
|
217
|
+
if (key === wildcard_1.wildcardPrimitive) {
|
218
|
+
acc[def.key] = wildcard_1.wildcard;
|
219
|
+
}
|
220
|
+
else {
|
221
|
+
acc[def.key] = key;
|
222
|
+
}
|
223
|
+
}
|
224
|
+
return acc;
|
225
|
+
}, {});
|
226
|
+
}
|
227
|
+
function buildResourcePath(resources, input = {}) {
|
228
|
+
const lastResource = resources[resources.length - 1];
|
229
|
+
return resources.reduce((acc, res) => {
|
230
|
+
if (res.type === 'simple') {
|
231
|
+
if (input.childPermission === res.id ||
|
232
|
+
(res.id === lastResource.id && input.childResource)) {
|
233
|
+
return [...acc, res.id, wildcard_1.wildcardPrimitive];
|
234
|
+
}
|
235
|
+
return [...acc, res.id];
|
236
|
+
}
|
237
|
+
else {
|
238
|
+
if (!(res.key in input))
|
239
|
+
return [...acc, res.id];
|
240
|
+
const key = input[res.key];
|
241
|
+
if (key == '' || key == null)
|
242
|
+
return [...acc, res.id];
|
243
|
+
if (key === wildcard_1.wildcard)
|
244
|
+
return [...acc, res.id, wildcard_1.wildcardPrimitive];
|
245
|
+
const isValid = (0, resource_1.validateResourceSegment)(key);
|
246
|
+
if (!isValid)
|
247
|
+
throw new InvalidKeyForCollection(res.key, key);
|
248
|
+
if ((res.id === lastResource.id && input.childResource) ||
|
249
|
+
input.childPermission === res.id) {
|
250
|
+
return [...acc, res.id, key, wildcard_1.wildcardPrimitive];
|
251
|
+
}
|
252
|
+
return [...acc, res.id, key];
|
253
|
+
}
|
254
|
+
}, []);
|
255
|
+
}
|
256
|
+
/** Build a resource class from a definition.
|
257
|
+
*
|
258
|
+
* - remember to add `as const` to the input object, to get accurate auto-complete.
|
259
|
+
* - for resource names, use valid javascript identifiers - i.e adminUsers and not 'admin-users'. those identifies are mapped to properties, so non-standard names would make them harder to access.
|
260
|
+
*/
|
261
|
+
function buildResourceClass(resourceDef) {
|
262
|
+
return build(resourceDef, []);
|
263
|
+
}
|
264
|
+
exports.buildResourceClass = buildResourceClass;
|
265
|
+
class MissingKeyForCollection extends Error {
|
266
|
+
constructor(keyName) {
|
267
|
+
super(`No key for collection; keyName: '${String(keyName)}'`);
|
268
|
+
}
|
269
|
+
}
|
270
|
+
exports.MissingKeyForCollection = MissingKeyForCollection;
|
271
|
+
class InvalidKeyForCollection extends Error {
|
272
|
+
constructor(keyName, keyValue) {
|
273
|
+
super(`Invalid key for collection; keyName: '${String(keyName)}', value: '${keyValue}'`);
|
274
|
+
}
|
275
|
+
}
|
276
|
+
exports.InvalidKeyForCollection = InvalidKeyForCollection;
|
277
|
+
//# sourceMappingURL=resource-class-builder.js.map
|
@@ -0,0 +1,22 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.resourceClassRegistry = void 0;
|
4
|
+
class ResourceClassRegistry {
|
5
|
+
constructor() {
|
6
|
+
this.templates = [];
|
7
|
+
}
|
8
|
+
register(name) {
|
9
|
+
this.templates.push(name);
|
10
|
+
}
|
11
|
+
getTemplates() {
|
12
|
+
return [...this.templates];
|
13
|
+
}
|
14
|
+
}
|
15
|
+
/* not very DI-like but for this specific use case (library, registry of fixed
|
16
|
+
values) it's fine.
|
17
|
+
|
18
|
+
if we do want to play nice with DI, we'll need to have the registry provided
|
19
|
+
to the resource creation externally, and have the DI provide it.
|
20
|
+
*/
|
21
|
+
exports.resourceClassRegistry = new ResourceClassRegistry();
|
22
|
+
//# sourceMappingURL=resource-registry.js.map
|
@@ -0,0 +1,93 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Resource = exports.validateResourceSegment = exports.segmentMatcher = void 0;
|
4
|
+
const wildcard_1 = require("./wildcard");
|
5
|
+
exports.segmentMatcher = /^[a-zA-Z0-9_-]+$/;
|
6
|
+
function validateResourceSegment(segment, options) {
|
7
|
+
if ((options === null || options === void 0 ? void 0 : options.allowWildcard) && segment === wildcard_1.wildcardPrimitive)
|
8
|
+
return true;
|
9
|
+
if (segment === undefined)
|
10
|
+
return true;
|
11
|
+
if (segment.startsWith('[') && segment.endsWith(']')) {
|
12
|
+
segment = segment.slice(1, -1); // remove template brackets
|
13
|
+
}
|
14
|
+
return exports.segmentMatcher.test(segment);
|
15
|
+
}
|
16
|
+
exports.validateResourceSegment = validateResourceSegment;
|
17
|
+
class Resource {
|
18
|
+
constructor(path) {
|
19
|
+
this.path = path;
|
20
|
+
}
|
21
|
+
static parse(str) {
|
22
|
+
const path = str.split(Resource.separator);
|
23
|
+
if (path.length === 0) {
|
24
|
+
return { success: false, error: 'Resource path is empty' };
|
25
|
+
}
|
26
|
+
const emptySegments = path.filter((segment) => segment === '');
|
27
|
+
if (emptySegments.length > 0) {
|
28
|
+
return { success: false, error: `Resource path contains empty segments` };
|
29
|
+
}
|
30
|
+
const invalidSegments = path.filter((segment) => !validateResourceSegment(segment, { allowWildcard: true }));
|
31
|
+
if (invalidSegments.length > 0) {
|
32
|
+
return {
|
33
|
+
success: false,
|
34
|
+
error: 'Resource path contains invalid segments',
|
35
|
+
invalidSegments,
|
36
|
+
validationRegex: exports.segmentMatcher,
|
37
|
+
};
|
38
|
+
}
|
39
|
+
return {
|
40
|
+
success: true,
|
41
|
+
resource: new Resource(path),
|
42
|
+
};
|
43
|
+
}
|
44
|
+
/** checks if this resource owns `other`. i.e if `other` is a subset of this resource.
|
45
|
+
*
|
46
|
+
* examples:
|
47
|
+
* - `apps/123/users` does not own `apps/123/users/456`
|
48
|
+
* - `apps/123/users/*` owns `apps/123/users/456`
|
49
|
+
* - `apps/123/users` does not own `apps/123`
|
50
|
+
* - `apps/123/users` owns `apps/123/users` (itself)
|
51
|
+
*
|
52
|
+
* it's like `israel/tel-aviv/*` owns `israel/tel-aviv/alenby`, but not the other way around.
|
53
|
+
* and `israel/tel-aviv` does not own `israel/tel-aviv/alenby`, it owns only itself.
|
54
|
+
*/
|
55
|
+
owns(other) {
|
56
|
+
const maxPathLength = Math.max(this.path.length, other.path.length);
|
57
|
+
// safeguard against unintentional global permission. should be explicit `*`
|
58
|
+
if (other.path.length === 0 || other.path[0] === '')
|
59
|
+
return false;
|
60
|
+
for (let i = 0; i < maxPathLength; i++) {
|
61
|
+
const thisSegment = this.path[i];
|
62
|
+
const otherSegment = other.path[i];
|
63
|
+
// e.g this is `apps/123` does not own `apps/123/users`.
|
64
|
+
// but 'apps/123/*' owns 'apps/123/users/567' , 'apps/*' owns 'apps/123/users/567' or 'apps/*/users' etc.
|
65
|
+
if (!thisSegment) {
|
66
|
+
if (this.path[i - 1] === wildcard_1.wildcardPrimitive) {
|
67
|
+
return true;
|
68
|
+
}
|
69
|
+
return false;
|
70
|
+
}
|
71
|
+
// if `other` ended, but `this` didn't, then `this` doesn't contain `other`.
|
72
|
+
if (!otherSegment)
|
73
|
+
return false;
|
74
|
+
// if this segment is wildcard, no need for additional checks - it's a match.
|
75
|
+
// we only check further if it's not.
|
76
|
+
if (thisSegment !== wildcard_1.wildcardPrimitive) {
|
77
|
+
// if this segment isn't wildcard, but other is, then this can't possibly contain other.
|
78
|
+
if (otherSegment === wildcard_1.wildcardPrimitive)
|
79
|
+
return false;
|
80
|
+
// if the segments don't match, we can stop checking.
|
81
|
+
if (thisSegment !== otherSegment)
|
82
|
+
return false;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
return true;
|
86
|
+
}
|
87
|
+
toString() {
|
88
|
+
return this.path.join(Resource.separator);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
exports.Resource = Resource;
|
92
|
+
Resource.separator = '/';
|
93
|
+
//# sourceMappingURL=resource.js.map
|
@@ -0,0 +1,8 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.isValidEnumValue = void 0;
|
4
|
+
function isValidEnumValue(enumType, value) {
|
5
|
+
return Object.values(enumType).includes(value);
|
6
|
+
}
|
7
|
+
exports.isValidEnumValue = isValidEnumValue;
|
8
|
+
//# sourceMappingURL=is-valid-enum-value.js.map
|
package/package.json
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"name": "@transmit-security/rbac",
|
3
|
+
"private": false,
|
4
|
+
"description": "RBAC impl of Transmt sec",
|
5
|
+
"version": "1.0.0-beta",
|
6
|
+
"main": "dist/ui.es.js",
|
7
|
+
"module": "dist/ui.es.js",
|
8
|
+
"author": "htrs-sec",
|
9
|
+
"repository": "https://www.github.com/htrs-sec/@transmit-security/rbac",
|
10
|
+
"license": "MIT",
|
11
|
+
"files": [
|
12
|
+
"dist",
|
13
|
+
"scripts"
|
14
|
+
],
|
15
|
+
"publishConfig": {
|
16
|
+
"access": "public"
|
17
|
+
},
|
18
|
+
"scripts": {
|
19
|
+
"build": "tsc"
|
20
|
+
},
|
21
|
+
"devDependencies": {
|
22
|
+
"husky": "9.1.4",
|
23
|
+
"lint-staged": "13.1.4",
|
24
|
+
"typescript": "^5.6.2"
|
25
|
+
},
|
26
|
+
"husky": {
|
27
|
+
"hooks": {
|
28
|
+
"commit-msg": "commitlint .commitlintrc.js -E HUSKY_GIT_PARAMS",
|
29
|
+
"pre-commit": "lint-staged"
|
30
|
+
}
|
31
|
+
},
|
32
|
+
"lint-staged": {
|
33
|
+
"*": [
|
34
|
+
"eden lint format",
|
35
|
+
"git add"
|
36
|
+
]
|
37
|
+
}
|
38
|
+
}
|