@atproto/oauth-scopes 0.5.2 → 0.5.3

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +10 -6
  3. package/jest.config.cjs +0 -14
  4. package/src/atproto-oauth-scope.ts +0 -79
  5. package/src/index.ts +0 -13
  6. package/src/lib/lexicon.ts +0 -21
  7. package/src/lib/mime.test.ts +0 -98
  8. package/src/lib/mime.ts +0 -71
  9. package/src/lib/nsid.ts +0 -5
  10. package/src/lib/parser.ts +0 -176
  11. package/src/lib/resource-permission.ts +0 -10
  12. package/src/lib/syntax-lexicon.ts +0 -55
  13. package/src/lib/syntax-string.test.ts +0 -130
  14. package/src/lib/syntax-string.ts +0 -132
  15. package/src/lib/syntax.test.ts +0 -43
  16. package/src/lib/syntax.ts +0 -54
  17. package/src/lib/util.ts +0 -18
  18. package/src/scope-missing-error.ts +0 -15
  19. package/src/scope-permissions-transition.test.ts +0 -122
  20. package/src/scope-permissions-transition.ts +0 -71
  21. package/src/scope-permissions.test.ts +0 -303
  22. package/src/scope-permissions.ts +0 -91
  23. package/src/scopes/account-permission.test.ts +0 -187
  24. package/src/scopes/account-permission.ts +0 -78
  25. package/src/scopes/blob-permission.test.ts +0 -126
  26. package/src/scopes/blob-permission.ts +0 -105
  27. package/src/scopes/identity-permission.test.ts +0 -80
  28. package/src/scopes/identity-permission.ts +0 -54
  29. package/src/scopes/include-scope.test.ts +0 -637
  30. package/src/scopes/include-scope.ts +0 -208
  31. package/src/scopes/repo-permission.test.ts +0 -267
  32. package/src/scopes/repo-permission.ts +0 -111
  33. package/src/scopes/rpc-permission.test.ts +0 -323
  34. package/src/scopes/rpc-permission.ts +0 -90
  35. package/src/scopes-set.test.ts +0 -47
  36. package/src/scopes-set.ts +0 -134
  37. package/tsconfig.build.json +0 -9
  38. package/tsconfig.build.tsbuildinfo +0 -1
  39. package/tsconfig.json +0 -7
  40. package/tsconfig.tests.json +0 -7
