-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathdelegate.js
87 lines (76 loc) · 2.34 KB
/
delegate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import * as Server from '@ucanto/server'
import * as Access from '@web3-storage/capabilities/access'
import * as API from '../types.js'
import * as Allocator from '../space-allocate.js'
/**
* @param {API.AccessServiceContext} ctx
*/
export const provide = (ctx) =>
Server.provide(Access.delegate, (input) => delegate(input, ctx))
/**
* @param {API.Input<Access.delegate>} input
* @param {API.AccessServiceContext} context
* @returns {Promise<API.Result<API.AccessDelegateSuccess, API.AccessDelegateFailure>>}
*/
export const delegate = async ({ capability, invocation }, context) => {
const delegated = extractProvenDelegations(capability, invocation.proofs)
if (delegated.error) {
return delegated
}
const result = await Allocator.allocate(
{
capability: {
with: capability.with,
},
},
context
)
if (result.ok) {
await context.delegationsStorage.putMany(delegated.ok, {
cause: invocation.link(),
})
return { ok: {} }
} else {
return result
}
}
/**
* @param {API.InferInvokedCapability<typeof Access.delegate>} capability
* @param {API.Proof[]} proofs
* @returns {API.Result<API.Delegation<API.Capabilities>[], API.DelegationNotFound>}
*/
const extractProvenDelegations = (capability, proofs) => {
const nbDelegations = new Set(Object.values(capability.nb.delegations))
const proofDelegations = proofs.flatMap((proof) =>
'capabilities' in proof ? [proof] : []
)
if (nbDelegations.size > proofDelegations.length) {
return {
error: new DelegationNotFound(
`nb.delegations has more delegations than proofs`
),
}
}
const delegations = []
for (const delegationLink of nbDelegations) {
// @todo avoid O(m*n) check here, but not obvious how while also using full Link#equals logic
// (could be O(minimum(m,n)) if comparing CID as strings, but that might ignore same link diff multibase)
const delegationProof = proofDelegations.find((p) =>
delegationLink.equals(p.cid)
)
if (!delegationProof) {
return {
error: new DelegationNotFound(
`missing proof for delegation cid ${delegationLink}`
),
}
}
delegations.push(delegationProof)
}
return { ok: delegations }
}
class DelegationNotFound extends Server.Failure {
get name() {
return /** @type {const} */ ('DelegationNotFound')
}
}