Skip to content

Commit

Permalink
wip: initial work toward revoke command
Browse files Browse the repository at this point in the history
needs new versions of access-client and w3up-client from this PR to build cleanly:

storacha/w3up#975
  • Loading branch information
travis committed Oct 17, 2023
1 parent a7bda04 commit 1abd7b3
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 1 deletion.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ List delegations created by this agent for others.

* `--json` Format as newline delimited JSON


### `w3 delegation revoke <delegation-cid>`

Revoke a delegation by CID.

* `--proof` Name of a file containing the delegation and any additional proofs needed to prove authority to revoke

### `w3 proof add <proof.ucan>`

Add a proof delegated to this agent. The proof is a CAR encoded delegation to _this_ agent. Note: you probably want to use `w3 space add` unless you know the delegation you received targets a resource _other_ than a w3 space.
Expand Down
6 changes: 6 additions & 0 deletions bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
spaceInfo,
createDelegation,
listDelegations,
revokeDelegation,
addProof,
listProofs,
upload,
Expand Down Expand Up @@ -117,6 +118,11 @@ cli.command('delegation ls')
.option('--json', 'Format as newline delimited JSON')
.action(listDelegations)

cli.command('delegation revoke <delegation-cid>')
.describe('Revoke a delegation by CID.')
.option('-p, --proof', 'Name of a file containing the delegation and any additional proofs needed to prove authority to revoke')
.action(revokeDelegation)

cli.command('proof add <proof>')
.describe('Add a proof delegated to this agent.')
.option('--json', 'Format as newline delimited JSON')
Expand Down
34 changes: 34 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,40 @@ export async function listDelegations (opts) {
}
}

/**
* @param {string} delegationCid
* @param {object} opts
* @param {string} [opts.proof]
*/
export async function revokeDelegation (delegationCid, opts) {
const client = await getClient()
let proof
try {
if (opts.proof) {
proof = await readProof(opts.proof)
}
} catch (/** @type {any} */err) {
console.log(`Error: ${err.message}`)
process.exit(1)
}
let cid
try {
// TODO: we should valiate that this is a UCANLink
cid = ucanto.parseLink(delegationCid.trim())
} catch (/** @type {any} */err) {
console.error(`Error: ${delegationCid} is not a CID`)
process.exit(1)
}
try {
await client.revokeDelegation(/** @type {import('@ucanto/interface').UCANLink} */(cid), { proofs: proof ? [proof] : [] })
console.log(`⁂ delegation ${delegationCid} revoked`)
} catch (/** @type {any} */err) {
console.error(`error trying to revoke ${delegationCid}: ${err.message}`)
console.error(err)
process.exit(1)
}
}

/**
* @param {string} proofPath
* @param {{ json?: boolean, 'dry-run'?: boolean }} [opts]
Expand Down
33 changes: 32 additions & 1 deletion test/bin.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as DID from '@ipld/dag-ucan/did'
import * as StoreCapabilities from '@web3-storage/capabilities/store'
import * as UploadCapabilities from '@web3-storage/capabilities/upload'
import * as SpaceCapabilities from '@web3-storage/capabilities/space'
import * as UCANCapabilities from '@web3-storage/capabilities/ucan'
import * as Link from 'multiformats/link'
import { CarReader } from '@ipld/car'
import { StoreConf } from '@web3-storage/access/stores/store-conf'
Expand Down Expand Up @@ -39,7 +40,8 @@ test.beforeEach(async t => {
const server = createServer({
id: serviceSigner,
service,
codec: CAR.inbound
codec: CAR.inbound,
validateAuthorization: () => ok({})
})
setRequestListener(createHTTPListener(server))
}
Expand Down Expand Up @@ -369,6 +371,35 @@ test('w3 delegation ls', async t => {
t.is(delegationData.capabilities[0].can, '*')
})

test.only('w3 delegation revoke', async t => {
const env = t.context.env.alice
const service = mockService({
ucan: {
revoke: provide(UCANCapabilities.revoke, () => {
return ok({ time: Date.now() })
})
}
})
t.context.setService(service)

await execa('./bin.js', ['space', 'create'], { env })

const bob = await Signer.generate()
await execa('./bin.js', ['delegation', 'create', bob.did(), '-c', '*'], { env })

const out1 = await execa('./bin.js', ['delegation', 'ls', '--json'], { env })
const delegationData = JSON.parse(out1.stdout)

// alice should be able to revoke the delegation she just created
const out2 = await execa('./bin.js', ['delegation', 'revoke', delegationData.cid], { env })
t.regex(out2.stdout, new RegExp(`delegation ${delegationData.cid} revoked`))

// but bob should not be able to revoke alice's delegation
/** @type {any} */
const out3 = await t.throwsAsync(() => execa('./bin.js', ['delegation', 'revoke', delegationData.cid], { env: t.context.env.bob }))
t.regex(out3.stderr, new RegExp(`error trying to revoke ${delegationData.cid}: could not find delegation ${delegationData.cid}`))
})

test('w3 space add', async t => {
const aliceEnv = t.context.env.alice
const bobEnv = t.context.env.bob
Expand Down
4 changes: 4 additions & 0 deletions test/helpers/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const notImplemented = () => {
* store: Partial<import('@web3-storage/upload-client/types').Service['store']>
* upload: Partial<import('@web3-storage/upload-client/types').Service['upload']>
* space: Partial<import('@web3-storage/access/types').Service['space']>
* ucan: Partial<import('@web3-storage/access/types').Service['ucan']>
* }>} impl
*/
export function mockService (impl) {
Expand All @@ -25,6 +26,9 @@ export function mockService (impl) {
},
space: {
info: withCallCount(impl.space?.info ?? notImplemented)
},
ucan: {
revoke: withCallCount(impl.ucan?.revoke ?? notImplemented)
}
}
}
Expand Down

0 comments on commit 1abd7b3

Please sign in to comment.