forked from storacha/w3up
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(capabilities)!: add
index/add
capability (storacha#1410)
Adds `index/add` capability. refs https://github.com/w3s-project/specs/blob/main/w3-index.md BREAKING CHANGE: `BlobMultihash` type in `@web3-storage/capabilities` renamed to `Multihash`. --------- Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
- Loading branch information
1 parent
2441ee9
commit 1b71b89
Showing
7 changed files
with
262 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* Index Capabilities. | ||
* | ||
* W3 Indexing protocol allows authorized agents to submit verifiable claims | ||
* about content-addressed data to be published on the InterPlanetary Network | ||
* Indexer (IPNI), making it publicly queryable. | ||
* | ||
* These can be imported directly with: | ||
* ```js | ||
* import * as Index from '@web3-storage/capabilities/index' | ||
* ``` | ||
* | ||
* @module | ||
*/ | ||
import { CAR } from '@ucanto/core' | ||
import { capability, Schema, ok } from '@ucanto/validator' | ||
import { equalWith, SpaceDID, and, equal } from '../utils.js' | ||
|
||
/** | ||
* Capability can only be delegated (but not invoked) allowing audience to | ||
* derive any `index/` prefixed capability for the space identified by the DID | ||
* in the `with` field. | ||
*/ | ||
export const index = capability({ | ||
can: 'index/*', | ||
/** DID of the space where indexed data is stored. */ | ||
with: SpaceDID, | ||
derives: equalWith, | ||
}) | ||
|
||
/** | ||
* `index/add` capability allows an agent to submit verifiable claims | ||
* about content-addressed data to be published on the InterPlanetary Network | ||
* Indexer (IPNI), making it publicly queryable. | ||
*/ | ||
export const add = capability({ | ||
can: 'index/add', | ||
/** DID of the space where indexed data is stored. */ | ||
with: SpaceDID, | ||
nb: Schema.struct({ | ||
/** Content Archive (CAR) containing the `Index`. */ | ||
index: Schema.link({ code: CAR.code }), | ||
}), | ||
derives: (claimed, delegated) => | ||
and(equalWith(claimed, delegated)) || | ||
and(equal(claimed.nb.index, delegated.nb.index, 'index')) || | ||
ok({}), | ||
}) | ||
|
||
// ⚠️ We export imports here so they are not omitted in generated typedefs | ||
// @see https://github.com/microsoft/TypeScript/issues/51548 | ||
export { Schema } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import assert from 'assert' | ||
import { access } from '@ucanto/validator' | ||
import { Verifier } from '@ucanto/principal' | ||
import * as Index from '../../src/index/index.js' | ||
import * as Capability from '../../src/top.js' | ||
import { | ||
alice, | ||
service as w3, | ||
mallory as account, | ||
bob, | ||
} from '../helpers/fixtures.js' | ||
import { createCarCid, validateAuthorization } from '../helpers/utils.js' | ||
|
||
const top = async () => | ||
Capability.top.delegate({ | ||
issuer: account, | ||
audience: alice, | ||
with: account.did(), | ||
}) | ||
|
||
const index = async () => | ||
Index.index.delegate({ | ||
issuer: account, | ||
audience: alice, | ||
with: account.did(), | ||
proofs: [await top()], | ||
}) | ||
|
||
describe('index capabilities', function () { | ||
it('index/add can be derived from *', async () => { | ||
const add = Index.add.invoke({ | ||
issuer: alice, | ||
audience: w3, | ||
with: account.did(), | ||
nb: { | ||
index: await createCarCid('test'), | ||
}, | ||
proofs: [await top()], | ||
}) | ||
|
||
const result = await access(await add.delegate(), { | ||
capability: Index.add, | ||
principal: Verifier, | ||
authority: w3, | ||
validateAuthorization, | ||
}) | ||
|
||
if (result.error) { | ||
assert.fail(result.error.message) | ||
} | ||
|
||
assert.deepEqual(result.ok.audience.did(), w3.did()) | ||
assert.equal(result.ok.capability.can, 'index/add') | ||
assert.deepEqual(result.ok.capability.nb, { | ||
index: await createCarCid('test'), | ||
}) | ||
}) | ||
|
||
it('index/add can be derived from index/*', async () => { | ||
const add = Index.add.invoke({ | ||
issuer: alice, | ||
audience: w3, | ||
with: account.did(), | ||
nb: { | ||
index: await createCarCid('test'), | ||
}, | ||
proofs: [await index()], | ||
}) | ||
|
||
const result = await access(await add.delegate(), { | ||
capability: Index.add, | ||
principal: Verifier, | ||
authority: w3, | ||
validateAuthorization, | ||
}) | ||
|
||
if (result.error) { | ||
assert.fail(result.error.message) | ||
} | ||
|
||
assert.deepEqual(result.ok.audience.did(), w3.did()) | ||
assert.equal(result.ok.capability.can, 'index/add') | ||
assert.deepEqual(result.ok.capability.nb, { | ||
index: await createCarCid('test'), | ||
}) | ||
}) | ||
|
||
it('index/add can be derived from index/* derived from *', async () => { | ||
const index = await Index.index.delegate({ | ||
issuer: alice, | ||
audience: bob, | ||
with: account.did(), | ||
proofs: [await top()], | ||
}) | ||
|
||
const add = Index.add.invoke({ | ||
issuer: bob, | ||
audience: w3, | ||
with: account.did(), | ||
nb: { | ||
index: await createCarCid('test'), | ||
}, | ||
proofs: [index], | ||
}) | ||
|
||
const result = await access(await add.delegate(), { | ||
capability: Index.add, | ||
principal: Verifier, | ||
authority: w3, | ||
validateAuthorization, | ||
}) | ||
|
||
if (result.error) { | ||
assert.fail(result.error.message) | ||
} | ||
|
||
assert.deepEqual(result.ok.audience.did(), w3.did()) | ||
assert.equal(result.ok.capability.can, 'index/add') | ||
assert.deepEqual(result.ok.capability.nb, { | ||
index: await createCarCid('test'), | ||
}) | ||
}) | ||
|
||
it('index/add should fail when escalating index constraint', async () => { | ||
const delegation = await Index.add.delegate({ | ||
issuer: alice, | ||
audience: bob, | ||
with: account.did(), | ||
nb: { | ||
index: await createCarCid('test'), | ||
}, | ||
proofs: [await top()], | ||
}) | ||
|
||
const add = Index.add.invoke({ | ||
issuer: bob, | ||
audience: w3, | ||
with: account.did(), | ||
nb: { | ||
index: await createCarCid('test2'), | ||
}, | ||
proofs: [delegation], | ||
}) | ||
|
||
const result = await access(await add.delegate(), { | ||
capability: Index.add, | ||
principal: Verifier, | ||
authority: w3, | ||
validateAuthorization, | ||
}) | ||
|
||
assert.ok(result.error) | ||
assert(result.error.message.includes('violates imposed index constraint')) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters