UNPKG

@eturino/claims

Version:

Claim, ClaimSet and Ability for permissions (Typescript port of https://github.com/eturino/claims)

1 lines 25.5 kB
{"version":3,"sources":["../src/lib/claims/ability.ts","../src/lib/claims/claim.ts","../src/lib/claims/rules.ts","../src/lib/claims/errors.ts","../src/lib/claims/claim-set.ts","../src/lib/claims/is-valid-claim-string.ts"],"sourcesContent":["import { type KeySet, all, some } from \"@eturino/key-set\";\nimport { type Claim, type IClaimData, extractVerbResource } from \"./claim\";\nimport { type ClaimSet, buildClaimSet } from \"./claim-set\";\n\nexport class Ability {\n constructor(\n public readonly permitted: ClaimSet,\n public readonly prohibited: ClaimSet,\n ) {}\n\n /**\n Returns a new ability with clones with the claim sets\n */\n public clone(): Ability {\n return new Ability(this.permitted.clone(), this.prohibited.clone());\n }\n\n /**\n * returns a string with the permitted and prohibited jsons inside, for caching purposes\n */\n get cacheID(): string {\n return `(${this.permitted.toJSONString()},${this.prohibited.toJSONString()})`;\n }\n\n /**\n * inverse of `can()`\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n *\n * @see can\n */\n public cannot(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): boolean {\n return !this.can(query);\n }\n\n /**\n * return true if permitted is true and prohibited is false\n * - permitted -> if the permitted ClaimSet returns true on `check()` for the given query\n * - prohibited -> if the prohibited ClaimSet returns true on `check()` for the given query\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see ClaimSet\n */\n public can(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): boolean {\n const parsedQuery = extractVerbResource(query);\n return this.permitted.check(parsedQuery) && !this.prohibited.check(parsedQuery);\n }\n\n /**\n * returns true if there is a prohibited claim that returns true on `check()`\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see ClaimSet\n * @see Claim\n */\n public isExplicitlyProhibited(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): boolean {\n return this.prohibited.check(query);\n }\n\n /**\n * returns a KeySet describing the access of this ability to the children of the given query:\n * allows on direct descendants, forbids on direct children\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n */\n accessToResources(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): KeySet<string> {\n const allowed = this.permitted.check(query) ? all<string>() : some(this.permitted.directDescendants(query));\n const forbidden = this.prohibited.check(query) ? all<string>() : some(this.prohibited.directChildren(query));\n\n return allowed.remove(forbidden);\n }\n}\n\n/**\n *\n * @param permittedStrings each element can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @param prohibitedStrings each element can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see buildClaimSet\n * @see Ability\n */\nexport function buildAbility(\n permittedStrings: readonly (string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>)[],\n prohibitedStrings: readonly (string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>)[],\n): Ability {\n const permitted = buildClaimSet(permittedStrings);\n const prohibited = buildClaimSet(prohibitedStrings);\n\n return new Ability(permitted, prohibited);\n}\n","import { isPlainObject, isString } from \"es-toolkit\";\nimport { InvalidPatternError, InvalidVerbError } from \"./errors\";\nimport { type AllowedVerb, isAllowedVerb } from \"./rules\";\n\nconst CLAIM_REGEX = /^([\\w_\\-]+):([\\w_.\\-]+\\w)(\\.\\*)?$/; // allows for the optional `.*` at the end, that will be ignored on the Claim creation\nconst GLOBAL_WILDCARD_CLAIM_REGEX = /^([\\w_\\-]+):\\*$/; // cater for `read:*` global claims\n// const QUERY_RESOURCE_REGEX = /^([\\w_.\\-]+\\w)(\\.\\*)?$/; // allows for the optional `.*` at the end, that will be ignored on the Claim creation\n\nexport interface IClaimData {\n verb: AllowedVerb;\n resource: string | null;\n}\n\nfunction extractFromString(s: string): IClaimData {\n const globalMatch = GLOBAL_WILDCARD_CLAIM_REGEX.exec(s);\n if (globalMatch) {\n const verb = globalMatch[1];\n if (!isAllowedVerb(verb)) {\n throw new InvalidVerbError(verb);\n }\n return { verb, resource: null };\n }\n\n const resourceMatch = CLAIM_REGEX.exec(s);\n if (resourceMatch) {\n const verb = resourceMatch[1];\n if (!isAllowedVerb(verb)) {\n throw new InvalidVerbError(verb);\n }\n\n const resource = resourceMatch[2];\n\n if (resource.includes(\"..\")) {\n throw new InvalidPatternError(s);\n }\n\n return { verb, resource };\n }\n\n throw new InvalidPatternError(s);\n}\n\nexport function extractVerbResource(\n stringOrData: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>,\n): IClaimData {\n if (stringOrData instanceof Claim) {\n return { verb: stringOrData.verb, resource: stringOrData.resource };\n }\n\n if (isString(stringOrData)) {\n return extractFromString(stringOrData);\n }\n\n if (isPlainObject(stringOrData) && \"verb\" in stringOrData) {\n return { verb: stringOrData.verb, resource: stringOrData.resource || null };\n }\n\n throw new Error(\n \"cannot recognise verb and resource, it is neither `verb:*` or `verb:some.resource` string or an object with `verb` and `resource`\",\n );\n}\n\nexport function partsFromResource(resource: string | null): string[] {\n if (!resource) return [];\n return resource.split(\".\");\n}\n\nexport class Claim {\n private get resourceParts(): string[] {\n if (!this._resourceParts) {\n this._resourceParts = partsFromResource(this.resource);\n }\n return this._resourceParts;\n }\n public readonly verb: AllowedVerb;\n public readonly resource: string | null;\n\n private _resourceParts: string[] | null = null;\n\n constructor({ verb, resource }: IClaimData | Readonly<IClaimData>) {\n if (!isAllowedVerb(verb)) {\n throw new InvalidVerbError(verb);\n }\n this.verb = verb;\n this.resource = resource;\n }\n\n /**\n * returns a new Claim with the same data\n */\n public clone(): Claim {\n return new Claim({ verb: this.verb, resource: this.resource });\n }\n\n /**\n * returns `verb:resource` (if global, it will return `verb:*`)\n */\n public toString(): string {\n return `${this.verb}:${this.resource || \"*\"}`;\n }\n\n /**\n * true if the given verb is the same as the claim's\n * @param verb\n */\n public hasVerb(verb: string): boolean {\n return this.verb === verb;\n }\n\n /**\n * true if the claim has no resource (global verb). This means that it represents all resources for this verb\n */\n public isGlobal(): boolean {\n return !this.resource;\n }\n\n /**\n * returns true if this claim includes the given query\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n */\n public check(query: string | IClaimData | Readonly<IClaimData> | Claim | Readonly<Claim>): boolean {\n const { verb, resource } = extractVerbResource(query);\n if (this.verb !== verb) return false;\n\n if (this.isGlobal()) return true;\n\n if (!resource) return false;\n\n if (resource === this.resource) return true;\n\n return resource.startsWith(`${this.resource}.`);\n }\n\n /**\n * returns true if this claim represents exactly the same as the given query\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n */\n public isExact(query: string | IClaimData | Readonly<IClaimData> | Claim | Readonly<Claim>): boolean {\n const { verb, resource } = extractVerbResource(query);\n if (this.verb !== verb) return false;\n if (!resource) return this.isGlobal();\n return resource === this.resource;\n }\n\n /**\n * given a query, if this claim is a direct child of that query, it will return the immediate child part. Otherwise it returns null\n *\n * e.g.\n * ```js\n * const claim = buildClaim(\"read:what.some.stuff\");\n * claim.directChild(\"admin:*\") // => null\n * claim.directChild(\"read:*\") // => null\n * claim.directChild(\"read:what\") // => null\n * claim.directChild(\"read:what.some\") // => \"stuff\"\n * claim.directChild(\"read:what.some.stuff\") // => null\n * claim.directChild(\"read:what.some.stuff.blah\") // => null\n * ```\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n */\n public directChild(query: string | IClaimData | Readonly<IClaimData> | Claim | Readonly<Claim>): string | null {\n const { verb, resource } = extractVerbResource(query);\n return this.lookupDirectChild(verb, resource);\n }\n\n /**\n * return true if directChild() does not return null\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see directChild\n */\n public isDirectChild(query: string | IClaimData | Readonly<IClaimData> | Claim | Readonly<Claim>): boolean {\n return !!this.directChild(query);\n }\n\n /**\n * given a query, if this claim is a direct descendant of that query, it will return the immediate child part. Otherwise it returns null\n *\n * e.g.\n * ```js\n * claim.directDescendant(\"admin:*\") // => null\n * claim.directDescendant(\"read:*\") // => \"what\"\n * claim.directDescendant(\"read:what\") // => \"some\"\n * claim.directDescendant(\"read:what.some\") // => \"stuff\"\n * claim.directDescendant(\"read:what.some.stuff\") // => null\n * claim.directDescendant(\"read:what.some.stuff.blah\") // => null\n * ```\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n */\n public directDescendant(query: string | IClaimData | Readonly<IClaimData> | Claim | Readonly<Claim>): string | null {\n const { verb, resource } = extractVerbResource(query);\n return this.lookupDirectDescendant(verb, resource);\n }\n\n /**\n * return true if isDirectDescendant() does not return null\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see isDirectDescendant\n */\n public isDirectDescendant(query: string | IClaimData | Readonly<IClaimData> | Claim | Readonly<Claim>): boolean {\n return !!this.directDescendant(query);\n }\n\n private lookupDirectChild(verb: string, resource: string | null): string | null {\n if (!this.resource || !this.hasVerb(verb)) return null;\n\n const resourceParts = partsFromResource(resource);\n if (this.resourceParts.length !== resourceParts.length + 1) return null;\n\n if (!resource) return this.resourceParts[0];\n\n if (!this.resource.startsWith(`${resource}.`)) return null;\n return `${this.resource}`.replace(`${resource}.`, \"\");\n }\n\n private lookupDirectDescendant(verb: string, resource: string | null): string | null {\n if (!this.resource || !this.hasVerb(verb)) return null;\n\n if (!resource) return this.resourceParts[0];\n\n if (!this.resource.startsWith(`${resource}.`)) return null;\n const index = partsFromResource(resource).length;\n return this.resourceParts[index];\n }\n}\n\n/**\n * creates a new `Claim` object with the info given\n *\n * it validates the verb is one of the valid verbs\n *\n * @param stringOrObject can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see ALLOWED_VERBS\n * @see Claim\n */\nexport function buildClaim(\n stringOrObject: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>,\n): Claim {\n return new Claim(extractVerbResource(stringOrObject));\n}\n","/**\n * allowed verbs for a Claim\n */\nexport const ALLOWED_VERBS = [\"admin\", \"read\", \"delete\", \"create\", \"update\", \"manage\"] as const;\n\n/**\n * allowed verbs for a Claim\n */\nexport type AllowedVerb = (typeof ALLOWED_VERBS)[number];\n\n/**\n * returns true if the given string is one of the allowed verbs\n * @param verb\n */\nexport function isAllowedVerb(verb: string): verb is AllowedVerb {\n return ALLOWED_VERBS.includes(verb as AllowedVerb);\n}\n","import { ALLOWED_VERBS } from \"./rules\";\n\n/**\n * Error thrown when a claim is not valid because the verb is not an allowed one.\n */\nexport class InvalidVerbError extends Error {\n constructor(readonly verb: string) {\n super(`the given verb '${verb}' is not one of the allowed verbs: ${JSON.stringify(ALLOWED_VERBS)}`);\n }\n}\n\n/**\n * Error thrown when a claim is not valid because the pattern cannot be parsed as a Claim.\n */\nexport class InvalidPatternError extends Error {\n constructor(readonly raw: string) {\n super(`the given raw string cannot be parsed as a claim ${JSON.stringify(raw)}`);\n }\n}\n\n/**\n * Error thrown when trying to alter a frozen claimSet.\n */\nexport class FrozenClaimSetError extends Error {}\n","import { compact, uniq } from \"es-toolkit\";\nimport { type Claim, type IClaimData, buildClaim, extractVerbResource } from \"./claim\";\nimport { FrozenClaimSetError } from \"./errors\";\n\nexport class ClaimSet {\n protected frozen: boolean;\n constructor(public readonly claims: Claim[]) {\n this.frozen = true;\n }\n\n protected _jsonString: string | null = null;\n /**\n * returns a string with the JSON representation of the claim set\n *\n * It is calculated only once and then memoized, but resets if the claimSet gets unfrozen\n */\n public toJSONString(): string {\n if (!this._jsonString) {\n this._jsonString = JSON.stringify(this.claims.map((x) => x.toString()));\n }\n\n return this._jsonString;\n }\n\n /**\n * returns a new ClaimSet with clones of the same claims\n */\n public clone(): ClaimSet {\n return new ClaimSet(this.claims.map((x) => x.clone()));\n }\n\n /**\n * disallow any changes to the claim set. Resets the JSON string\n */\n public freeze(): void {\n this._jsonString = null;\n this.frozen = true;\n }\n\n /**\n * allow changes to the claim set\n */\n public unfreeze(): void {\n this.frozen = false;\n }\n\n /**\n * returns True if the claim set does not allow any changes\n */\n public isFrozen(): boolean {\n return this.frozen;\n }\n\n /**\n * if the given claim is not `check` in the claim set already it will add it\n * @param claim\n */\n public addIfNotChecked(claim: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): void {\n if (this.frozen) {\n throw new FrozenClaimSetError(\"ClaimSet is frozen\");\n }\n if (!this.check(claim)) {\n this.claims.push(buildClaim(claim));\n this.claims.sort();\n }\n }\n\n /**\n * if the given claim is not `hasExact` in the claim set already it will add it\n * @param claim\n */\n public addIfNotExact(claim: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): void {\n if (this.frozen) {\n throw new FrozenClaimSetError(\"ClaimSet is frozen\");\n }\n if (!this.hasExact(claim)) {\n this.claims.push(buildClaim(claim));\n this.claims.sort();\n }\n }\n\n /**\n * returns true if any of the claims of the set returns true for the `check()` of the given query\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see Claim\n */\n public check(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): boolean {\n const parsedQuery = extractVerbResource(query);\n return this.claims.some((claim: Claim) => claim.check(parsedQuery));\n }\n\n /**\n * returns true if any of the claims of the set returns true for the `hasExact()` of the given query\n *\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see Claim\n */\n public hasExact(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): boolean {\n const parsedQuery = extractVerbResource(query);\n return this.claims.some((claim: Claim) => claim.isExact(parsedQuery));\n }\n\n /**\n * collects from the claims of the set the result of `directChild()`\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see Claim\n */\n public directChildren(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): string[] {\n return this.mapInClaims(query, (claim, parsedQuery) => claim.directChild(parsedQuery));\n }\n\n /**\n * collects from the claims of the set the result of `directDescendant()`\n * @param query can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see Claim\n */\n public directDescendants(query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>): string[] {\n return this.mapInClaims(query, (claim, parsedQuery) => claim.directDescendant(parsedQuery));\n }\n\n private mapInClaims(\n query: string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>,\n fn: (claim: Claim | Readonly<Claim>, parsedQuery: IClaimData | Readonly<IClaimData>) => string | null,\n ): string[] {\n const parsedQuery = extractVerbResource(query);\n const list = this.claims.map((claim) => fn(claim, parsedQuery));\n return uniq(compact(list)).sort();\n }\n}\n\n/**\n * creates a new ClaimSet by calling `buildClaim()` on each element of the given list and assign that to a new `ClaimSet`\n * @param list each element can be a string (\"verb:resource\" or \"verb:*\") or an object with `verb` and `resource`\n * @see buildClaim\n * @see ClaimSet\n */\nexport function buildClaimSet(\n list: readonly (string | IClaimData | Claim | Readonly<IClaimData> | Readonly<Claim>)[],\n): ClaimSet {\n const claims = list.map((s) => buildClaim(s)).sort();\n\n return new ClaimSet(claims);\n}\n","import { extractVerbResource } from \"./claim\";\n\n/**\n * tries to parse the given string into a claim, and returns true if it is valid, false otherwise\n * @param str the given string to check\n */\nexport function isValidClaimString(str: string): boolean {\n try {\n extractVerbResource(str);\n return true;\n } catch (e) {\n return false;\n }\n}\n"],"mappings":"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","names":[]}