@ucanto/validator
Advanced tools
Comparing version 6.1.0 to 7.0.0
@@ -21,3 +21,3 @@ export function capability<A extends API.Ability, R extends API.URI<`${string}:`>, C extends API.Caveats = {}>({ derives, nb, ...etc }: Descriptor<A, R, C>): API.TheCapabilityParser<API.CapabilityMatch<A, R, C>>; | ||
nb: C; | ||
}) => API.Result<true, API.Failure>) | undefined; | ||
}) => API.Result<{}, API.Failure>) | undefined; | ||
}; | ||
@@ -58,6 +58,5 @@ import * as API from "@ucanto/interface"; | ||
} | ||
import { Failure } from "./error.js"; | ||
import * as Schema from "./schema.js"; | ||
import { Schema } from "@ucanto/core"; | ||
import { DelegationError as MatchError } from "./error.js"; | ||
export {}; | ||
//# sourceMappingURL=capability.d.ts.map |
@@ -1,16 +0,1 @@ | ||
/** | ||
* @implements {API.Failure} | ||
*/ | ||
export class Failure extends Error implements API.Failure { | ||
/** @type {true} */ | ||
get error(): true; | ||
describe(): string; | ||
get message(): string; | ||
toJSON(): { | ||
error: true; | ||
name: string; | ||
message: string; | ||
stack: string | undefined; | ||
}; | ||
} | ||
export class EscalatedCapability extends Failure { | ||
@@ -114,3 +99,2 @@ /** | ||
toJSON(): { | ||
error: true; | ||
name: "InvalidAudience"; | ||
@@ -159,3 +143,2 @@ audience: `did:${string}:${string}`; | ||
toJSON(): { | ||
error: true; | ||
name: "Expired"; | ||
@@ -180,3 +163,2 @@ message: string; | ||
toJSON(): { | ||
error: true; | ||
name: "NotValidBefore"; | ||
@@ -190,3 +172,6 @@ message: string; | ||
export function li(message: string): string; | ||
import { Failure } from "@ucanto/core/result"; | ||
import { fail } from "@ucanto/core/result"; | ||
import * as API from "@ucanto/interface"; | ||
export { Failure, fail }; | ||
//# sourceMappingURL=error.d.ts.map |
export { capability } from "./capability.js"; | ||
export * from "./schema.js"; | ||
export * from "@ucanto/core/schema"; | ||
export function access<A extends API.Ability, R extends API.URI<`${string}:`>, URI extends R, C extends API.Caveats>(invocation: API.Invocation<API.Capability<A, URI, C>>, { capability, ...config }: API.ValidationOptions<API.ParsedCapability<A, R, C>>): Promise<API.Result<Authorization<API.ParsedCapability<A, R, C>>, API.Unauthorized>>; | ||
export function claim<A extends API.Ability, R extends API.URI<`${string}:`>, C extends API.Caveats>(capability: API.CapabilityParser<API.Match<API.ParsedCapability<A, R, C>, API.UnknownMatch>>, proofs: API.Proof[], { authority, principal, resolveDIDKey, canIssue, resolve, }: API.ClaimOptions): Promise<API.Result<Authorization<API.ParsedCapability<A, R, C>>, API.Unauthorized>>; | ||
export function authorize<Match extends API.Match<any, API.UnknownMatch>>(match: Match, config: Required<API.ClaimOptions>): Promise<API.Result<Authorization<API.ParsedCapability>, API.InvalidClaim>>; | ||
import * as Schema from "@ucanto/core/schema"; | ||
import { Failure } from "./error.js"; | ||
import { fail } from "@ucanto/core/result.js"; | ||
import { ok } from "@ucanto/core/result.js"; | ||
import { UnavailableProof } from "./error.js"; | ||
import { MalformedCapability } from "./error.js"; | ||
import { DIDKeyResolutionError } from "./error.js"; | ||
import * as Schema from "./schema.js"; | ||
import * as API from "@ucanto/interface"; | ||
@@ -55,8 +57,2 @@ /** | ||
failedProofs: API.InvalidClaim[]; | ||
toJSON(): { | ||
error: true; | ||
name: "Unauthorized"; | ||
message: string; | ||
stack: string | undefined; | ||
}; | ||
} | ||
@@ -106,3 +102,3 @@ /** | ||
} | ||
export { Failure, UnavailableProof, MalformedCapability, DIDKeyResolutionError as DIDResolutionError, Schema }; | ||
export { Schema, Failure, fail, ok, UnavailableProof, MalformedCapability, DIDKeyResolutionError as DIDResolutionError }; | ||
//# sourceMappingURL=lib.d.ts.map |
{ | ||
"name": "@ucanto/validator", | ||
"description": "UCAN RPC validators", | ||
"version": "6.1.0", | ||
"version": "7.0.0", | ||
"keywords": [ | ||
@@ -25,4 +25,4 @@ "UCAN", | ||
"multiformats": "^11.0.0", | ||
"@ucanto/core": "^5.1.0", | ||
"@ucanto/interface": "^6.1.0" | ||
"@ucanto/core": "^7.0.0", | ||
"@ucanto/interface": "^7.0.0" | ||
}, | ||
@@ -40,4 +40,4 @@ "devDependencies": { | ||
"typescript": "^4.9.5", | ||
"@ucanto/client": "^5.1.0", | ||
"@ucanto/principal": "^5.1.0" | ||
"@ucanto/client": "^7.0.0", | ||
"@ucanto/principal": "^7.0.0" | ||
}, | ||
@@ -73,3 +73,3 @@ "type": "module", | ||
"test:node": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha test/**/*.spec.js", | ||
"test": "npm run test:node", | ||
"test": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha --bail test/**/*.spec.js", | ||
"coverage": "c8 --reporter=html mocha test/**/*.spec.js", | ||
@@ -76,0 +76,0 @@ "check": "tsc --build", |
@@ -8,6 +8,4 @@ import * as API from '@ucanto/interface' | ||
DelegationError as MatchError, | ||
Failure, | ||
} from './error.js' | ||
import { invoke, delegate } from '@ucanto/core' | ||
import * as Schema from './schema.js' | ||
import { invoke, delegate, Schema } from '@ucanto/core' | ||
@@ -22,3 +20,3 @@ /** | ||
* nb?: Schema.MapRepresentation<C, unknown> | ||
* derives?: (claim: {can:A, with: R, nb: C}, proof:{can:A, with:R, nb:C}) => API.Result<true, API.Failure> | ||
* derives?: (claim: {can:A, with: R, nb: C}, proof:{can:A, with:R, nb:C}) => API.Result<{}, API.Failure> | ||
* }} Descriptor | ||
@@ -84,3 +82,3 @@ */ | ||
match(source) { | ||
return new UnknownCapability(source.capability) | ||
return { error: new UnknownCapability(source.capability) } | ||
} | ||
@@ -90,2 +88,3 @@ | ||
* @param {API.Source[]} capabilities | ||
* @returns {API.Select<M>} | ||
*/ | ||
@@ -164,5 +163,8 @@ select(capabilities) { | ||
if (resource.error) { | ||
throw Object.assign(new Error(`Invalid 'with' - ${resource.message}`), { | ||
cause: resource, | ||
}) | ||
throw Object.assign( | ||
new Error(`Invalid 'with' - ${resource.error.message}`), | ||
{ | ||
cause: resource, | ||
} | ||
) | ||
} | ||
@@ -172,3 +174,3 @@ | ||
if (nb.error) { | ||
throw Object.assign(new Error(`Invalid 'nb' - ${nb.message}`), { | ||
throw Object.assign(new Error(`Invalid 'nb' - ${nb.error.message}`), { | ||
cause: nb, | ||
@@ -178,3 +180,3 @@ }) | ||
return createCapability({ can, with: resource, nb }) | ||
return createCapability({ can, with: resource.ok, nb: nb.ok }) | ||
} | ||
@@ -205,5 +207,8 @@ | ||
if (resource.error) { | ||
throw Object.assign(new Error(`Invalid 'with' - ${resource.message}`), { | ||
cause: resource, | ||
}) | ||
throw Object.assign( | ||
new Error(`Invalid 'with' - ${resource.error.message}`), | ||
{ | ||
cause: resource, | ||
} | ||
) | ||
} | ||
@@ -213,3 +218,3 @@ | ||
if (nb.error) { | ||
throw Object.assign(new Error(`Invalid 'nb' - ${nb.message}`), { | ||
throw Object.assign(new Error(`Invalid 'nb' - ${nb.error.message}`), { | ||
cause: nb, | ||
@@ -220,3 +225,3 @@ }) | ||
return delegate({ | ||
capabilities: [createCapability({ can, with: resource, nb })], | ||
capabilities: [createCapability({ can, with: resource.ok, nb: nb.ok })], | ||
...options, | ||
@@ -236,3 +241,5 @@ }) | ||
const result = parseCapability(this.descriptor, source) | ||
return result.error ? result : new Match(source, result, this.descriptor) | ||
return result.error | ||
? result | ||
: { ok: new Match(source, result.ok, this.descriptor) } | ||
} | ||
@@ -295,3 +302,3 @@ toString() { | ||
if (right.error) { | ||
return right.name === 'MalformedCapability' | ||
return right.error.name === 'MalformedCapability' | ||
? // | ||
@@ -338,7 +345,9 @@ right | ||
} else { | ||
group.push(result) | ||
group.push(result.ok) | ||
} | ||
} | ||
return new AndMatch(/** @type {API.InferMembers<Selectors>} */ (group)) | ||
return { | ||
ok: new AndMatch(/** @type {API.InferMembers<Selectors>} */ (group)), | ||
} | ||
} | ||
@@ -416,3 +425,3 @@ | ||
} else { | ||
return new DerivedMatch(match, this.from, this.derives) | ||
return { ok: new DerivedMatch(match.ok, this.from, this.derives) } | ||
} | ||
@@ -476,8 +485,8 @@ } | ||
const result = resolveCapability(this.descriptor, this.value, capability) | ||
if (!result.error) { | ||
const claim = this.descriptor.derives(this.value, result) | ||
if (result.ok) { | ||
const claim = this.descriptor.derives(this.value, result.ok) | ||
if (claim.error) { | ||
errors.push( | ||
new MatchError( | ||
[new EscalatedCapability(this.value, result, claim)], | ||
[new EscalatedCapability(this.value, result.ok, claim.error)], | ||
this | ||
@@ -487,12 +496,12 @@ ) | ||
} else { | ||
matches.push(new Match(capability, result, this.descriptor)) | ||
matches.push(new Match(capability, result.ok, this.descriptor)) | ||
} | ||
} else { | ||
switch (result.name) { | ||
switch (result.error.name) { | ||
case 'UnknownCapability': | ||
unknown.push(result.capability) | ||
unknown.push(result.error.capability) | ||
break | ||
case 'MalformedCapability': | ||
default: | ||
errors.push(new MatchError([result], this)) | ||
errors.push(new MatchError([result.error], this)) | ||
} | ||
@@ -577,3 +586,3 @@ } | ||
new MatchError( | ||
[new EscalatedCapability(value, match.value, result)], | ||
[new EscalatedCapability(value, match.value, result.error)], | ||
this | ||
@@ -758,3 +767,3 @@ ) | ||
if (descriptor.can !== capability.can) { | ||
return new UnknownCapability(capability) | ||
return { error: new UnknownCapability(capability) } | ||
} | ||
@@ -764,3 +773,3 @@ | ||
if (uri.error) { | ||
return new MalformedCapability(capability, uri) | ||
return { error: new MalformedCapability(capability, uri.error) } | ||
} | ||
@@ -770,6 +779,6 @@ | ||
if (nb.error) { | ||
return new MalformedCapability(capability, nb) | ||
return { error: new MalformedCapability(capability, nb.error) } | ||
} | ||
return new CapabilityView(descriptor.can, uri, nb, delegation) | ||
return { ok: new CapabilityView(descriptor.can, uri.ok, nb.ok, delegation) } | ||
} | ||
@@ -797,3 +806,3 @@ | ||
if (can == null) { | ||
return new UnknownCapability(capability) | ||
return { error: new UnknownCapability(capability) } | ||
} | ||
@@ -808,3 +817,3 @@ | ||
if (uri.error) { | ||
return new MalformedCapability(capability, uri) | ||
return { error: new MalformedCapability(capability, uri.error) } | ||
} | ||
@@ -818,6 +827,6 @@ | ||
if (nb.error) { | ||
return new MalformedCapability(capability, nb) | ||
return { error: new MalformedCapability(capability, nb.error) } | ||
} | ||
return new CapabilityView(can, uri, nb, delegation) | ||
return { ok: new CapabilityView(can, uri.ok, nb.ok, delegation) } | ||
} | ||
@@ -849,2 +858,3 @@ | ||
* @param {API.Source[]} capabilities | ||
* @returns {API.Select<M>} | ||
*/ | ||
@@ -859,12 +869,12 @@ | ||
if (result.error) { | ||
switch (result.name) { | ||
switch (result.error.name) { | ||
case 'UnknownCapability': | ||
unknown.push(result.capability) | ||
unknown.push(result.error.capability) | ||
break | ||
case 'MalformedCapability': | ||
default: | ||
errors.push(new MatchError([result], result.capability)) | ||
errors.push(new MatchError([result.error], result.error.capability)) | ||
} | ||
} else { | ||
matches.push(result) | ||
matches.push(result.ok) | ||
} | ||
@@ -920,3 +930,3 @@ } | ||
if (!claimed.with.startsWith(delegated.with.slice(0, -1))) { | ||
return new Failure( | ||
return Schema.error( | ||
`Resource ${claimed.with} does not match delegated ${delegated.with} ` | ||
@@ -926,3 +936,3 @@ ) | ||
} else if (delegated.with !== claimed.with) { | ||
return new Failure( | ||
return Schema.error( | ||
`Resource ${claimed.with} is not contained by ${delegated.with}` | ||
@@ -939,7 +949,7 @@ ) | ||
if (nb[name] != value) { | ||
return new Failure(`${String(name)}: ${nb[name]} violates ${value}`) | ||
return Schema.error(`${String(name)}: ${nb[name]} violates ${value}`) | ||
} | ||
} | ||
return true | ||
return { ok: true } | ||
} |
import * as API from '@ucanto/interface' | ||
import { the } from './util.js' | ||
import { isLink } from 'multiformats/link' | ||
import { isLink } from '@ucanto/core/link' | ||
import { fail, Failure } from '@ucanto/core/result' | ||
/** | ||
* @implements {API.Failure} | ||
*/ | ||
export class Failure extends Error { | ||
/** @type {true} */ | ||
get error() { | ||
return true | ||
} | ||
/* c8 ignore next 3 */ | ||
describe() { | ||
return this.name | ||
} | ||
get message() { | ||
return this.describe() | ||
} | ||
export { Failure, fail } | ||
toJSON() { | ||
const { error, name, message, stack } = this | ||
return { error, name, message, stack } | ||
} | ||
} | ||
export class EscalatedCapability extends Failure { | ||
@@ -203,5 +184,4 @@ /** | ||
toJSON() { | ||
const { error, name, audience, message, stack } = this | ||
const { name, audience, message, stack } = this | ||
return { | ||
error, | ||
name, | ||
@@ -273,5 +253,4 @@ audience: audience.did(), | ||
toJSON() { | ||
const { error, name, expiredAt, message, stack } = this | ||
const { name, expiredAt, message, stack } = this | ||
return { | ||
error, | ||
name, | ||
@@ -303,5 +282,4 @@ message, | ||
toJSON() { | ||
const { error, name, validAt, message, stack } = this | ||
const { name, validAt, message, stack } = this | ||
return { | ||
error, | ||
name, | ||
@@ -308,0 +286,0 @@ message, |
118
src/lib.js
import * as API from '@ucanto/interface' | ||
import { isDelegation, UCAN } from '@ucanto/core' | ||
import { isDelegation, UCAN, ok, fail } from '@ucanto/core' | ||
import { capability } from './capability.js' | ||
import * as Schema from './schema.js' | ||
import * as Schema from '@ucanto/core/schema' | ||
import { | ||
@@ -19,4 +19,10 @@ UnavailableProof, | ||
export { capability } from './capability.js' | ||
export * from '@ucanto/core/schema' | ||
export { | ||
Schema, | ||
Failure, | ||
fail, | ||
ok, | ||
UnavailableProof, | ||
@@ -27,10 +33,7 @@ MalformedCapability, | ||
export { capability } from './capability.js' | ||
export * from './schema.js' | ||
export { Schema } | ||
/** | ||
* @param {UCAN.Link} proof | ||
* @returns {{error:API.UnavailableProof}} | ||
*/ | ||
const unavailable = proof => new UnavailableProof(proof) | ||
const unavailable = proof => ({ error: new UnavailableProof(proof) }) | ||
@@ -40,5 +43,5 @@ /** | ||
* @param {UCAN.DID} did | ||
* @returns {API.DIDKeyResolutionError} | ||
* @returns {{error:API.DIDKeyResolutionError}} | ||
*/ | ||
const failDIDKeyResolution = did => new DIDKeyResolutionError(did) | ||
const failDIDKeyResolution = did => ({ error: new DIDKeyResolutionError(did) }) | ||
@@ -100,5 +103,5 @@ /** | ||
if (result.error) { | ||
errors.push(result) | ||
errors.push(result.error) | ||
} else { | ||
delegations.push(result) | ||
delegations.push(result.ok) | ||
} | ||
@@ -169,3 +172,3 @@ } catch (error) { | ||
if (validation.error) { | ||
errors.push(new ProofError(proof.cid, validation)) | ||
errors.push(new ProofError(proof.cid, validation.error)) | ||
} else { | ||
@@ -256,10 +259,9 @@ // otherwise create source objects for it's capabilities, so we could | ||
// otherwise collect the error. | ||
const delegation = await validate(proof, delegations, config) | ||
if (!delegation.error) { | ||
for (const [index, capability] of delegation.capabilities.entries()) { | ||
const validation = await validate(proof, delegations, config) | ||
if (validation.ok) { | ||
for (const capability of validation.ok.capabilities.values()) { | ||
sources.push( | ||
/** @type {API.Source} */ ({ | ||
capability, | ||
delegation, | ||
index, | ||
delegation: validation.ok, | ||
}) | ||
@@ -269,3 +271,3 @@ ) | ||
} else { | ||
invalidProofs.push(delegation) | ||
invalidProofs.push(validation.error) | ||
} | ||
@@ -281,9 +283,9 @@ } | ||
if (selector == null) { | ||
return new Authorization(matched, []) | ||
return { ok: new Authorization(matched, []) } | ||
} else { | ||
const result = await authorize(selector, config) | ||
if (result.error) { | ||
failedProofs.push(result) | ||
failedProofs.push(result.error) | ||
} else { | ||
return new Authorization(matched, [result]) | ||
return { ok: new Authorization(matched, [result.ok]) } | ||
} | ||
@@ -293,9 +295,11 @@ } | ||
return new Unauthorized({ | ||
capability, | ||
delegationErrors, | ||
unknownCapabilities, | ||
invalidProofs, | ||
failedProofs, | ||
}) | ||
return { | ||
error: new Unauthorized({ | ||
capability, | ||
delegationErrors, | ||
unknownCapabilities, | ||
invalidProofs, | ||
failedProofs, | ||
}), | ||
} | ||
} | ||
@@ -350,11 +354,11 @@ | ||
// group of capabilities but we can deal with that in the future. | ||
return new Authorization(matched, []) | ||
return { ok: new Authorization(matched, []) } | ||
} else { | ||
const result = await authorize(selector, config) | ||
if (result.error) { | ||
failedProofs.push(result) | ||
failedProofs.push(result.error) | ||
} else { | ||
// @ts-expect-error - it may not be a parsed capability but rather a | ||
// group of capabilities but we can deal with that in the future. | ||
return new Authorization(matched, [result]) | ||
return { ok: new Authorization(matched, [result.ok]) } | ||
} | ||
@@ -364,9 +368,11 @@ } | ||
return new InvalidClaim({ | ||
match, | ||
delegationErrors, | ||
unknownCapabilities, | ||
invalidProofs, | ||
failedProofs, | ||
}) | ||
return { | ||
error: new InvalidClaim({ | ||
match, | ||
delegationErrors, | ||
unknownCapabilities, | ||
invalidProofs, | ||
failedProofs, | ||
}), | ||
} | ||
} | ||
@@ -490,6 +496,2 @@ | ||
} | ||
toJSON() { | ||
const { error, name, message, stack } = this | ||
return { error, name, message, stack } | ||
} | ||
} | ||
@@ -509,11 +511,15 @@ | ||
if (UCAN.isExpired(delegation.data)) { | ||
return new Expired( | ||
/** @type {API.Delegation & {expiration: number}} */ (delegation) | ||
) | ||
return { | ||
error: new Expired( | ||
/** @type {API.Delegation & {expiration: number}} */ (delegation) | ||
), | ||
} | ||
} | ||
if (UCAN.isTooEarly(delegation.data)) { | ||
return new NotValidBefore( | ||
/** @type {API.Delegation & {notBefore: number}} */ (delegation) | ||
) | ||
return { | ||
error: new NotValidBefore( | ||
/** @type {API.Delegation & {notBefore: number}} */ (delegation) | ||
), | ||
} | ||
} | ||
@@ -552,6 +558,8 @@ | ||
// If we have valid session we consider authorization valid | ||
if (!session.error) { | ||
return delegation | ||
} else if (session.failedProofs.length > 0) { | ||
return new SessionEscalation({ delegation, cause: session }) | ||
if (session.ok) { | ||
return { ok: delegation } | ||
} else if (session.error.failedProofs.length > 0) { | ||
return { | ||
error: new SessionEscalation({ delegation, cause: session.error }), | ||
} | ||
} | ||
@@ -567,3 +575,3 @@ // Otherwise we try to resolve did:key from the DID instead | ||
delegation, | ||
config.principal.parse(verifier).withDID(issuer) | ||
config.principal.parse(verifier.ok).withDID(issuer) | ||
) | ||
@@ -583,3 +591,5 @@ } | ||
const valid = await UCAN.verifySignature(delegation.data, verifier) | ||
return valid ? delegation : new InvalidSignature(delegation, verifier) | ||
return valid | ||
? { ok: delegation } | ||
: { error: new InvalidSignature(delegation, verifier) } | ||
} | ||
@@ -586,0 +596,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
68295
13
2091
+ Added@ucanto/core@7.1.1(transitive)
+ Added@ucanto/interface@7.1.0(transitive)
- Removed@ucanto/core@5.2.0(transitive)
- Removed@ucanto/interface@6.2.0(transitive)
Updated@ucanto/core@^7.0.0
Updated@ucanto/interface@^7.0.0