@atproto/oauth-scopes 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atproto/oauth-scopes
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#4992](https://github.com/bluesky-social/atproto/pull/4992) [`622d365`](https://github.com/bluesky-social/atproto/commit/622d365aeb240133f40763a3b1c43981112837fc) Thanks [@devinivy](https://github.com/devinivy)! - **BREAKING:** Remove the `AtprotoAudience` and `isAtprotoAudience` re-exports. They are superseded by `AtprotoDidRefAbsolute` and `isAtprotoDidRefAbsolute`, also re-exported from this package.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`622d365`](https://github.com/bluesky-social/atproto/commit/622d365aeb240133f40763a3b1c43981112837fc)]:
12
+ - @atproto/did@0.5.0
13
+
3
14
  ## 0.4.0
4
15
 
5
16
  ### Minor Changes
@@ -1,10 +1,9 @@
1
- import { AtprotoAudience } from '@atproto/did';
2
1
  import { LexiconPermission, LexiconPermissionSet } from '../lib/lexicon.js';
3
2
  import { Nsid, isNsid } from '../lib/nsid.js';
4
3
  import { Parser } from '../lib/parser.js';
5
4
  import { ScopeStringFor, ScopeSyntax } from '../lib/syntax.js';
6
5
  import { RepoPermission } from './repo-permission.js';
7
- import { RpcPermission } from './rpc-permission.js';
6
+ import { AtprotoDidRefAbsolute, RpcPermission, isAtprotoDidRefAbsolute } from './rpc-permission.js';
8
7
  export { type LexiconPermission, type LexiconPermissionSet, type Nsid, isNsid };
9
8
  /**
10
9
  * This is used to handle "include:" oauth scope values, used to include
@@ -13,8 +12,8 @@ export { type LexiconPermission, type LexiconPermissionSet, type Nsid, isNsid };
13
12
  */
