Skip to content

Commit

Permalink
confirming access/authorize email no longer stores ucan/attest delega…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
gobengo committed Feb 28, 2023
1 parent 83141c4 commit 685af65
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 109 deletions.
84 changes: 18 additions & 66 deletions packages/access-api/src/routes/validate-email.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
import * as ucanto from '@ucanto/core'
import * as validator from '@ucanto/validator'
import { Verifier } from '@ucanto/principal/ed25519'
import { ed25519 } from '@ucanto/principal'

/**
* @param {import('@web3-storage/worker-utils/router').ParsedRequest} req
Expand Down Expand Up @@ -150,81 +149,34 @@ async function session(req, env) {
`unable to validate access session: ${accessSessionResult.error}`
)
}
const accountDID = accessSessionResult.audience.did()
// @todo: use new ucanto `Account` instead
const accountOneOffKey = await ed25519.generate()
const account = accountOneOffKey.withDID(accountDID)

const account = { did: () => accessSessionResult.audience.did() }
const agentPubkey = accessSessionResult.capability.nb.key

const update = await ucanto.delegate({
issuer: env.signer,
audience: account,
capabilities: [
{
with: env.signer.did(),
can: './update',
nb: {
key: agentPubkey,
},
},
],
})
const attestKeyAuthorizesAccount = await ucanto.delegate({
const wrappedKeyCanAsignForAccount = await ucanto.delegate({
issuer: env.signer,
audience: { did: () => agentPubkey },
capabilities: [
{
with: env.signer.did(),
can: 'ucan/attest',
nb: {
proof: update.cid,
},
},
],
proofs: [update],
})

// create delegations that should be claimable
const delegationAccountToKey = await ucanto.delegate({
issuer: account,
audience: {
did() {
return agentPubkey
},
},
capabilities: [
{
with: 'ucan:*',
can: '*',
can: 'access-api/delegation',
},
],
})
// generate a delegation to the key that we can save in
// models.delegations to be found by subsequent access/claim
// invocations invoked by the did:key
const delegateToKey = await ucanto.delegate({
issuer: env.signer,
audience: {
did() {
return agentPubkey
},
},
proofs: [delegationAccountToKey],
capabilities: [
{
can: 'ucan/attest',
with: env.signer.did(),
nb: {
proof: delegationAccountToKey.cid,
},
},
proofs: [
await ucanto.delegate({
issuer: env.signer,
audience: account,
capabilities: [
{
with: env.signer.did(),
can: './update',
nb: {
key: agentPubkey,
},
},
],
}),
],
})
await env.models.delegations.putMany(
delegateToKey,
attestKeyAuthorizesAccount
)
await env.models.delegations.putMany(wrappedKeyCanAsignForAccount)
}

try {
Expand Down
56 changes: 13 additions & 43 deletions packages/access-api/test/access-authorize.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,61 +149,31 @@ describe('access/authorize', function () {
)
assert.deepEqual(
claimedDelegations.length,
2,
1,
'should have claimed delegation(s)'
)
/**
* narrow Ucanto.Proof to Ucanto.Delegation
*
* @param {import('@ucanto/interface').Proof} proof
*/
// eslint-disable-next-line unicorn/consistent-function-scoping
const proofDelegation = (proof) => {
if (!('cid' in proof)) {

const claimedDelegationIssuedByService = claimedDelegations.find((d) => {
if (!('cid' in d.proofs[0])) {
throw new Error('proof must be delegation')
}
return proof
}
const attest = claimedDelegations.find(
(d) => proofDelegation(d.proofs[0])?.issuer.did() === accountDID
)
assert.ok(
attest,
'should claim ucan/attest delegation with proof.iss=accountDID'
)
assert.deepEqual(attest.issuer.did(), service.did())
assert.deepEqual(attest.audience.did(), issuer.did())
assert.deepEqual(attest.capabilities[0].can, 'ucan/attest')
assert.deepEqual(attest.capabilities[0].with, service.did())

// ucan/attest nb.proof can be decoded into a delegation
const claimedNb = attest.capabilities[0].nb
assert.ok(
claimedNb && typeof claimedNb === 'object' && 'proof' in claimedNb,
'should have nb.proof'
)
const expectAccountToKey = proofDelegation(attest.proofs[0])
assert.ok(expectAccountToKey, 'expect proofs to contain delegation')
assert.deepEqual(expectAccountToKey.issuer.did(), accountDID)
assert.deepEqual(expectAccountToKey.audience.did(), issuer.did())
assert.deepEqual(expectAccountToKey.capabilities, [
{ can: '*', with: 'ucan:*' },
])

const attestIssService = claimedDelegations.find(
(d) => proofDelegation(d.proofs[0])?.issuer.did() === service.did()
)
return d.proofs[0].issuer.did() === service.did()
})
assert.ok(
attestIssService,
claimedDelegationIssuedByService,
'should claim ucan/attest with proof.iss=service'
)
const accountAuthorization = attestIssService.proofs[0]

// we can use claimedDelegationIssuedByService to invoke access/claim as iss=accountDID
const account = issuer.withDID(accountDID)
const claimAsAccount = Access.claim.invoke({
issuer: account,
audience: service,
with: account.did(),
proofs: [accountAuthorization],
proofs: [
// allows signing with issuer.signer as iss=accountDID
claimedDelegationIssuedByService.proofs[0],
],
})
const claimAsAccountResult = await claimAsAccount.execute(conn)
warnOnErrorResult(claimAsAccountResult)
Expand Down

0 comments on commit 685af65

Please sign in to comment.