@api-client/core 0.18.50 → 0.18.52
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/build/src/models/store/Permission.d.ts +12 -1
- package/build/src/models/store/Permission.d.ts.map +1 -1
- package/build/src/models/store/Permission.js +52 -2
- package/build/src/models/store/Permission.js.map +1 -1
- package/build/src/runtime/http-engine/ntlm/MD4.js +3 -3
- package/build/src/runtime/http-engine/ntlm/MD4.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +10 -10
- package/package.json +2 -2
- package/src/models/store/Permission.ts +57 -2
- package/src/runtime/http-engine/ntlm/MD4.ts +3 -3
- package/tests/unit/models/store/Permission.spec.ts +278 -0
|
@@ -42068,10 +42068,10 @@
|
|
|
42068
42068
|
"@id": "#194"
|
|
42069
42069
|
},
|
|
42070
42070
|
{
|
|
42071
|
-
"@id": "#
|
|
42071
|
+
"@id": "#200"
|
|
42072
42072
|
},
|
|
42073
42073
|
{
|
|
42074
|
-
"@id": "#
|
|
42074
|
+
"@id": "#197"
|
|
42075
42075
|
},
|
|
42076
42076
|
{
|
|
42077
42077
|
"@id": "#203"
|
|
@@ -42810,10 +42810,10 @@
|
|
|
42810
42810
|
"@id": "#219"
|
|
42811
42811
|
},
|
|
42812
42812
|
{
|
|
42813
|
-
"@id": "#
|
|
42813
|
+
"@id": "#219"
|
|
42814
42814
|
},
|
|
42815
42815
|
{
|
|
42816
|
-
"@id": "#
|
|
42816
|
+
"@id": "#210"
|
|
42817
42817
|
},
|
|
42818
42818
|
{
|
|
42819
42819
|
"@id": "#213"
|
|
@@ -43478,7 +43478,7 @@
|
|
|
43478
43478
|
"doc:ExternalDomainElement",
|
|
43479
43479
|
"doc:DomainElement"
|
|
43480
43480
|
],
|
|
43481
|
-
"doc:raw": "
|
|
43481
|
+
"doc:raw": "class: '3'\ndescription: '150 - 300'\nnumberOfFte: 5500\nnumberOfEmployees: 5232\n",
|
|
43482
43482
|
"core:mediaType": "application/yaml",
|
|
43483
43483
|
"sourcemaps:sources": [
|
|
43484
43484
|
{
|
|
@@ -43499,7 +43499,7 @@
|
|
|
43499
43499
|
"doc:ExternalDomainElement",
|
|
43500
43500
|
"doc:DomainElement"
|
|
43501
43501
|
],
|
|
43502
|
-
"doc:raw": "
|
|
43502
|
+
"doc:raw": "code: '5'\ndescription: 'Limited company'\n",
|
|
43503
43503
|
"core:mediaType": "application/yaml",
|
|
43504
43504
|
"sourcemaps:sources": [
|
|
43505
43505
|
{
|
|
@@ -44232,7 +44232,7 @@
|
|
|
44232
44232
|
"doc:ExternalDomainElement",
|
|
44233
44233
|
"doc:DomainElement"
|
|
44234
44234
|
],
|
|
44235
|
-
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '
|
|
44235
|
+
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
|
|
44236
44236
|
"core:mediaType": "application/yaml",
|
|
44237
44237
|
"sourcemaps:sources": [
|
|
44238
44238
|
{
|
|
@@ -44295,7 +44295,7 @@
|
|
|
44295
44295
|
"doc:ExternalDomainElement",
|
|
44296
44296
|
"doc:DomainElement"
|
|
44297
44297
|
],
|
|
44298
|
-
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '
|
|
44298
|
+
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
|
|
44299
44299
|
"core:mediaType": "application/yaml",
|
|
44300
44300
|
"sourcemaps:sources": [
|
|
44301
44301
|
{
|
|
@@ -44766,12 +44766,12 @@
|
|
|
44766
44766
|
{
|
|
44767
44767
|
"@id": "#199/source-map/lexical/element_0",
|
|
44768
44768
|
"sourcemaps:element": "amf://id#199",
|
|
44769
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44769
|
+
"sourcemaps:value": "[(1,0)-(5,0)]"
|
|
44770
44770
|
},
|
|
44771
44771
|
{
|
|
44772
44772
|
"@id": "#202/source-map/lexical/element_0",
|
|
44773
44773
|
"sourcemaps:element": "amf://id#202",
|
|
44774
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44774
|
+
"sourcemaps:value": "[(1,0)-(3,0)]"
|
|
44775
44775
|
},
|
|
44776
44776
|
{
|
|
44777
44777
|
"@id": "#205/source-map/lexical/element_0",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@api-client/core",
|
|
3
3
|
"description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
|
|
4
|
-
"version": "0.18.
|
|
4
|
+
"version": "0.18.52",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./browser.js": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"types": "./build/src/index.d.ts"
|
|
19
19
|
},
|
|
20
20
|
"./package.json": "./package.json",
|
|
21
|
-
"./nanoid.js": "./build/src/nanoid
|
|
21
|
+
"./nanoid.js": "./build/src/nanoid.js",
|
|
22
22
|
"./amf/*.js": "./build/src/amf/*.js",
|
|
23
23
|
"./amf/*": "./build/src/amf/*",
|
|
24
24
|
"./authorization/*.js": "./build/src/authorization/*.js",
|
|
@@ -15,6 +15,8 @@ const orderedRoles: PermissionRole[] = ['reader', 'commenter', 'writer', 'owner'
|
|
|
15
15
|
* A predefined set of rules that can be used to determine the source of the permission.
|
|
16
16
|
* - `direct_user_grant`: The permission is granted directly to the user.
|
|
17
17
|
* - `creator_default_owner`: The permission is granted to the creator of the item as the default owner.
|
|
18
|
+
* - `parent_owner_editor_rule`: The object is placed in a folder and the owner of the folder
|
|
19
|
+
* has automatically granted role to the object.
|
|
18
20
|
*/
|
|
19
21
|
export type PermissionSourceRule = 'direct_user_grant' | 'creator_default_owner' | 'parent_owner_editor_rule'
|
|
20
22
|
|
|
@@ -338,8 +340,61 @@ export class Permission {
|
|
|
338
340
|
* Link to the `Permission.hasRole(minimumLevel, currentRole)`.
|
|
339
341
|
* @see {@link Permission.hasRole}
|
|
340
342
|
*/
|
|
341
|
-
hasRole(minimumLevel: PermissionRole
|
|
342
|
-
return Permission.hasRole(minimumLevel,
|
|
343
|
+
hasRole(minimumLevel: PermissionRole): boolean {
|
|
344
|
+
return Permission.hasRole(minimumLevel, this.role)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Checks if the user has the required role in the list of permissions.
|
|
349
|
+
* The permissions list must be filtered for the user, user's organization, and user's groups.
|
|
350
|
+
*
|
|
351
|
+
* @param minimumLevel The minimum requested role
|
|
352
|
+
* @param permissions The list of permissions to check.
|
|
353
|
+
* @returns True if the user has the required role.
|
|
354
|
+
*/
|
|
355
|
+
static hasRoleIn(minimumLevel: PermissionRole, permissions: IPermission[]): boolean {
|
|
356
|
+
if (!permissions || !permissions.length) {
|
|
357
|
+
return false
|
|
358
|
+
}
|
|
359
|
+
// 1. Sort/Group permissions by depth (ascending).
|
|
360
|
+
// We want to process the closest permissions first.
|
|
361
|
+
const sorted = [...permissions].sort((a, b) => a.depth - b.depth)
|
|
362
|
+
const closestDepth = sorted[0].depth
|
|
363
|
+
const closestPermissions = sorted.filter((p) => p.depth === closestDepth)
|
|
364
|
+
|
|
365
|
+
// 2. Specificity: User > Group > Organization
|
|
366
|
+
let effectivePermission: IPermission | undefined
|
|
367
|
+
|
|
368
|
+
// Check for user permissions
|
|
369
|
+
const userPermissions = closestPermissions.filter((p) => p.type === 'user')
|
|
370
|
+
if (userPermissions.length) {
|
|
371
|
+
// Pick highest role if multiple user permissions exist at same depth (unlikely but safe)
|
|
372
|
+
effectivePermission = userPermissions.sort((a, b) => {
|
|
373
|
+
return orderedRoles.indexOf(b.role) - orderedRoles.indexOf(a.role)
|
|
374
|
+
})[0]
|
|
375
|
+
} else {
|
|
376
|
+
// Check for group permissions
|
|
377
|
+
const groupPermissions = closestPermissions.filter((p) => p.type === 'group')
|
|
378
|
+
if (groupPermissions.length) {
|
|
379
|
+
effectivePermission = groupPermissions.sort((a, b) => {
|
|
380
|
+
return orderedRoles.indexOf(b.role) - orderedRoles.indexOf(a.role)
|
|
381
|
+
})[0]
|
|
382
|
+
} else {
|
|
383
|
+
// Check for organization permissions
|
|
384
|
+
const orgPermissions = closestPermissions.filter((p) => p.type === 'organization')
|
|
385
|
+
if (orgPermissions.length) {
|
|
386
|
+
effectivePermission = orgPermissions.sort((a, b) => {
|
|
387
|
+
return orderedRoles.indexOf(b.role) - orderedRoles.indexOf(a.role)
|
|
388
|
+
})[0]
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!effectivePermission) {
|
|
394
|
+
return false
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return Permission.hasRole(minimumLevel, effectivePermission.role)
|
|
343
398
|
}
|
|
344
399
|
|
|
345
400
|
toJSON(): IPermission {
|
|
@@ -14,7 +14,7 @@ export class MD4 {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
static core(x: number[], len: number): number[] {
|
|
17
|
-
x[len >> 5] |= 0x80 << len % 32
|
|
17
|
+
x[len >> 5] |= 0x80 << (len % 32)
|
|
18
18
|
x[(((len + 64) >>> 9) << 4) + 14] = len
|
|
19
19
|
|
|
20
20
|
let a = 1732584193
|
|
@@ -117,7 +117,7 @@ export class MD4 {
|
|
|
117
117
|
const bin: number[] = []
|
|
118
118
|
const mask = (1 << MD4.chrsz) - 1
|
|
119
119
|
for (let i = 0; i < str.length * MD4.chrsz; i += MD4.chrsz) {
|
|
120
|
-
bin[i >> 5] |= (str.charCodeAt(i / MD4.chrsz) & mask) << i % 32
|
|
120
|
+
bin[i >> 5] |= (str.charCodeAt(i / MD4.chrsz) & mask) << (i % 32)
|
|
121
121
|
}
|
|
122
122
|
return bin
|
|
123
123
|
}
|
|
@@ -126,7 +126,7 @@ export class MD4 {
|
|
|
126
126
|
let str = ''
|
|
127
127
|
const mask = (1 << MD4.chrsz) - 1
|
|
128
128
|
for (let i = 0; i < bin.length * 32; i += MD4.chrsz) {
|
|
129
|
-
str += String.fromCharCode((bin[i >> 5] >>> i % 32) & mask)
|
|
129
|
+
str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask)
|
|
130
130
|
}
|
|
131
131
|
return str
|
|
132
132
|
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { IPermission, Permission, PermissionRole, PermissionType } from '../../../../src/models/store/Permission.js'
|
|
3
|
+
|
|
4
|
+
test.group('Permission.hasRoleIn()', () => {
|
|
5
|
+
const createPerm = (role: PermissionRole, depth: number, type: PermissionType = 'user', id = 'id'): IPermission => ({
|
|
6
|
+
kind: 'Core#Permission',
|
|
7
|
+
key: 'key',
|
|
8
|
+
role,
|
|
9
|
+
depth,
|
|
10
|
+
type,
|
|
11
|
+
granteeId: id,
|
|
12
|
+
itemId: 'item',
|
|
13
|
+
addingUser: 'user',
|
|
14
|
+
sourceRule: 'direct_user_grant',
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('returns false for empty permissions', ({ assert }) => {
|
|
18
|
+
assert.isFalse(Permission.hasRoleIn('reader', []))
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('returns true when user has direct role meeting requirement', ({ assert }) => {
|
|
22
|
+
const perms = [createPerm('writer', 0)]
|
|
23
|
+
assert.isTrue(Permission.hasRoleIn('reader', perms))
|
|
24
|
+
assert.isTrue(Permission.hasRoleIn('writer', perms))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('returns false when user does not meet requirement', ({ assert }) => {
|
|
28
|
+
const perms = [createPerm('reader', 0)]
|
|
29
|
+
assert.isFalse(Permission.hasRoleIn('writer', perms))
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('prioritizes closer depth (depth 0 overrides depth 1)', ({ assert }) => {
|
|
33
|
+
// Depth 0: Reader (Direct), Depth 1: Owner (Inherited)
|
|
34
|
+
// Expectation: Reader wins (Specificity of depth) -> returns false for Writer check
|
|
35
|
+
const perms = [createPerm('reader', 0), createPerm('owner', 1)]
|
|
36
|
+
assert.isFalse(Permission.hasRoleIn('writer', perms))
|
|
37
|
+
assert.isTrue(Permission.hasRoleIn('reader', perms))
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('prioritizes closer depth (depth 1 overrides depth 2)', ({ assert }) => {
|
|
41
|
+
// Depth 1: Writer, Depth 2: Reader
|
|
42
|
+
// Expectation: Writer wins
|
|
43
|
+
const perms = [createPerm('writer', 1), createPerm('reader', 2)]
|
|
44
|
+
assert.isTrue(Permission.hasRoleIn('writer', perms))
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('prioritizes user over group at same depth', ({ assert }) => {
|
|
48
|
+
// Depth 0: User=Reader, Group=Owner
|
|
49
|
+
// Expectation: User wins -> Reader
|
|
50
|
+
const perms = [createPerm('reader', 0, 'user'), createPerm('owner', 0, 'group')]
|
|
51
|
+
assert.isFalse(Permission.hasRoleIn('writer', perms))
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('prioritizes group over organization at same depth', ({ assert }) => {
|
|
55
|
+
// Depth 0: Group=Reader, Org=Owner
|
|
56
|
+
// Expectation: Group wins -> Reader
|
|
57
|
+
const perms = [createPerm('reader', 0, 'group'), createPerm('owner', 0, 'organization')]
|
|
58
|
+
assert.isFalse(Permission.hasRoleIn('writer', perms))
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('uses highest role when multiple groups at same depth', ({ assert }) => {
|
|
62
|
+
// Depth 0: GroupA=Reader, GroupB=Writer
|
|
63
|
+
// Expectation: Writer wins (Union)
|
|
64
|
+
const perms = [createPerm('reader', 0, 'group', 'A'), createPerm('writer', 0, 'group', 'B')]
|
|
65
|
+
assert.isTrue(Permission.hasRoleIn('writer', perms))
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('uses highest role when multiple users at same depth (theoretical)', ({ assert }) => {
|
|
69
|
+
// Depth 0: User=Reader, User=Writer
|
|
70
|
+
// Expectation: Writer wins
|
|
71
|
+
const perms = [createPerm('reader', 0, 'user'), createPerm('writer', 0, 'user')]
|
|
72
|
+
assert.isTrue(Permission.hasRoleIn('writer', perms))
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('ignores deeper permissions even if they are more specific types', ({ assert }) => {
|
|
76
|
+
// Depth 0: Org=Reader
|
|
77
|
+
// Depth 1: User=Owner
|
|
78
|
+
// Expectation: Depth 0 (Org=Reader) wins because it's closer.
|
|
79
|
+
// User assumption: "closest to the item directly set... should be considered first"
|
|
80
|
+
const perms = [createPerm('reader', 0, 'organization'), createPerm('owner', 1, 'user')]
|
|
81
|
+
assert.isFalse(Permission.hasRoleIn('writer', perms))
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test.group('Permission.constructor()', () => {
|
|
86
|
+
test('creates a default permission when no input', ({ assert }) => {
|
|
87
|
+
const p = new Permission()
|
|
88
|
+
assert.equal(p.kind, 'Core#Permission')
|
|
89
|
+
assert.typeOf(p.key, 'string')
|
|
90
|
+
assert.equal(p.role, 'reader')
|
|
91
|
+
assert.equal(p.type, 'user')
|
|
92
|
+
assert.equal(p.depth, 0)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test('creates from string JSON', ({ assert }) => {
|
|
96
|
+
const json = JSON.stringify({
|
|
97
|
+
kind: 'Core#Permission',
|
|
98
|
+
key: 'key',
|
|
99
|
+
role: 'writer',
|
|
100
|
+
type: 'group',
|
|
101
|
+
granteeId: 'group-id',
|
|
102
|
+
itemId: 'item-id',
|
|
103
|
+
addingUser: 'adder',
|
|
104
|
+
})
|
|
105
|
+
const p = new Permission(json)
|
|
106
|
+
assert.equal(p.role, 'writer')
|
|
107
|
+
assert.equal(p.type, 'group')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('creates from object', ({ assert }) => {
|
|
111
|
+
const init: IPermission = {
|
|
112
|
+
kind: 'Core#Permission',
|
|
113
|
+
key: 'key',
|
|
114
|
+
role: 'owner',
|
|
115
|
+
type: 'user',
|
|
116
|
+
granteeId: 'user-id',
|
|
117
|
+
itemId: 'item-id',
|
|
118
|
+
addingUser: 'adder',
|
|
119
|
+
depth: 0,
|
|
120
|
+
sourceRule: 'direct_user_grant',
|
|
121
|
+
}
|
|
122
|
+
const p = new Permission(init)
|
|
123
|
+
assert.equal(p.role, 'owner')
|
|
124
|
+
assert.equal(p.granteeId, 'user-id')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('throws when input is not a permission', ({ assert }) => {
|
|
128
|
+
assert.throws(() => new Permission({ kind: 'Wrong' } as unknown as IPermission), /Not a permission/)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test('restores optional fields', ({ assert }) => {
|
|
132
|
+
const init: IPermission = {
|
|
133
|
+
kind: 'Core#Permission',
|
|
134
|
+
key: 'key',
|
|
135
|
+
role: 'owner',
|
|
136
|
+
type: 'user',
|
|
137
|
+
granteeId: 'user-id',
|
|
138
|
+
itemId: 'item-id',
|
|
139
|
+
addingUser: 'adder',
|
|
140
|
+
displayName: 'Name',
|
|
141
|
+
expirationTime: 12345,
|
|
142
|
+
depth: 0,
|
|
143
|
+
sourceRule: 'direct_user_grant',
|
|
144
|
+
}
|
|
145
|
+
const p = new Permission(init)
|
|
146
|
+
assert.equal(p.displayName, 'Name')
|
|
147
|
+
assert.equal(p.expirationTime, 12345)
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test.group('Permission static factories', () => {
|
|
152
|
+
test('fromUserRole creates valid permission', ({ assert }) => {
|
|
153
|
+
const p = Permission.fromUserRole('writer', 'item', 'user', 'adder')
|
|
154
|
+
assert.equal(p.type, 'user')
|
|
155
|
+
assert.equal(p.role, 'writer')
|
|
156
|
+
assert.equal(p.itemId, 'item')
|
|
157
|
+
assert.equal(p.granteeId, 'user')
|
|
158
|
+
assert.equal(p.addingUser, 'adder')
|
|
159
|
+
assert.typeOf(p.key, 'string')
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
test('fromGroupRole creates valid permission', ({ assert }) => {
|
|
163
|
+
const p = Permission.fromGroupRole('commenter', 'item', 'group', 'adder')
|
|
164
|
+
assert.equal(p.type, 'group')
|
|
165
|
+
assert.equal(p.role, 'commenter')
|
|
166
|
+
assert.equal(p.itemId, 'item')
|
|
167
|
+
assert.equal(p.granteeId, 'group')
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('fromOrganizationRole creates valid permission', ({ assert }) => {
|
|
171
|
+
const p = Permission.fromOrganizationRole('reader', 'item', 'org', 'adder')
|
|
172
|
+
assert.equal(p.type, 'organization')
|
|
173
|
+
assert.equal(p.role, 'reader')
|
|
174
|
+
assert.equal(p.itemId, 'item')
|
|
175
|
+
assert.equal(p.granteeId, 'org')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
test('fromValues creates permission with new key', ({ assert }) => {
|
|
179
|
+
const base = {
|
|
180
|
+
role: 'owner',
|
|
181
|
+
type: 'user',
|
|
182
|
+
granteeId: 'u',
|
|
183
|
+
itemId: 'i',
|
|
184
|
+
addingUser: 'a',
|
|
185
|
+
depth: 0,
|
|
186
|
+
sourceRule: 'direct_user_grant',
|
|
187
|
+
} as unknown as IPermission as unknown as IPermission
|
|
188
|
+
const p = Permission.fromValues(base)
|
|
189
|
+
assert.equal(p.role, 'owner')
|
|
190
|
+
// fromValues generates a new key
|
|
191
|
+
assert.typeOf(p.key, 'string')
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test.group('Permission.isPermission()', () => {
|
|
196
|
+
test('returns true for valid permission interface', ({ assert }) => {
|
|
197
|
+
const p = { kind: 'Core#Permission' }
|
|
198
|
+
assert.isTrue(Permission.isPermission(p))
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
test('returns false for null', ({ assert }) => {
|
|
202
|
+
assert.isFalse(Permission.isPermission(null))
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('returns false for wrong kind', ({ assert }) => {
|
|
206
|
+
assert.isFalse(Permission.isPermission({ kind: 'Wrong' }))
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test.group('Permission.hasRole()', () => {
|
|
211
|
+
test('returns false when current role is missing', ({ assert }) => {
|
|
212
|
+
assert.isFalse(Permission.hasRole('reader', undefined))
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
test('owner satisfies all', ({ assert }) => {
|
|
216
|
+
assert.isTrue(Permission.hasRole('owner', 'owner'))
|
|
217
|
+
assert.isTrue(Permission.hasRole('writer', 'owner'))
|
|
218
|
+
assert.isTrue(Permission.hasRole('commenter', 'owner'))
|
|
219
|
+
assert.isTrue(Permission.hasRole('reader', 'owner'))
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
test('writer satisfies lower', ({ assert }) => {
|
|
223
|
+
assert.isFalse(Permission.hasRole('owner', 'writer'))
|
|
224
|
+
assert.isTrue(Permission.hasRole('writer', 'writer'))
|
|
225
|
+
assert.isTrue(Permission.hasRole('commenter', 'writer'))
|
|
226
|
+
assert.isTrue(Permission.hasRole('reader', 'writer'))
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
test('reader only satisfies reader', ({ assert }) => {
|
|
230
|
+
assert.isFalse(Permission.hasRole('writer', 'reader'))
|
|
231
|
+
assert.isTrue(Permission.hasRole('reader', 'reader'))
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
test('instance method calls static', ({ assert }) => {
|
|
235
|
+
const p = Permission.fromUserRole('writer', 'item', 'user', 'adder')
|
|
236
|
+
assert.isTrue(p.hasRole('reader'))
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
test.group('Permission.isHigherRole()', () => {
|
|
241
|
+
test('owner > writer', ({ assert }) => {
|
|
242
|
+
assert.isTrue(Permission.isHigherRole('owner', 'writer'))
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
test('writer > reader', ({ assert }) => {
|
|
246
|
+
assert.isTrue(Permission.isHigherRole('writer', 'reader'))
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
test('reader !> writer', ({ assert }) => {
|
|
250
|
+
assert.isFalse(Permission.isHigherRole('reader', 'writer'))
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
test('same role returns false', ({ assert }) => {
|
|
254
|
+
assert.isFalse(Permission.isHigherRole('owner', 'owner'))
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
test.group('Permission.toJSON()', () => {
|
|
259
|
+
test('returns plain object with all fields', ({ assert }) => {
|
|
260
|
+
const p = Permission.fromUserRole('owner', 'item', 'user', 'adder')
|
|
261
|
+
p.displayName = 'User Name'
|
|
262
|
+
p.expirationTime = 1000
|
|
263
|
+
|
|
264
|
+
const json = p.toJSON()
|
|
265
|
+
assert.equal(json.kind, 'Core#Permission')
|
|
266
|
+
assert.equal(json.role, 'owner')
|
|
267
|
+
assert.equal(json.displayName, 'User Name')
|
|
268
|
+
assert.equal(json.expirationTime, 1000)
|
|
269
|
+
assert.typeOf(json.key, 'string')
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
test('omits optional fields if undefined', ({ assert }) => {
|
|
273
|
+
const p = Permission.fromUserRole('owner', 'item', 'user', 'adder')
|
|
274
|
+
const json = p.toJSON()
|
|
275
|
+
assert.isUndefined(json.displayName)
|
|
276
|
+
assert.isUndefined(json.expirationTime)
|
|
277
|
+
})
|
|
278
|
+
})
|