@atproto/oauth-scopes
Version:
A library for manipulating and validating ATproto OAuth scopes in TypeScript.
97 lines • 3.17 kB
JavaScript
import { ScopeMissingError } from './scope-missing-error.js';
import { AccountPermission, } from './scopes/account-permission.js';
import { BlobPermission, } from './scopes/blob-permission.js';
import { IdentityPermission, } from './scopes/identity-permission.js';
import { RepoPermission, } from './scopes/repo-permission.js';
import { RpcPermission, } from './scopes/rpc-permission.js';
export { ScopeMissingError };
/**
* Utility class to manage a set of scopes and check if they match specific
* options for a given resource.
*/
export class ScopesSet extends Set {
/**
* Check if the container has a scope that matches the given options for a
* specific resource.
*/
matches(resource, options) {
for (const scope of this) {
if (permissionScopeMatches(scope, resource, options))
return true;
}
return false;
}
assert(resource, options) {
if (!this.matches(resource, options)) {
const scope = scopeNeededFor(resource, options);
throw new ScopeMissingError(scope);
}
}
some(fn) {
for (const scope of this)
if (fn(scope))
return true;
return false;
}
every(fn) {
for (const scope of this)
if (!fn(scope))
return false;
return true;
}
*filter(fn) {
for (const scope of this)
if (fn(scope))
yield scope;
}
*map(fn) {
for (const scope of this)
yield fn(scope);
}
static fromString(string) {
return new ScopesSet(string?.split(' '));
}
}
function scopeNeededFor(resource, options) {
switch (resource) {
case 'account':
return AccountPermission.scopeNeededFor(options);
case 'identity':
return IdentityPermission.scopeNeededFor(options);
case 'repo':
return RepoPermission.scopeNeededFor(options);
case 'rpc':
return RpcPermission.scopeNeededFor(options);
case 'blob':
return BlobPermission.scopeNeededFor(options);
}
// @ts-expect-error
throw new TypeError(`Unknown resource: ${resource}`);
}
function permissionScopeMatches(scope, resource, options) {
// @NOTE we might want to cache the parsed scopes though, in practice, a
// single scope is unlikely to be parsed multiple times during a single
// request.
const permission = parsePermissionScope(resource, scope);
if (!permission)
return false;
// @ts-expect-error
return permission.matches(options);
}
function parsePermissionScope(resource, scope) {
switch (resource) {
case 'account':
return AccountPermission.fromString(scope);
case 'identity':
return IdentityPermission.fromString(scope);
case 'repo':
return RepoPermission.fromString(scope);
case 'rpc':
return RpcPermission.fromString(scope);
case 'blob':
return BlobPermission.fromString(scope);
default:
return null;
}
}
//# sourceMappingURL=scopes-set.js.map