-
Notifications
You must be signed in to change notification settings - Fork 23
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: define access/confirm
handler and use it in ucanto-test-utils registerSpaces + validate-email handler
#530
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f177195
access authorize test uses claimed delegations and ensures no error
gobengo 4b3cc98
expose access/confirm handler
gobengo 4401ece
ucanto-test-utils registerSpaces uses provider/add flow
gobengo 6355c17
access-confirm handler uses delegationsResponse.encode
gobengo 901c460
Update packages/access-api/src/service/access-confirm.js
gobengo 9080cfb
validate-email authorize confirmation error is included as cause with…
gobengo b4fc3c7
fix misleading var name
gobengo 6490ba2
Merge branch 'main' into accessconfirmregisterspaces
gobengo 492c33d
remove misleading comment
gobengo c74969a
mergeback main with provider id change
gobengo 0d4dd44
pass error cause in validate-email authorize
gobengo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import * as Ucanto from '@ucanto/interface' | ||
import * as ucanto from '@ucanto/core' | ||
import { Verifier, Absentee } from '@ucanto/principal' | ||
import { collect } from 'streaming-iterables' | ||
import * as Access from '@web3-storage/capabilities/access' | ||
import { delegationsToString } from '@web3-storage/access/encoding' | ||
import * as delegationsResponse from '../utils/delegations-response.js' | ||
|
||
/** | ||
* @typedef {import('@web3-storage/capabilities/types').AccessConfirmSuccess} AccessConfirmSuccess | ||
* @typedef {import('@web3-storage/capabilities/types').AccessConfirmFailure} AccessConfirmFailure | ||
*/ | ||
|
||
/** | ||
* @param {Ucanto.Invocation<import('@web3-storage/capabilities/src/types').AccessConfirm>} invocation | ||
*/ | ||
export function parse(invocation) { | ||
const capability = invocation.capabilities[0] | ||
// Create a absentee signer for the account that authorized the delegation | ||
const account = Absentee.from({ id: capability.nb.iss }) | ||
const agent = Verifier.parse(capability.nb.aud) | ||
return { | ||
account, | ||
agent, | ||
} | ||
} | ||
|
||
/** | ||
* @param {Ucanto.Invocation<import('@web3-storage/capabilities/src/types').AccessConfirm>} invocation | ||
* @param {import('../bindings').RouteContext} ctx | ||
* @returns {Promise<Ucanto.Result<AccessConfirmSuccess, AccessConfirmFailure>>} | ||
*/ | ||
export async function handleAccessConfirm(invocation, ctx) { | ||
const capability = invocation.capabilities[0] | ||
if (capability.with !== ctx.signer.did()) { | ||
throw new Error(`Not a valid access/confirm delegation`) | ||
} | ||
|
||
const { account, agent } = parse(invocation) | ||
|
||
// It the future we should instead render a page and allow a user to select | ||
// which delegations they wish to re-delegate. Right now we just re-delegate | ||
// everything that was requested for all of the resources. | ||
const capabilities = | ||
/** @type {ucanto.UCAN.Capabilities} */ | ||
( | ||
capability.nb.att.map(({ can }) => ({ | ||
can, | ||
with: /** @type {ucanto.UCAN.Resource} */ ('ucan:*'), | ||
})) | ||
) | ||
|
||
// create an delegation on behalf of the account with an absent signature. | ||
const delegation = await ucanto.delegate({ | ||
issuer: account, | ||
audience: agent, | ||
capabilities, | ||
expiration: Infinity, | ||
// We include all the delegations to the account so that the agent will | ||
// have delegation chains to all the delegated resources. | ||
// We should actually filter out only delegations that support delegated | ||
// capabilities, but for now we just include all of them since we only | ||
// implement sudo access anyway. | ||
proofs: await collect( | ||
ctx.models.delegations.find({ | ||
audience: account.did(), | ||
}) | ||
), | ||
}) | ||
|
||
const attestation = await Access.session.delegate({ | ||
issuer: ctx.signer, | ||
audience: agent, | ||
with: ctx.signer.did(), | ||
nb: { proof: delegation.cid }, | ||
expiration: Infinity, | ||
}) | ||
|
||
// Store the delegations so that they can be pulled with access/claim | ||
// The fact that we're storing proofs chains that we pulled from the | ||
// database is not great, but it's a tradeoff we're making for now. | ||
await ctx.models.delegations.putMany(delegation, attestation) | ||
|
||
const authorization = delegationsToString([delegation, attestation]) | ||
// Save delegations for the validation process | ||
await ctx.models.validations.putSession(authorization, agent.did()) | ||
|
||
return { | ||
delegations: delegationsResponse.encode([delegation, attestation]), | ||
} | ||
} |
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 |
---|---|---|
|
@@ -4,6 +4,7 @@ import * as Server from '@ucanto/server' | |
import * as validator from '@ucanto/validator' | ||
import { Failure } from '@ucanto/server' | ||
import * as Space from '@web3-storage/capabilities/space' | ||
import * as Access from '@web3-storage/capabilities/access' | ||
import { top } from '@web3-storage/capabilities/top' | ||
import { | ||
delegationToString, | ||
|
@@ -17,6 +18,7 @@ import { accessDelegateProvider } from './access-delegate.js' | |
import { accessClaimProvider } from './access-claim.js' | ||
import { providerAddProvider } from './provider-add.js' | ||
import { Spaces } from '../models/spaces.js' | ||
import { handleAccessConfirm } from './access-confirm.js' | ||
|
||
/** | ||
* @param {import('../bindings').RouteContext} ctx | ||
|
@@ -45,6 +47,21 @@ export function service(ctx) { | |
config: ctx.config, | ||
})(...args) | ||
}, | ||
confirm: Server.provide( | ||
Access.confirm, | ||
async ({ capability, invocation }) => { | ||
// only needed in tests | ||
if (ctx.config.ENV !== 'test') { | ||
throw new Error(`access/confirm is disabled`) | ||
} | ||
Comment on lines
+53
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would not limit this to tests only. |
||
return handleAccessConfirm( | ||
/** @type {Ucanto.Invocation<import('@web3-storage/access/types').AccessConfirm>} */ ( | ||
invocation | ||
), | ||
ctx | ||
) | ||
} | ||
), | ||
delegate: (...args) => { | ||
// disable until hardened in test/staging | ||
if (ctx.config.ENV === 'production') { | ||
|
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this all going to be backwards compatible with the current implementation? backwards compatibility isn't necessarily a hard requirement, but I am interested in tracking what's likely to break for older clients
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is yes, it will be. All the old tests pass.
(this whole path is only exercised when clicking confirmation email sent by
access/authorize
, so it will be backward compatible with the not-very-many implementations of the client side of that, e.g. the observable I made)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OH right, the separate codepath for this should make it all work fine, cool!