14
13
  export declare class IncludeScope {
15
14
  readonly nsid: Nsid;
16
- readonly aud: undefined | AtprotoAudience;
17
- constructor(nsid: Nsid, aud?: undefined | AtprotoAudience);
15
+ readonly aud: undefined | AtprotoDidRefAbsolute;
16
+ constructor(nsid: Nsid, aud?: undefined | AtprotoDidRefAbsolute);
18
17
  toString(): ScopeStringFor<"include">;
19
18
  toPermissions(permissionSet: LexiconPermissionSet): Array<RepoPermission | RpcPermission>;
20
19
  toScopes(permissionSet: LexiconPermissionSet): Array<ScopeStringFor<'repo' | 'rpc'>>;
@@ -46,7 +45,7 @@ export declare class IncludeScope {
46
45
  aud: {
47
46
  multiple: false;
48
47
  required: false;
49
- validate: (value: unknown) => value is AtprotoAudience;
48
+ validate: typeof isAtprotoDidRefAbsolute;
50
49
  };
51
50
  }>;
52
51
  static fromString(scope: string): IncludeScope | null;
@@ -1 +1 @@
1
- {"version":3,"file":"include-scope.d.ts","sourceRoot":"","sources":["../../src/scopes/include-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAqB,MAAM,cAAc,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAGzC,OAAO,EACL,cAAc,EACd,WAAW,EAGZ,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,IAAI,EAAE,MAAM,EAAE,CAAA;AAE/E;;;;GAIG;AACH,qBAAa,YAAY;aAEL,IAAI,EAAE,IAAI;aACV,GAAG,EAAE,SAAS,GAAG,eAAe;gBADhC,IAAI,EAAE,IAAI,EACV,GAAG,GAAE,SAAS,GAAG,eAA2B;IAG9D,QAAQ;IAIR,aAAa,CACX,aAAa,EAAE,oBAAoB,GAClC,KAAK,CAAC,cAAc,GAAG,aAAa,CAAC;IAIxC,QAAQ,CACN,aAAa,EAAE,oBAAoB,GAClC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAIxC;;;OAGG;IACF,gBAAgB,CACf,aAAa,EAAE,oBAAoB,GAClC,SAAS,CAAC,cAAc,GAAG,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC;IAc3D,SAAS,CAAC,kBAAkB,CAC1B,UAAU,EAAE,iBAAiB,GAC5B,WAAW,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,IAAI;IAkCrC;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAC3B,UAAU,EAAE,aAAa,GAAG,cAAc,GACzC,OAAO;IAYV;;;;OAIG;IACI,mBAAmB,CAAC,SAAS,EAAE,GAAG,GAAG,IAAI;IAgChD,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;;;;;;;;OAe/B;IAED,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM;IAM/B,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC;CAKjD"}
1
+ {"version":3,"file":"include-scope.d.ts","sourceRoot":"","sources":["../../src/scopes/include-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAGzC,OAAO,EACL,cAAc,EACd,WAAW,EAGZ,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,uBAAuB,EACxB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,IAAI,EAAE,MAAM,EAAE,CAAA;AAE/E;;;;GAIG;AACH,qBAAa,YAAY;aAEL,IAAI,EAAE,IAAI;aACV,GAAG,EAAE,SAAS,GAAG,qBAAqB;gBADtC,IAAI,EAAE,IAAI,EACV,GAAG,GAAE,SAAS,GAAG,qBAAiC;IAGpE,QAAQ;IAIR,aAAa,CACX,aAAa,EAAE,oBAAoB,GAClC,KAAK,CAAC,cAAc,GAAG,aAAa,CAAC;IAIxC,QAAQ,CACN,aAAa,EAAE,oBAAoB,GAClC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAIxC;;;OAGG;IACF,gBAAgB,CACf,aAAa,EAAE,oBAAoB,GAClC,SAAS,CAAC,cAAc,GAAG,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC;IAc3D,SAAS,CAAC,kBAAkB,CAC1B,UAAU,EAAE,iBAAiB,GAC5B,WAAW,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,IAAI;IAkCrC;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAC3B,UAAU,EAAE,aAAa,GAAG,cAAc,GACzC,OAAO;IAYV;;;;OAIG;IACI,mBAAmB,CAAC,SAAS,EAAE,GAAG,GAAG,IAAI;IAgChD,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;;;;;;;;OAe/B;IAED,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM;IAM/B,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC;CAKjD"}
@@ -1,11 +1,10 @@
1
- import { isAtprotoAudience } from '@atproto/did';
2
1
  import { isNsid } from '../lib/nsid.js';
3
2
  import { Parser } from '../lib/parser.js';
4
3
  import { LexPermissionSyntax } from '../lib/syntax-lexicon.js';
5
4
  import { ScopeStringSyntax } from '../lib/syntax-string.js';
6
5
  import { isScopeStringFor, isScopeSyntaxFor, } from '../lib/syntax.js';
7
6
  import { RepoPermission } from './repo-permission.js';
8
- import { RpcPermission } from './rpc-permission.js';
7
+ import { RpcPermission, isAtprotoDidRefAbsolute, } from './rpc-permission.js';
9
8
  export { isNsid };
10
9
  /**
11
10
  * This is used to handle "include:" oauth scope values, used to include
@@ -123,7 +122,7 @@ export class IncludeScope {
123
122
  aud: {
124
123
  multiple: false,
125
124
  required: false,
126
- validate: isAtprotoAudience,
125
+ validate: isAtprotoDidRefAbsolute,
127
126
  },
128
127
  }, 'nsid'); }
129
128
  static fromString(scope) {
@@ -1 +1 @@
1
- {"version":3,"file":"include-scope.js","sourceRoot":"","sources":["../../src/scopes/include-scope.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtprotoAudience, isAtprotoAudience } from '@atproto/did'\nimport { LexiconPermission, LexiconPermissionSet } from '../lib/lexicon.js'\nimport { Nsid, isNsid } from '../lib/nsid.js'\nimport { Parser } from '../lib/parser.js'\nimport { LexPermissionSyntax } from '../lib/syntax-lexicon.js'\nimport { ScopeStringSyntax } from '../lib/syntax-string.js'\nimport {\n ScopeStringFor,\n ScopeSyntax,\n isScopeStringFor,\n isScopeSyntaxFor,\n} from '../lib/syntax.js'\nimport { RepoPermission } from './repo-permission.js'\nimport { RpcPermission } from './rpc-permission.js'\n\nexport { type LexiconPermission, type LexiconPermissionSet, type Nsid, isNsid }\n\n/**\n * This is used to handle \"include:\" oauth scope values, used to include\n * permissions from a lexicon defined permission set. Not being a resource\n * permission, it does not implement `Matchable`.\n */\nexport class IncludeScope {\n constructor(\n public readonly nsid: Nsid,\n public readonly aud: undefined | AtprotoAudience = undefined,\n ) {}\n\n toString() {\n return IncludeScope.parser.format(this)\n }\n\n toPermissions(\n permissionSet: LexiconPermissionSet,\n ): Array<RepoPermission | RpcPermission> {\n return Array.from(this.buildPermissions(permissionSet))\n }\n\n toScopes(\n permissionSet: LexiconPermissionSet,\n ): Array<ScopeStringFor<'repo' | 'rpc'>> {\n return Array.from(this.buildPermissions(permissionSet), (p) => p.toString())\n }\n\n /**\n * Converts an \"include:\" to the list of permissions it includes, based on the\n * lexicon defined permission set.\n */\n *buildPermissions(\n permissionSet: LexiconPermissionSet,\n ): Generator<RepoPermission | RpcPermission, void, unknown> {\n for (const lexPermission of permissionSet.permissions) {\n const syntax = this.parseLexPermission(lexPermission)\n if (!syntax) continue\n\n const resourcePermission = toResourcePermission(syntax)\n if (!resourcePermission) continue\n\n if (this.isAllowedPermission(resourcePermission)) {\n yield resourcePermission\n }\n }\n }\n\n protected parseLexPermission(\n permission: LexiconPermission,\n ): ScopeSyntax<'repo' | 'rpc'> | null {\n // This function converts permissions listed in the permission set into\n // their respective ScopeSyntax representations, handling special cases as\n // needed.\n\n if (isLexPermissionForResource(permission, 'repo')) {\n return new LexPermissionSyntax(permission)\n }\n\n if (isLexPermissionForResource(permission, 'rpc')) {\n // \"rpc\" permissions with a defined audience are not allowed in permission\n // sets\n if (permission.aud !== undefined && permission.aud !== '*') {\n return null\n }\n\n // \"rpc\" permissions can \"inherit\" their audience from \"aud\" param defined\n // in the \"include:<nsid>?aud=<audience>\" scope the permission set was\n // loaded from.\n if (\n permission.inheritAud === true &&\n permission.aud === undefined &&\n this.aud !== undefined\n ) {\n const { inheritAud, ...rest } = permission\n return new LexPermissionSyntax({ aud: this.aud, ...rest })\n }\n\n return new LexPermissionSyntax(permission)\n }\n\n return null\n }\n\n /**\n * Verifies that a permission included through a lexicon permission set is\n * allowed in the context of the `include:` scope. This basically checks that\n * the permission is \"under\" the namespace authority of the `include:` scope,\n * and that it only contains \"repo:\", \"rpc:\", or \"blob:\" permissions.\n */\n protected isAllowedPermission(\n permission: RpcPermission | RepoPermission,\n ): boolean {\n if (permission instanceof RpcPermission) {\n return permission.lxm.every(this.isParentAuthorityOf, this)\n }\n\n if (permission instanceof RepoPermission) {\n return permission.collection.every(this.isParentAuthorityOf, this)\n }\n\n throw new TypeError(`Unexpected permission ${permission}`)\n }\n\n /**\n * Verifies that a permission item's nsid is under the same authority as the\n * nsid of the lexicon itself (which is the same as the nsid of the `include:`\n * scope).\n */\n public isParentAuthorityOf(otherNsid: '*' | Nsid) {\n if (otherNsid === '*') {\n return false\n }\n\n const lexiconNsid = this.nsid\n\n const groupPrefixEnd = lexiconNsid.lastIndexOf('.')\n\n // There should always be a dot, but since this is a security feature, let's\n // be strict about it.\n if (groupPrefixEnd === -1) {\n throw new TypeError('Dot character (\".\") missing from lexicon NSID')\n }\n\n // Make sure that otherNsid is at least as long as the \"group prefix\"\n if (groupPrefixEnd >= otherNsid.length - 1) {\n return false\n }\n\n // Make sure that the \"otherNsid\" starts with the group of the lexiconNsid,\n // up to the dot itself. We check in reverse order as nsids tend to have\n // long common prefixes.\n for (let i = groupPrefixEnd; i >= 0; i--) {\n if (lexiconNsid.charCodeAt(i) !== otherNsid.charCodeAt(i)) {\n return false\n }\n }\n\n return true\n }\n\n protected static readonly parser = new Parser(\n 'include',\n {\n nsid: {\n multiple: false,\n required: true,\n validate: isNsid,\n },\n aud: {\n multiple: false,\n required: false,\n validate: isAtprotoAudience,\n },\n },\n 'nsid',\n )\n\n static fromString(scope: string) {\n if (!isScopeStringFor(scope, 'include')) return null\n const syntax = ScopeStringSyntax.fromString(scope)\n return IncludeScope.fromSyntax(syntax)\n }\n\n static fromSyntax(syntax: ScopeSyntax<'include'>) {\n const result = IncludeScope.parser.parse(syntax)\n if (!result) return null\n return new IncludeScope(result.nsid, result.aud)\n }\n}\n\nfunction toResourcePermission(\n syntax: ScopeSyntax<'repo' | 'rpc'>,\n): RepoPermission | RpcPermission | null {\n if (isScopeSyntaxFor(syntax, 'repo')) {\n return RepoPermission.fromSyntax(syntax)\n }\n if (isScopeSyntaxFor(syntax, 'rpc')) {\n return RpcPermission.fromSyntax(syntax)\n }\n return null\n}\n\nfunction isLexPermissionForResource<\n P extends { resource: unknown },\n T extends string,\n>(permission: P, type: T): permission is P & { resource: T } {\n return permission.resource === type\n}\n"]}
1
+ {"version":3,"file":"include-scope.js","sourceRoot":"","sources":["../../src/scopes/include-scope.ts"],"names":[],"mappings":"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","sourcesContent":["import { LexiconPermission, LexiconPermissionSet } from '../lib/lexicon.js'\nimport { Nsid, isNsid } from '../lib/nsid.js'\nimport { Parser } from '../lib/parser.js'\nimport { LexPermissionSyntax } from '../lib/syntax-lexicon.js'\nimport { ScopeStringSyntax } from '../lib/syntax-string.js'\nimport {\n ScopeStringFor,\n ScopeSyntax,\n isScopeStringFor,\n isScopeSyntaxFor,\n} from '../lib/syntax.js'\nimport { RepoPermission } from './repo-permission.js'\nimport {\n AtprotoDidRefAbsolute,\n RpcPermission,\n isAtprotoDidRefAbsolute,\n} from './rpc-permission.js'\n\nexport { type LexiconPermission, type LexiconPermissionSet, type Nsid, isNsid }\n\n/**\n * This is used to handle \"include:\" oauth scope values, used to include\n * permissions from a lexicon defined permission set. Not being a resource\n * permission, it does not implement `Matchable`.\n */\nexport class IncludeScope {\n constructor(\n public readonly nsid: Nsid,\n public readonly aud: undefined | AtprotoDidRefAbsolute = undefined,\n ) {}\n\n toString() {\n return IncludeScope.parser.format(this)\n }\n\n toPermissions(\n permissionSet: LexiconPermissionSet,\n ): Array<RepoPermission | RpcPermission> {\n return Array.from(this.buildPermissions(permissionSet))\n }\n\n toScopes(\n permissionSet: LexiconPermissionSet,\n ): Array<ScopeStringFor<'repo' | 'rpc'>> {\n return Array.from(this.buildPermissions(permissionSet), (p) => p.toString())\n }\n\n /**\n * Converts an \"include:\" to the list of permissions it includes, based on the\n * lexicon defined permission set.\n */\n *buildPermissions(\n permissionSet: LexiconPermissionSet,\n ): Generator<RepoPermission | RpcPermission, void, unknown> {\n for (const lexPermission of permissionSet.permissions) {\n const syntax = this.parseLexPermission(lexPermission)\n if (!syntax) continue\n\n const resourcePermission = toResourcePermission(syntax)\n if (!resourcePermission) continue\n\n if (this.isAllowedPermission(resourcePermission)) {\n yield resourcePermission\n }\n }\n }\n\n protected parseLexPermission(\n permission: LexiconPermission,\n ): ScopeSyntax<'repo' | 'rpc'> | null {\n // This function converts permissions listed in the permission set into\n // their respective ScopeSyntax representations, handling special cases as\n // needed.\n\n if (isLexPermissionForResource(permission, 'repo')) {\n return new LexPermissionSyntax(permission)\n }\n\n if (isLexPermissionForResource(permission, 'rpc')) {\n // \"rpc\" permissions with a defined audience are not allowed in permission\n // sets\n if (permission.aud !== undefined && permission.aud !== '*') {\n return null\n }\n\n // \"rpc\" permissions can \"inherit\" their audience from \"aud\" param defined\n // in the \"include:<nsid>?aud=<audience>\" scope the permission set was\n // loaded from.\n if (\n permission.inheritAud === true &&\n permission.aud === undefined &&\n this.aud !== undefined\n ) {\n const { inheritAud, ...rest } = permission\n return new LexPermissionSyntax({ aud: this.aud, ...rest })\n }\n\n return new LexPermissionSyntax(permission)\n }\n\n return null\n }\n\n /**\n * Verifies that a permission included through a lexicon permission set is\n * allowed in the context of the `include:` scope. This basically checks that\n * the permission is \"under\" the namespace authority of the `include:` scope,\n * and that it only contains \"repo:\", \"rpc:\", or \"blob:\" permissions.\n */\n protected isAllowedPermission(\n permission: RpcPermission | RepoPermission,\n ): boolean {\n if (permission instanceof RpcPermission) {\n return permission.lxm.every(this.isParentAuthorityOf, this)\n }\n\n if (permission instanceof RepoPermission) {\n return permission.collection.every(this.isParentAuthorityOf, this)\n }\n\n throw new TypeError(`Unexpected permission ${permission}`)\n }\n\n /**\n * Verifies that a permission item's nsid is under the same authority as the\n * nsid of the lexicon itself (which is the same as the nsid of the `include:`\n * scope).\n */\n public isParentAuthorityOf(otherNsid: '*' | Nsid) {\n if (otherNsid === '*') {\n return false\n }\n\n const lexiconNsid = this.nsid\n\n const groupPrefixEnd = lexiconNsid.lastIndexOf('.')\n\n // There should always be a dot, but since this is a security feature, let's\n // be strict about it.\n if (groupPrefixEnd === -1) {\n throw new TypeError('Dot character (\".\") missing from lexicon NSID')\n }\n\n // Make sure that otherNsid is at least as long as the \"group prefix\"\n if (groupPrefixEnd >= otherNsid.length - 1) {\n return false\n }\n\n // Make sure that the \"otherNsid\" starts with the group of the lexiconNsid,\n // up to the dot itself. We check in reverse order as nsids tend to have\n // long common prefixes.\n for (let i = groupPrefixEnd; i >= 0; i--) {\n if (lexiconNsid.charCodeAt(i) !== otherNsid.charCodeAt(i)) {\n return false\n }\n }\n\n return true\n }\n\n protected static readonly parser = new Parser(\n 'include',\n {\n nsid: {\n multiple: false,\n required: true,\n validate: isNsid,\n },\n aud: {\n multiple: false,\n required: false,\n validate: isAtprotoDidRefAbsolute,\n },\n },\n 'nsid',\n )\n\n static fromString(scope: string) {\n if (!isScopeStringFor(scope, 'include')) return null\n const syntax = ScopeStringSyntax.fromString(scope)\n return IncludeScope.fromSyntax(syntax)\n }\n\n static fromSyntax(syntax: ScopeSyntax<'include'>) {\n const result = IncludeScope.parser.parse(syntax)\n if (!result) return null\n return new IncludeScope(result.nsid, result.aud)\n }\n}\n\nfunction toResourcePermission(\n syntax: ScopeSyntax<'repo' | 'rpc'>,\n): RepoPermission | RpcPermission | null {\n if (isScopeSyntaxFor(syntax, 'repo')) {\n return RepoPermission.fromSyntax(syntax)\n }\n if (isScopeSyntaxFor(syntax, 'rpc')) {\n return RpcPermission.fromSyntax(syntax)\n }\n return null\n}\n\nfunction isLexPermissionForResource<\n P extends { resource: unknown },\n T extends string,\n>(permission: P, type: T): permission is P & { resource: T } {\n return permission.resource === type\n}\n"]}
@@ -1,21 +1,21 @@
1
- import { AtprotoAudience, isAtprotoAudience } from '@atproto/did';
1
+ import { AtprotoDidRefAbsolute, isAtprotoDidRefAbsolute } from '@atproto/did';
2
2
  import { Nsid, isNsid } from '../lib/nsid.js';
3
3
  import { Parser } from '../lib/parser.js';
4
4
  import { ResourcePermission } from '../lib/resource-permission.js';
5
5
  import { NeRoArray, ScopeSyntax } from '../lib/syntax.js';
6
- export { type AtprotoAudience, type Nsid, isAtprotoAudience, isNsid };
6
+ export { type AtprotoDidRefAbsolute, type Nsid, isAtprotoDidRefAbsolute, isNsid, };
7
7
  export type LxmParam = '*' | Nsid;
8
8
  export declare const isLxmParam: (value: unknown) => value is LxmParam;
9
- export type AudParam = '*' | AtprotoAudience;
9
+ export type AudParam = '*' | AtprotoDidRefAbsolute;
10
10
  export declare const isAudParam: (value: unknown) => value is AudParam;
11
11
  export type RpcPermissionMatch = {
12
12
  lxm: string;
13
13
  aud: string;
14
14
  };
15
15
  export declare class RpcPermission implements ResourcePermission<'rpc', RpcPermissionMatch> {
16
- readonly aud: '*' | AtprotoAudience;
17
- readonly lxm: NeRoArray<'*' | Nsid>;
18
- constructor(aud: '*' | AtprotoAudience, lxm: NeRoArray<'*' | Nsid>);
16
+ readonly aud: AudParam;
17
+ readonly lxm: NeRoArray<LxmParam>;
18
+ constructor(aud: AudParam, lxm: NeRoArray<LxmParam>);
19
19
  matches(options: RpcPermissionMatch): boolean;
20
20
  toString(): import("../lib/syntax.js").ScopeStringFor<"rpc">;
21
21
  protected static readonly parser: Parser<"rpc", {
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-permission.d.ts","sourceRoot":"","sources":["../../src/scopes/rpc-permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AAElE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAoB,MAAM,kBAAkB,CAAA;AAE3E,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAA;AAErE,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAA;AACjC,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,QACrB,CAAA;AAChC,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,eAAe,CAAA;AAC5C,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,QACV,CAAA;AAE3C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,qBAAa,aACX,YAAW,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,CAAC;aAGtC,GAAG,EAAE,GAAG,GAAG,eAAe;aAC1B,GAAG,EAAE,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC;gBAD1B,GAAG,EAAE,GAAG,GAAG,eAAe,EAC1B,GAAG,EAAE,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC;IAG5C,OAAO,CAAC,OAAO,EAAE,kBAAkB;IAQnC,QAAQ;IAIR,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;8BA/BA,OAAO,KAAG,KAAK,IAAI,QAAQ;;;;;;8BAG3B,OAAO,KAAG,KAAK,IAAI,QAAQ;;OA+C1D;IAED,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAMtD,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,aAAa,GAAG,IAAI;IAUnE,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM;CAM3D"}
1
+ {"version":3,"file":"rpc-permission.d.ts","sourceRoot":"","sources":["../../src/scopes/rpc-permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AAElE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAoB,MAAM,kBAAkB,CAAA;AAE3E,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,IAAI,EACT,uBAAuB,EACvB,MAAM,GACP,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAA;AACjC,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,QACrB,CAAA;AAChC,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,qBAAqB,CAAA;AAClD,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,QACJ,CAAA;AAEjD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,qBAAa,aACX,YAAW,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,CAAC;aAGtC,GAAG,EAAE,QAAQ;aACb,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC;gBADxB,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC;IAG1C,OAAO,CAAC,OAAO,EAAE,kBAAkB;IAQnC,QAAQ;IAIR,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;8BA/BA,OAAO,KAAG,KAAK,IAAI,QAAQ;;;;;;8BAG3B,OAAO,KAAG,KAAK,IAAI,QAAQ;;OA+C1D;IAED,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAMtD,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,aAAa,GAAG,IAAI;IAUnE,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM;CAM3D"}
@@ -1,11 +1,11 @@
1
- import { isAtprotoAudience } from '@atproto/did';
1
+ import { isAtprotoDidRefAbsolute } from '@atproto/did';
2
2
  import { isNsid } from '../lib/nsid.js';
3
3
  import { Parser } from '../lib/parser.js';
4
4
  import { ScopeStringSyntax } from '../lib/syntax-string.js';
5
5
  import { isScopeStringFor } from '../lib/syntax.js';
6
- export { isAtprotoAudience, isNsid };
6
+ export { isAtprotoDidRefAbsolute, isNsid, };
7
7
  export const isLxmParam = (value) => value === '*' || isNsid(value);
8
- export const isAudParam = (value) => value === '*' || isAtprotoAudience(value);
8
+ export const isAudParam = (value) => value === '*' || isAtprotoDidRefAbsolute(value);
9
9
  export class RpcPermission {
10
10
  constructor(aud, lxm) {
11
11
  this.aud = aud;
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-permission.js","sourceRoot":"","sources":["../../src/scopes/rpc-permission.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtprotoAudience, isAtprotoAudience } from '@atproto/did'\nimport { Nsid, isNsid } from '../lib/nsid.js'\nimport { Parser } from '../lib/parser.js'\nimport { ResourcePermission } from '../lib/resource-permission.js'\nimport { ScopeStringSyntax } from '../lib/syntax-string.js'\nimport { NeRoArray, ScopeSyntax, isScopeStringFor } from '../lib/syntax.js'\n\nexport { type AtprotoAudience, type Nsid, isAtprotoAudience, isNsid }\n\nexport type LxmParam = '*' | Nsid\nexport const isLxmParam = (value: unknown): value is LxmParam =>\n value === '*' || isNsid(value)\nexport type AudParam = '*' | AtprotoAudience\nexport const isAudParam = (value: unknown): value is AudParam =>\n value === '*' || isAtprotoAudience(value)\n\nexport type RpcPermissionMatch = {\n lxm: string\n aud: string\n}\n\nexport class RpcPermission\n implements ResourcePermission<'rpc', RpcPermissionMatch>\n{\n constructor(\n public readonly aud: '*' | AtprotoAudience,\n public readonly lxm: NeRoArray<'*' | Nsid>,\n ) {}\n\n matches(options: RpcPermissionMatch) {\n const { aud, lxm } = this\n return (\n (aud === '*' || aud === options.aud) &&\n (lxm.includes('*') || (lxm as readonly string[]).includes(options.lxm))\n )\n }\n\n toString() {\n return RpcPermission.parser.format(this)\n }\n\n protected static readonly parser = new Parser(\n 'rpc',\n {\n lxm: {\n multiple: true,\n required: true,\n validate: isLxmParam,\n normalize: (value) =>\n value.length > 1 && value.includes('*')\n ? (['*'] as const)\n : ([...new Set(value)].sort() as [Nsid, ...Nsid[]]),\n },\n aud: {\n multiple: false,\n required: true,\n validate: isAudParam,\n },\n },\n 'lxm',\n )\n\n static fromString(scope: string): RpcPermission | null {\n if (!isScopeStringFor(scope, 'rpc')) return null\n const syntax = ScopeStringSyntax.fromString(scope)\n return RpcPermission.fromSyntax(syntax)\n }\n\n static fromSyntax(syntax: ScopeSyntax<'rpc'>): RpcPermission | null {\n const result = RpcPermission.parser.parse(syntax)\n if (!result) return null\n\n // rpc:*?aud=* is forbidden\n if (result.aud === '*' && result.lxm.includes('*')) return null\n\n return new RpcPermission(result.aud, result.lxm)\n }\n\n static scopeNeededFor(options: RpcPermissionMatch): string {\n return RpcPermission.parser.format({\n aud: options.aud as AtprotoAudience,\n lxm: [options.lxm as Nsid],\n })\n }\n}\n"]}
1
+ {"version":3,"file":"rpc-permission.js","sourceRoot":"","sources":["../../src/scopes/rpc-permission.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtprotoDidRefAbsolute, isAtprotoDidRefAbsolute } from '@atproto/did'\nimport { Nsid, isNsid } from '../lib/nsid.js'\nimport { Parser } from '../lib/parser.js'\nimport { ResourcePermission } from '../lib/resource-permission.js'\nimport { ScopeStringSyntax } from '../lib/syntax-string.js'\nimport { NeRoArray, ScopeSyntax, isScopeStringFor } from '../lib/syntax.js'\n\nexport {\n type AtprotoDidRefAbsolute,\n type Nsid,\n isAtprotoDidRefAbsolute,\n isNsid,\n}\n\nexport type LxmParam = '*' | Nsid\nexport const isLxmParam = (value: unknown): value is LxmParam =>\n value === '*' || isNsid(value)\nexport type AudParam = '*' | AtprotoDidRefAbsolute\nexport const isAudParam = (value: unknown): value is AudParam =>\n value === '*' || isAtprotoDidRefAbsolute(value)\n\nexport type RpcPermissionMatch = {\n lxm: string\n aud: string\n}\n\nexport class RpcPermission\n implements ResourcePermission<'rpc', RpcPermissionMatch>\n{\n constructor(\n public readonly aud: AudParam,\n public readonly lxm: NeRoArray<LxmParam>,\n ) {}\n\n matches(options: RpcPermissionMatch) {\n const { aud, lxm } = this\n return (\n (aud === '*' || aud === options.aud) &&\n (lxm.includes('*') || (lxm as readonly string[]).includes(options.lxm))\n )\n }\n\n toString() {\n return RpcPermission.parser.format(this)\n }\n\n protected static readonly parser = new Parser(\n 'rpc',\n {\n lxm: {\n multiple: true,\n required: true,\n validate: isLxmParam,\n normalize: (value) =>\n value.length > 1 && value.includes('*')\n ? (['*'] as const)\n : ([...new Set(value)].sort() as [Nsid, ...Nsid[]]),\n },\n aud: {\n multiple: false,\n required: true,\n validate: isAudParam,\n },\n },\n 'lxm',\n )\n\n static fromString(scope: string): RpcPermission | null {\n if (!isScopeStringFor(scope, 'rpc')) return null\n const syntax = ScopeStringSyntax.fromString(scope)\n return RpcPermission.fromSyntax(syntax)\n }\n\n static fromSyntax(syntax: ScopeSyntax<'rpc'>): RpcPermission | null {\n const result = RpcPermission.parser.parse(syntax)\n if (!result) return null\n\n // rpc:*?aud=* is forbidden\n if (result.aud === '*' && result.lxm.includes('*')) return null\n\n return new RpcPermission(result.aud, result.lxm)\n }\n\n static scopeNeededFor(options: RpcPermissionMatch): string {\n return RpcPermission.parser.format({\n aud: options.aud as AtprotoDidRefAbsolute,\n lxm: [options.lxm as Nsid],\n })\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/oauth-scopes",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },
@@ -26,8 +26,8 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
- "@atproto/did": "^0.4.0",
30
- "@atproto/syntax": "^0.6.0"
29
+ "@atproto/did": "^0.5.0",
30
+ "@atproto/syntax": "^0.6.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "jest": "^30.0.0",
@@ -264,4 +264,40 @@ describe('ScopePermissions', () => {
264
264
  ).toBe(false)
265
265
  })
266
266
  })
267
+
268
+ describe('assertRpc combined-aud', () => {
269
+ it('allows did#serviceId aud when scope grants the same combined form', () => {
270
+ const set = new ScopePermissions(
271
+ 'rpc:app.bsky.feed.getFeed?aud=did:web:example.com%23bsky_appview',
272
+ )
273
+ expect(() =>
274
+ set.assertRpc({
275
+ aud: 'did:web:example.com#bsky_appview',
276
+ lxm: 'app.bsky.feed.getFeed',
277
+ }),
278
+ ).not.toThrow()
279
+ })
280
+
281
+ it('rejects bare-DID aud when scope grants a combined form', () => {
282
+ const set = new ScopePermissions(
283
+ 'rpc:app.bsky.feed.getFeed?aud=did:web:example.com%23bsky_appview',
284
+ )
285
+ expect(() =>
286
+ set.assertRpc({
287
+ aud: 'did:web:example.com',
288
+ lxm: 'app.bsky.feed.getFeed',
289
+ }),
290
+ ).toThrow()
291
+ })
292
+
293
+ it('allows wildcard aud against a combined-form match', () => {
294
+ const set = new ScopePermissions('rpc:app.bsky.feed.getFeed?aud=*')
295
+ expect(() =>
296
+ set.assertRpc({
297
+ aud: 'did:web:example.com#bsky_appview',
298
+ lxm: 'app.bsky.feed.getFeed',
299
+ }),
300
+ ).not.toThrow()
301
+ })
302
+ })
267
303
  })
@@ -1,4 +1,3 @@
1
- import { AtprotoAudience, isAtprotoAudience } from '@atproto/did'
2
1
  import { LexiconPermission, LexiconPermissionSet } from '../lib/lexicon.js'
3
2
  import { Nsid, isNsid } from '../lib/nsid.js'
4
3
  import { Parser } from '../lib/parser.js'
@@ -11,7 +10,11 @@ import {
11
10
  isScopeSyntaxFor,
12
11
  } from '../lib/syntax.js'
13
12
  import { RepoPermission } from './repo-permission.js'
14
- import { RpcPermission } from './rpc-permission.js'
13
+ import {
14
+ AtprotoDidRefAbsolute,
15
+ RpcPermission,
16
+ isAtprotoDidRefAbsolute,
17
+ } from './rpc-permission.js'
15
18
 
16
19
  export { type LexiconPermission, type LexiconPermissionSet, type Nsid, isNsid }
17
20
 
@@ -23,7 +26,7 @@ export { type LexiconPermission, type LexiconPermissionSet, type Nsid, isNsid }
23
26
  export class IncludeScope {
24
27
  constructor(
25
28
  public readonly nsid: Nsid,
26
- public readonly aud: undefined | AtprotoAudience = undefined,
29
+ public readonly aud: undefined | AtprotoDidRefAbsolute = undefined,
27
30
  ) {}
28
31
 
29
32
  toString() {
@@ -166,7 +169,7 @@ export class IncludeScope {
166
169
  aud: {
167
170
  multiple: false,
168
171
  required: false,
169
- validate: isAtprotoAudience,
172
+ validate: isAtprotoDidRefAbsolute,
170
173
  },
171
174
  },
172
175
  'nsid',
@@ -1,18 +1,23 @@
1
- import { AtprotoAudience, isAtprotoAudience } from '@atproto/did'
1
+ import { AtprotoDidRefAbsolute, isAtprotoDidRefAbsolute } from '@atproto/did'
2
2
  import { Nsid, isNsid } from '../lib/nsid.js'
3
3
  import { Parser } from '../lib/parser.js'
4
4
  import { ResourcePermission } from '../lib/resource-permission.js'
5
5
  import { ScopeStringSyntax } from '../lib/syntax-string.js'
6
6
  import { NeRoArray, ScopeSyntax, isScopeStringFor } from '../lib/syntax.js'
7
7
 
8
- export { type AtprotoAudience, type Nsid, isAtprotoAudience, isNsid }
8
+ export {
9
+ type AtprotoDidRefAbsolute,
10
+ type Nsid,
11
+ isAtprotoDidRefAbsolute,
12
+ isNsid,
13
+ }
9
14
 
10
15
  export type LxmParam = '*' | Nsid
11
16
  export const isLxmParam = (value: unknown): value is LxmParam =>
12
17
  value === '*' || isNsid(value)
13
- export type AudParam = '*' | AtprotoAudience
18
+ export type AudParam = '*' | AtprotoDidRefAbsolute
14
19
  export const isAudParam = (value: unknown): value is AudParam =>
15
- value === '*' || isAtprotoAudience(value)
20
+ value === '*' || isAtprotoDidRefAbsolute(value)
16
21
 
17
22
  export type RpcPermissionMatch = {
18
23
  lxm: string
@@ -23,8 +28,8 @@ export class RpcPermission
23
28
  implements ResourcePermission<'rpc', RpcPermissionMatch>
24
29
  {
25
30
  constructor(
26
- public readonly aud: '*' | AtprotoAudience,
27
- public readonly lxm: NeRoArray<'*' | Nsid>,
31
+ public readonly aud: AudParam,
32
+ public readonly lxm: NeRoArray<LxmParam>,
28
33
  ) {}
29
34
 
30
35
  matches(options: RpcPermissionMatch) {
@@ -78,7 +83,7 @@ export class RpcPermission
78
83
 
79
84
  static scopeNeededFor(options: RpcPermissionMatch): string {
80
85
  return RpcPermission.parser.format({
81
- aud: options.aud as AtprotoAudience,
86
+ aud: options.aud as AtprotoDidRefAbsolute,
82
87
  lxm: [options.lxm as Nsid],
83
88
  })
84
89
  }