Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: update session API #227

Merged
merged 12 commits into from
Feb 28, 2023
2 changes: 1 addition & 1 deletion packages/client/test/fixtures.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as ed25519 from '@ucanto/principal/ed25519'

/** did:key:z6Mkqa4oY9Z5Pf5tUcjLHLUsDjKwMC95HGXdE1j22jkbhz6r */
/** did:key:z6Mkk89bC3JrVqKie71YEcc5M1SMVxuCgNx6zLZ8SYJsxALi */
export const alice = ed25519.parse(
'MgCZT5vOnYZoVAeyjnzuJIVY9J4LNtJ+f8Js0cTPuKUpFne0BVEDJjEu6quFIU8yp91/TY/+MYK8GvlKoTDnqOCovCVM='
)
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/delegation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import * as UCAN from '@ipld/dag-ucan'
import * as Signature from '@ipld/dag-ucan/signature'
import { from as toPrincipal } from '@ipld/dag-ucan/did'
import * as API from '@ucanto/interface'
import * as Link from './link.js'
import * as CBOR from '@ipld/dag-cbor'
import { sha256 } from 'multiformats/hashes/sha2'

/**
* @deprecated
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/fixtures.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as ed25519 from '@ucanto/principal/ed25519'

/** did:key:z6Mkqa4oY9Z5Pf5tUcjLHLUsDjKwMC95HGXdE1j22jkbhz6r */
/** did:key:z6Mkk89bC3JrVqKie71YEcc5M1SMVxuCgNx6zLZ8SYJsxALi */
export const alice = ed25519.parse(
'MgCZT5vOnYZoVAeyjnzuJIVY9J4LNtJ+f8Js0cTPuKUpFne0BVEDJjEu6quFIU8yp91/TY/+MYK8GvlKoTDnqOCovCVM='
)
Expand Down
14 changes: 10 additions & 4 deletions packages/interface/src/capability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
export interface Source {
capability: { can: Ability; with: URI; nb?: Caveats }
delegation: Delegation
index: number
}

export interface Match<T = unknown, M extends Match = UnknownMatch>
Expand Down Expand Up @@ -207,13 +206,13 @@ export type InferCreateOptions<R extends Resource, C extends {} | undefined> =
export type InferInvokeOptions<
R extends Resource,
C extends {} | undefined
> = UCANOptions & { issuer: Signer } & InferCreateOptions<R, C>
> = UCANOptions & { issuer: UCAN.Signer } & InferCreateOptions<R, C>

export type InferDelegationOptions<
R extends Resource,
C extends {} | undefined
> = UCANOptions & {
issuer: Signer
issuer: UCAN.Signer
with: R
nb?: Partial<InferCreateOptions<R, C>['nb']>
}
Expand Down Expand Up @@ -414,7 +413,7 @@ export interface DIDKeyResolutionError extends Failure {
readonly name: 'DIDKeyResolutionError'
readonly did: UCAN.DID

readonly cause?: Unauthorized
readonly cause?: Failure
}