@@ -1,637 +0,0 @@
1
- import { LexPermissionSyntax } from '../lib/syntax-lexicon.js'
2
- import { ScopeStringFor } from '../lib/syntax.js'
3
- import { AccountPermission } from './account-permission.js'
4
- import { IdentityPermission } from './identity-permission.js'
5
- import { IncludeScope, LexiconPermissionSet } from './include-scope.js'
6
-
7
- describe('IncludeScope', () => {
8
- describe('static', () => {
9
- describe('fromString', () => {
10
- describe('enables', () => {
11
- it('parsing of positional nsid', () => {
12
- expect(
13
- IncludeScope.fromString('include:com.example.bar'),
14
- ).toMatchObject({
15
- nsid: 'com.example.bar',
16
- aud: undefined,
17
- })
18
- })
19
-
20
- it('parsing of positional nsid and aud param', () => {
21
- expect(
22
- IncludeScope.fromString(
23
- 'include:com.example.baz?aud=did:web:example.com%23my_service',
24
- ),
25
- ).toMatchObject({
26
- nsid: 'com.example.baz',
27
- aud: 'did:web:example.com#my_service',
28
- })
29
- })
30
-
31
- it('parsing of # character in query string', () => {
32
- expect(
33
- IncludeScope.fromString(
34
- 'include:com.example.baz?aud=did:web:example.com#my_service',
35
- ),
36
- ).toMatchObject({
37
- nsid: 'com.example.baz',
38
- aud: 'did:web:example.com#my_service',
39
- })
40
- })
41
-
42
- it('parsing of named nsid', () => {
43
- expect(
44
- IncludeScope.fromString('include?nsid=com.example.baz'),
45
- ).toMatchObject({
46
- nsid: 'com.example.baz',
47
- aud: undefined,
48
- })
49
- })
50
-
51
- it('parsing of named nsid and aud', () => {
52
- expect(
53
- IncludeScope.fromString(
54
- 'include?aud=did:web:example.com%23my_service&nsid=com.example.baz',
55
- ),
56
- ).toMatchObject({
57
- nsid: 'com.example.baz',
58
- aud: 'did:web:example.com#my_service',
59
- })
60
- })
61
- })
62
-
63
- describe('rejects', () => {
64
- for (const invalid of [
65
- '',
66
- 'repo:com.example.baz',
67
- 'include',
68
- 'include#',
69
-
70
- // Invalid NSID
71
- 'include:',
72
- 'include:#',
73
- 'include:&',
74
- 'include:com..example',
75
- 'include:com',
76
- 'include:com.example',
77
- 'include:9com.example.foo',
78
- 'include:com.example.-bar',
79
- 'include:invalid^nsid',
80
- 'include:nsid',
81
-
82
- // Invalid AUD
83
- 'include:com.example.baz?aud=',
84
- 'include:com.example.baz?aud=did:web:example.com',
85
- 'include:com.example.baz?aud=invalid^did',
86
- 'include:com.example.baz?aud=invalid^did',
87
- ]) {
88
- it(JSON.stringify(invalid), () => {
89
- expect(IncludeScope.fromString(invalid)).toBeNull()
90
- })
91
- }
92
- })
93
- })
94
- })
95
-
96
- describe('instance', () => {
97
- describe('toString', () => {
98
- describe('enables', () => {
99
- it('formating of scope without aud', () => {
100
- expect(new IncludeScope('com.example.foo').toString()).toEqual(
101
- 'include:com.example.foo',
102
- )
103
- })
104
- it('formating of scope with aud', () => {
105
- expect(
106
- new IncludeScope(
107
- 'com.example.foo',
108
- 'did:web:example.com#my_service',
109
- ).toString(),
110
- ).toEqual(
111
- 'include:com.example.foo?aud=did:web:example.com%23my_service',
112
- )
113
- })
114
- })
115
- })
116
-
117
- describe('isParentAuthorityOf', () => {
118
- const scope = new IncludeScope('com.example.foo.auth')
119
-
120
- describe('enables', () => {
121
- it('same authority', () => {
122
- expect(scope.isParentAuthorityOf('com.example.foo.identifier')).toBe(
123
- true,
124
- )
125
- })
126
-
127
- it('child authorities', () => {
128
- expect(scope.isParentAuthorityOf('com.example.foo.bar.baz')).toBe(
129
- true,
130
- )
131
- expect(scope.isParentAuthorityOf('com.example.foo.bar.baz.quz')).toBe(
132
- true,
133
- )
134
- })
135
- })
136
-
137
- describe('rejects', () => {
138
- it('invalid nsids', () => {
139
- // @ts-expect-error
140
- expect(scope.isParentAuthorityOf('com')).toBe(false)
141
- // @ts-expect-error
142
- expect(scope.isParentAuthorityOf('com.example')).toBe(false)
143
- })
144
-
145
- it('siblings of root domain', () => {
146
- expect(scope.isParentAuthorityOf('com.example.bar')).toBe(false)
147
- expect(scope.isParentAuthorityOf('com.example.bar.foo')).toBe(false)
148
- expect(scope.isParentAuthorityOf('com.example.bar.qux')).toBe(false)
149
- })
150
-
151
- it('other domains', () => {
152
- expect(scope.isParentAuthorityOf('com.atproto.foo')).toBe(false)
153
- expect(scope.isParentAuthorityOf('com.atproto.foo.auth')).toBe(false)
154
- expect(scope.isParentAuthorityOf('com.atproto.foo.bar')).toBe(false)
155
- expect(scope.isParentAuthorityOf('com.atproto.foo.bar')).toBe(false)
156
- })
157
- })
158
- })
159
-
160
- describe('buildPermissions', () => {
161
- /**
162
- * Utility that transforms a (valid) "include:<nsid>" scope and matching
163
- * (resolved) permission set into the list of permission scopes.
164
- */
165
- const compilePermissions = (
166
- scope: ScopeStringFor<'include'>,
167
- permissionSet: LexiconPermissionSet,
168
- ) => IncludeScope.fromString(scope)!.toScopes(permissionSet)
169
-
170
- describe('blob', () => {
171
- describe('rejects', () => {
172
- it('valid permissions', () => {
173
- expect(
174
- compilePermissions('include:com.example.calendar.auth', {
175
- type: 'permission-set',
176
- permissions: [
177
- {
178
- type: 'permission',
179
- resource: 'blob',
180
- accept: ['image/*'],
181
- },
182
- ],
183
- }),
184
- ).toEqual([])
185
- })
186
-
187
- it('invalid permissions', () => {
188
- expect(
189
- compilePermissions('include:com.example.calendar.auth', {
190
- type: 'permission-set',
191
- permissions: [
192
- {
193
- type: 'permission',
194
- resource: 'blob',
195
- accept: 'image/*',
196
- },
197
- ],
198
- }),
199
- ).toEqual([])
200
-
201
- expect(
202
- compilePermissions('include:com.example.calendar.auth', {
203
- type: 'permission-set',
204
- permissions: [
205
- {
206
- type: 'permission',
207
- resource: 'blob',
208
- accept: ['image/*'],
209
- extra: 'property',
210
- },
211
- ],
212
- }),
213
- ).toEqual([])
214
- })
215
- })
216
- })
217
-
218
- describe('rpc', () => {
219
- describe('enables', () => {
220
- it('allows * aud', () => {
221
- expect(
222
- compilePermissions('include:com.example.calendar.auth', {
223
- type: 'permission-set',
224
- permissions: [
225
- {
226
- type: 'permission',
227
- resource: 'rpc',
228
- aud: '*',
229
- lxm: ['com.example.calendar.listEvents'],
230
- },
231
- ],
232
- }),
233
- ).toEqual(['rpc:com.example.calendar.listEvents?aud=*'])
234
- })
235
-
236
- it('inherits aud', () => {
237
- expect(
238
- compilePermissions(
239
- 'include:com.example.calendar.auth?aud=did:web:example.com#foo',
240
- {
241
- type: 'permission-set',
242
- permissions: [
243
- {
244
- type: 'permission',
245
- resource: 'rpc',
246
- inheritAud: true,
247
- lxm: ['com.example.calendar.listEvents'],
248
- },
249
- {
250
- type: 'permission',
251
- resource: 'rpc',
252
- inheritAud: true,
253
- lxm: ['com.example.calendar.getEventDetails'],
254
- },
255
- ],
256
- },
257
- ),
258
- ).toEqual([
259
- 'rpc:com.example.calendar.listEvents?aud=did:web:example.com%23foo',
260
- 'rpc:com.example.calendar.getEventDetails?aud=did:web:example.com%23foo',
261
- ])
262
- })
263
- })
264
-
265
- describe('rejects', () => {
266
- it('forbids use of specific "aud"', () => {
267
- expect(
268
- compilePermissions('include:com.example.calendar.auth', {
269
- type: 'permission-set',
270
- permissions: [
271
- {
272
- type: 'permission',
273
- resource: 'rpc',
274
- aud: 'did:web:example.com#foo',
275
- lxm: ['com.example.calendar.listEvents'],
276
- },
277
- ],
278
- }),
279
- ).toEqual([])
280
- })
281
-
282
- it('invalid "lxm" syntax', () => {
283
- expect(
284
- compilePermissions('include:com.example.calendar.auth', {
285
- type: 'permission-set',
286
- permissions: [
287
- {
288
- type: 'permission',
289
- resource: 'rpc',
290
- aud: 'did:web:example.com#foo',
291
- lxm: 'com.example.calendar.listEvents',
292
- },
293
- ],
294
- }),
295
- ).toEqual([])
296
- })
297
-
298
- it('extra properties', () => {
299
- expect(
300
- compilePermissions('include:com.example.calendar.auth', {
301
- type: 'permission-set',
302
- permissions: [
303
- {
304
- type: 'permission',
305
- resource: 'rpc',
306
- aud: 'did:web:example.com#foo',
307
- lxm: ['com.example.calendar.listEvents'],
308
- extra: 'property',
309
- },
310
- ],
311
- }),
312
- ).toEqual([])
313
- })
314
-
315
- it('missing "lxm"', () => {
316
- expect(
317
- compilePermissions('include:com.example.calendar.auth', {
318
- type: 'permission-set',
319
- permissions: [
320
- {
321
- type: 'permission',
322
- resource: 'rpc',
323
- aud: 'did:web:example.com#foo',
324
- },
325
- ],
326
- }),
327
- ).toEqual([])
328
- })
329
-
330
- it('missing "aud"', () => {
331
- expect(
332
- compilePermissions('include:com.example.calendar.auth', {
333
- type: 'permission-set',
334
- permissions: [
335
- {
336
- type: 'permission',
337
- resource: 'rpc',
338
- lxm: ['com.example.calendar.listEvents'],
339
- },
340
- ],
341
- }),
342
- ).toEqual([])
343
- })
344
-
345
- it('missing "aud" and "lxm"', () => {
346
- expect(
347
- compilePermissions('include:com.example.calendar.auth', {
348
- type: 'permission-set',
349
- permissions: [
350
- {
351
- type: 'permission',
352
- resource: 'rpc',
353
- },
354
- ],
355
- }),
356
- ).toEqual([])
357
- })
358
-
359
- it('both "inheritAud" and "aud" specified', () => {
360
- expect(
361
- compilePermissions(
362
- 'include:com.example.calendar.auth?aud=did:web:example.com#bar',
363
- {
364
- type: 'permission-set',
365
- permissions: [
366
- {
367
- type: 'permission',
368
- resource: 'rpc',
369
- aud: 'did:web:example.com#foo',
370
- inheritAud: true,
371
- lxm: ['com.example.calendar.listEvents'],
372
- },
373
- ],
374
- },
375
- ),
376
- ).toEqual([])
377
- })
378
-
379
- it('invalid authority', () => {
380
- expect(
381
- compilePermissions('include:com.example.calendar.auth', {
382
- type: 'permission-set',
383
- permissions: [
384
- {
385
- type: 'permission',
386
- resource: 'rpc',
387
- aud: 'did:web:example.com#foo',
388
- lxm: ['com.atproto.moderation.createReport'],
389
- },
390
- ],
391
- }),
392
- ).toEqual([])
393
- })
394
-
395
- it('un-specified inherited-aud', () => {
396
- expect(
397
- compilePermissions('include:com.example.calendar.auth', {
398
- type: 'permission-set',
399
- permissions: [
400
- {
401
- type: 'permission',
402
- resource: 'rpc',
403
- inheritAud: true,
404
- lxm: ['com.example.calendar.listEvents'],
405
- },
406
- ],
407
- }),
408
- ).toEqual([])
409
- })
410
-
411
- it('wildcard-aud', () => {
412
- expect(
413
- compilePermissions('include:com.example.calendar.auth', {
414
- type: 'permission-set',
415
- permissions: [
416
- {
417
- type: 'permission',
418
- resource: 'rpc',
419
- aud: '*',
420
- lxm: ['com.example.calendar.listEvents'],
421
- },
422
- ],
423
- }),
424
- ).toEqual(['rpc:com.example.calendar.listEvents?aud=*'])
425
- })
426
-
427
- it('wildcard-aud for invalid authority', () => {
428
- expect(
429
- compilePermissions('include:com.example.calendar.auth', {
430
- type: 'permission-set',
431
- permissions: [
432
- {
433
- type: 'permission',
434
- resource: 'rpc',
435
- aud: '*',
436
- lxm: ['com.atproto.moderation.createReport'],
437
- },
438
- ],
439
- }),
440
- ).toEqual([])
441
- })
442
- })
443
- })
444
-
445
- describe('repo', () => {
446
- describe('enabled', () => {
447
- it('valid permission', () => {
448
- expect(
449
- compilePermissions('include:com.example.calendar.auth', {
450
- type: 'permission-set',
451
- permissions: [
452
- {
453
- type: 'permission',
454
- resource: 'repo',
455
- collection: ['com.example.calendar.event'],
456
- action: ['create', 'update', 'delete'],
457
- },
458
- ],
459
- }),
460
- ).toEqual(['repo:com.example.calendar.event'])
461
- })
462
-
463
- it('valid permission with partial actions', () => {
464
- expect(
465
- compilePermissions('include:com.example.calendar.auth', {
466
- type: 'permission-set',
467
- permissions: [
468
- {
469
- type: 'permission',
470
- resource: 'repo',
471
- collection: ['com.example.calendar.event'],
472
- action: ['delete', 'update'],
473
- },
474
- {
475
- type: 'permission',
476
- resource: 'repo',
477
- collection: [
478
- 'com.example.calendar.event',
479
- 'com.example.calendar.rsvp',
480
- ],
481
- action: ['delete', 'create'],
482
- },
483
- ],
484
- }),
485
- ).toEqual([
486
- 'repo:com.example.calendar.event?action=update&action=delete',
487
- 'repo?collection=com.example.calendar.event&collection=com.example.calendar.rsvp&action=create&action=delete',
488
- ])
489
- })
490
- })
491
-
492
- describe('rejects', () => {
493
- it('invalid "collection" syntax', () => {
494
- expect(
495
- compilePermissions('include:com.example.calendar.auth', {
496
- type: 'permission-set',
497
- permissions: [
498
- {
499
- type: 'permission',
500
- resource: 'repo',
501
- collection: 'com.example.calendar.event',
502
- action: ['create', 'update', 'delete'],
503
- },
504
- ],
505
- }),
506
- ).toEqual([])
507
- })
508
-
509
- it('invalid "action" syntax', () => {
510
- expect(
511
- compilePermissions('include:com.example.calendar.auth', {
512
- type: 'permission-set',
513
- permissions: [
514
- {
515
- type: 'permission',
516
- resource: 'repo',
517
- collection: ['com.example.calendar.event'],
518
- action: 'all',
519
- },
520
- ],
521
- }),
522
- ).toEqual([])
523
- })
524
-
525
- it('invalid "action" values', () => {
526
- expect(
527
- compilePermissions('include:com.example.calendar.auth', {
528
- type: 'permission-set',
529
- permissions: [
530
- {
531
- type: 'permission',
532
- resource: 'repo',
533
- collection: ['com.example.calendar.event'],
534
- action: ['create', 'update', 'manage'],
535
- },
536
- ],
537
- }),
538
- ).toEqual([])
539
- })
540
-
541
- it('invalid authority', () => {
542
- expect(
543
- compilePermissions('include:com.example.calendar.auth', {
544
- type: 'permission-set',
545
- permissions: [
546
- {
547
- type: 'permission',
548
- resource: 'repo',
549
- collection: ['app.bsky.feed.post'],
550
- action: ['create', 'update', 'delete'],
551
- },
552
- ],
553
- }),
554
- ).toEqual([])
555
- })
556
-
557
- it('permissions with one valid and one invalid authority', () => {
558
- expect(
559
- compilePermissions('include:com.example.calendar.auth', {
560
- type: 'permission-set',
561
- permissions: [
562
- {
563
- type: 'permission',
564
- resource: 'repo',
565
- collection: [
566
- 'com.example.calendar.event',
567
- 'app.bsky.feed.post',
568
- ],
569
- action: ['create', 'update', 'delete'],
570
- },
571
- ],
572
- }),
573
- ).toEqual([])
574
- })
575
- })
576
- })
577
-
578
- describe('account', () => {
579
- const permission = {
580
- type: 'permission',
581
- resource: 'account',
582
- attr: 'email',
583
- action: ['read'],
584
- } as const
585
-
586
- it('parses valid permission syntax', () => {
587
- // Just to make sure that the test bellow doesn't give a false negative
588
- const syntax = new LexPermissionSyntax(permission)
589
- expect(AccountPermission.fromSyntax(syntax)).toMatchObject({
590
- constructor: AccountPermission,
591
- attr: 'email',
592
- action: ['read'],
593
- })
594
- })
595
-
596
- describe('rejects', () => {
597
- it('account permissions', () => {
598
- expect(
599
- compilePermissions('include:com.example.calendar.auth', {
600
- type: 'permission-set',
601
- permissions: [permission],
602
- }),
603
- ).toEqual([])
604
- })
605
- })
606
- })
607
-
608
- describe('identity', () => {
609
- const permission = {
610
- type: 'permission',
611
- resource: 'identity',
612
- attr: 'handle',
613
- } as const
614
-
615
- it('parses valid permission syntax', () => {
616
- // Just to make sure that the test bellow doesn't give a false negative
617
- const syntax = new LexPermissionSyntax(permission)
618
- expect(IdentityPermission.fromSyntax(syntax)).toMatchObject({
619
- constructor: IdentityPermission,
620
- attr: 'handle',
621
- })
622
- })
623
-
624
- describe('rejects', () => {
625
- it('identity permissions', () => {
626
- expect(
627
- compilePermissions('include:com.example.calendar.auth', {
628
- type: 'permission-set',
629
- permissions: [permission],
630
- }),
631
- ).toEqual([])
632
- })
633
- })
634
- })
635
- })
636
- })
637
- })