@manablox/auth 0.2.0 → 0.4.0
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/dist/index.d.ts +344 -0
- package/dist/index.js +585 -0
- package/package.json +14 -7
- package/src/api-key.ts +0 -164
- package/src/index.ts +0 -164
- package/src/password.ts +0 -17
- package/src/rbac.ts +0 -134
- package/src/user.service.ts +0 -192
- package/test/api-key.test.ts +0 -18
- package/test/rbac.test.ts +0 -128
- package/tsconfig.json +0 -1
- package/vitest.config.ts +0 -2
package/test/rbac.test.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
actorRoles,
|
|
4
|
-
allowedTypeIds,
|
|
5
|
-
assertCan,
|
|
6
|
-
can,
|
|
7
|
-
type Principal,
|
|
8
|
-
permissionsFor,
|
|
9
|
-
} from '../src/rbac.js';
|
|
10
|
-
|
|
11
|
-
const SPACE = 'space-1';
|
|
12
|
-
|
|
13
|
-
const principal = (over: Partial<Principal> = {}): Principal => ({
|
|
14
|
-
userId: 'u1',
|
|
15
|
-
email: 'u@example.com',
|
|
16
|
-
role: 'editor',
|
|
17
|
-
spaces: { [SPACE]: 'editor' },
|
|
18
|
-
...over,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe('rbac', () => {
|
|
22
|
-
it('denies everything to an anonymous caller', () => {
|
|
23
|
-
expect(can(null, SPACE, 'content:read')).toBe(false);
|
|
24
|
-
expect(() => assertCan(null, SPACE, 'content:read')).toThrow(/unauthorized/);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('lets an author write but not publish — the reason the role exists', () => {
|
|
28
|
-
const author = principal({ spaces: { [SPACE]: 'author' } });
|
|
29
|
-
expect(can(author, SPACE, 'content:write')).toBe(true);
|
|
30
|
-
expect(can(author, SPACE, 'content:publish')).toBe(false);
|
|
31
|
-
expect(() => assertCan(author, SPACE, 'content:publish')).toThrow(/forbidden/);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('confines a viewer to reads', () => {
|
|
35
|
-
const viewer = principal({ spaces: { [SPACE]: 'viewer' } });
|
|
36
|
-
expect(can(viewer, SPACE, 'content:read')).toBe(true);
|
|
37
|
-
expect(can(viewer, SPACE, 'content:write')).toBe(false);
|
|
38
|
-
expect(can(viewer, SPACE, 'asset:write')).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('grants nothing in a space the user is not a member of', () => {
|
|
42
|
-
expect(can(principal(), 'other-space', 'content:read')).toBe(false);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('short-circuits every check for a superadmin', () => {
|
|
46
|
-
const root = principal({ role: 'superadmin', spaces: {} });
|
|
47
|
-
expect(can(root, 'any-space', 'space:delete')).toBe(true);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('reserves space deletion for the owner', () => {
|
|
51
|
-
expect(can(principal({ spaces: { [SPACE]: 'admin' } }), SPACE, 'space:delete')).toBe(false);
|
|
52
|
-
expect(can(principal({ spaces: { [SPACE]: 'owner' } }), SPACE, 'space:delete')).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('exposes the roles a field-level permission check needs', () => {
|
|
56
|
-
expect(actorRoles(principal({ role: 'editor' }), SPACE)).toEqual(['editor', 'editor']);
|
|
57
|
-
expect(actorRoles(null, SPACE)).toEqual([]);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('never grants a write permission through a read-only role', () => {
|
|
61
|
-
for (const permission of permissionsFor('viewer')) {
|
|
62
|
-
expect(permission.endsWith(':read')).toBe(true);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('a custom role', () => {
|
|
67
|
-
const TYPE = 'type-1';
|
|
68
|
-
const blogger = principal({
|
|
69
|
-
spaces: { [SPACE]: 'blogger' },
|
|
70
|
-
permissions: { [SPACE]: ['space:read', 'content:read', `content:write:${TYPE}`] },
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('answers from its own grants rather than the built-in table', () => {
|
|
74
|
-
expect(can(blogger, SPACE, 'content:read')).toBe(true);
|
|
75
|
-
expect(can(blogger, SPACE, 'asset:read')).toBe(false);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('holds a content action for every type, or for the types named', () => {
|
|
79
|
-
expect(can(blogger, SPACE, 'content:read', 'type-2')).toBe(true);
|
|
80
|
-
expect(can(blogger, SPACE, 'content:write', TYPE)).toBe(true);
|
|
81
|
-
expect(can(blogger, SPACE, 'content:write', 'type-2')).toBe(false);
|
|
82
|
-
// Asked without a type: does the role write anything at all?
|
|
83
|
-
expect(can(blogger, SPACE, 'content:write')).toBe(true);
|
|
84
|
-
expect(can(blogger, SPACE, 'content:publish')).toBe(false);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('tells a listing which types to narrow to', () => {
|
|
88
|
-
expect(allowedTypeIds(blogger, SPACE, 'content:read')).toBeNull();
|
|
89
|
-
expect(allowedTypeIds(blogger, SPACE, 'content:write')).toEqual([TYPE]);
|
|
90
|
-
expect(allowedTypeIds(blogger, SPACE, 'content:publish')).toEqual([]);
|
|
91
|
-
expect(allowedTypeIds(principal({ role: 'superadmin' }), SPACE, 'content:write')).toBeNull();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('is nothing in a space where the name is unknown and no grants came along', () => {
|
|
95
|
-
const ghost = principal({ spaces: { [SPACE]: 'ghost' } });
|
|
96
|
-
expect(can(ghost, SPACE, 'content:read')).toBe(false);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe('an API key confined to grants', () => {
|
|
101
|
-
const TYPE = 'type-1';
|
|
102
|
-
const key = principal({
|
|
103
|
-
spaces: { [SPACE]: 'editor' },
|
|
104
|
-
viaApiKey: true,
|
|
105
|
-
allowedGrants: ['content:read', `content:write:${TYPE}`, 'space:delete'],
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('never widens the owner: a grant the role lacks stays refused', () => {
|
|
109
|
-
expect(can(key, SPACE, 'space:delete')).toBe(false);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('narrows the owner to the grants named', () => {
|
|
113
|
-
expect(can(key, SPACE, 'content:read')).toBe(true);
|
|
114
|
-
expect(can(key, SPACE, 'content:write', TYPE)).toBe(true);
|
|
115
|
-
expect(can(key, SPACE, 'content:write', 'type-2')).toBe(false);
|
|
116
|
-
expect(can(key, SPACE, 'asset:read')).toBe(false);
|
|
117
|
-
expect(allowedTypeIds(key, SPACE, 'content:write')).toEqual([TYPE]);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('binds a superadmin too', () => {
|
|
121
|
-
const root = principal({ role: 'superadmin', spaces: {}, allowedGrants: ['content:read'] });
|
|
122
|
-
expect(can(root, SPACE, 'content:read')).toBe(true);
|
|
123
|
-
expect(can(root, SPACE, 'space:delete')).toBe(false);
|
|
124
|
-
expect(allowedTypeIds(root, SPACE, 'content:read')).toBeNull();
|
|
125
|
-
expect(allowedTypeIds(root, SPACE, 'content:write')).toEqual([]);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{ "extends": "@manablox/config-typescript/library.json", "include": ["src", "test"] }
|
package/vitest.config.ts
DELETED