export interface Expired extends Failure {
Expand All @@ -436,6 +435,12 @@ export interface InvalidSignature extends Failure {
readonly delegation: Delegation
}

export interface SessionEscalation extends Failure {
Gozala marked this conversation as resolved.
Show resolved Hide resolved
readonly name: 'SessionEscalation'
readonly delegation: Delegation
readonly cause: Failure
}

/**
* Error produces by invalid proof
*/
Expand All @@ -444,6 +449,7 @@ export type InvalidProof =
| NotValidBefore
| InvalidSignature
| InvalidAudience
| SessionEscalation
| DIDKeyResolutionError
| UnavailableProof

Expand Down
4 changes: 2 additions & 2 deletions packages/interface/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export interface DelegationOptions<C extends Capabilities> extends UCANOptions {
* the `audience` {@link Principal}.
*
*/
issuer: Signer
issuer: UCAN.Signer

/**
* The `audience` for a {@link Delegation} is the party being delegated to, or the
Expand Down Expand Up @@ -224,7 +224,7 @@ export interface Invocation<C extends Capability = Capability>
export interface InvocationOptions<C extends Capability = Capability>
extends UCANOptions {
/** The `issuer` of an invocation is the "caller" of the RPC method and the party that signs the invocation UCAN token. */
issuer: Signer
issuer: UCAN.Signer

/** The {@link Capability} that is being invoked. */
capability: C
Expand Down
7 changes: 7 additions & 0 deletions packages/principal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
],
"rsa": [
"dist/src/rsa.d.ts"
],
"account": [
"dist/src/account.d.ts"
]
}
},
Expand All @@ -71,6 +74,10 @@
"./rsa": {
"types": "./dist/src/rsa.d.ts",
"import": "./src/rsa.js"
},
"./account": {
"types": "./dist/src/account.d.ts",
"import": "./src/account.js"
}
},
"c8": {
Expand Down
41 changes: 41 additions & 0 deletions packages/principal/src/absentee.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as Signature from '@ipld/dag-ucan/signature'
import * as UCAN from '@ipld/dag-ucan'

/**
* @template {UCAN.DID} ID
* @param {{id: ID }} id
* @returns {UCAN.Signer<ID, Signature.NON_STANDARD>}
*/
export const from = ({ id }) => new Absentee(id)

/**
* An absentee is a special type of signer that produces an absent signature,
* which signals that verifier needs to verify authorization interactively.
*
* @template {UCAN.DID} ID
* @implements {UCAN.Signer<ID, Signature.NON_STANDARD>}
*/
class Absentee {
/**
* @param {ID} id
*/
constructor(id) {
this.id = id
}
did() {
return this.id
}
/* c8 ignore next 3 */
get signatureCode() {
return Signature.NON_STANDARD
}
get signatureAlgorithm() {
return ''
}
sign() {
return Signature.createNonStandard(
this.signatureAlgorithm,
new Uint8Array(0)
)
}
}
1 change: 0 additions & 1 deletion packages/principal/src/ed25519/signer.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export const from = ({ id, keys }) => {
throw new TypeError(`Unsupported archive format`)
}

from
/**
* @template {API.SignerImporter} O
* @param {O} other
Expand Down
3 changes: 2 additions & 1 deletion packages/principal/src/lib.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as ed25519 from './ed25519.js'
import * as RSA from './rsa.js'
import * as Absentee from './absentee.js'

export const Verifier = ed25519.Verifier.or(RSA.Verifier)
export const Signer = ed25519.or(RSA)

export { ed25519, RSA }
export { ed25519, RSA, Absentee }
17 changes: 17 additions & 0 deletions packages/principal/test/absentee.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Absentee } from '../src/lib.js'
import { assert } from 'chai'

export const utf8 = new TextEncoder()
describe('Absentee', async () => {
it('it can sign', async () => {
const absentee = Absentee.from({ id: 'did:mailto:web.mail:alice' })
assert.deepEqual(absentee.did(), 'did:mailto:web.mail:alice')
assert.deepEqual(absentee.signatureAlgorithm, '')
assert.deepEqual(absentee.signatureCode, 0xd000)

const signature = await absentee.sign(utf8.encode('hello world'))
assert.deepEqual(signature.code, 0xd000)
assert.deepEqual(signature.algorithm, '')
assert.deepEqual(signature.raw, new Uint8Array())
})
})
2 changes: 1 addition & 1 deletion packages/server/test/fixtures.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as ed25519 from '@ucanto/principal/ed25519'

/** did:key:z6Mkqa4oY9Z5Pf5tUcjLHLUsDjKwMC95HGXdE1j22jkbhz6r */
/** did:key:z6Mkk89bC3JrVqKie71YEcc5M1SMVxuCgNx6zLZ8SYJsxALi */
export const alice = ed25519.parse(
'MgCZT5vOnYZoVAeyjnzuJIVY9J4LNtJ+f8Js0cTPuKUpFne0BVEDJjEu6quFIU8yp91/TY/+MYK8GvlKoTDnqOCovCVM='
)
Expand Down
2 changes: 1 addition & 1 deletion packages/transport/test/fixtures.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as ed25519 from '@ucanto/principal/ed25519'

/** did:key:z6Mkqa4oY9Z5Pf5tUcjLHLUsDjKwMC95HGXdE1j22jkbhz6r */
/** did:key:z6Mkk89bC3JrVqKie71YEcc5M1SMVxuCgNx6zLZ8SYJsxALi */
export const alice = ed25519.parse(
'MgCZT5vOnYZoVAeyjnzuJIVY9J4LNtJ+f8Js0cTPuKUpFne0BVEDJjEu6quFIU8yp91/TY/+MYK8GvlKoTDnqOCovCVM='
)
Expand Down
31 changes: 26 additions & 5 deletions packages/validator/src/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,30 @@ export class DelegationError extends Failure {
}
}

/**
* @implements {API.SessionEscalation}
*/
export class SessionEscalation extends Failure {
/**
* @param {object} source
* @param {API.Delegation} source.delegation
* @param {API.Failure} source.cause
*/
constructor({ delegation, cause }) {
super()
this.name = the('SessionEscalation')
this.delegation = delegation
this.cause = cause
}
describe() {
const issuer = this.delegation.issuer.did()
return [
`Delegation ${this.delegation.cid} issued by ${issuer} has an invalid session`,
li(this.cause.message),
].join('\n')
}
}

/**
* @implements {API.InvalidSignature}
*/
Expand Down Expand Up @@ -145,7 +169,7 @@ export class UnavailableProof extends Failure {
export class DIDKeyResolutionError extends Failure {
/**
* @param {API.UCAN.DID} did
* @param {API.Unauthorized} [cause]
* @param {API.Failure} [cause]
*/
constructor(did, cause) {
super()
Expand All @@ -154,10 +178,7 @@ export class DIDKeyResolutionError extends Failure {
this.cause = cause
}
describe() {
return [
`Unable to resolve '${this.did}' key`,
...(this.cause ? [li(`Resolution failed: ${this.cause.message}`)] : []),
].join('\n')
return `Unable to resolve '${this.did}' key`
}
}

Expand Down
Loading