Skip to content
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

fix: rm mention of 'sessionPrincipal' from agent and agent-data #546

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions packages/access-client/src/agent-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Signer } from '@ucanto/principal'
import { Signer as EdSigner } from '@ucanto/principal/ed25519'
import { importDAG } from '@ucanto/core/delegation'
import * as Ucanto from '@ucanto/interface'
import { DID } from '@ucanto/core'
import { CID } from 'multiformats'
import { Access } from '@web3-storage/capabilities'
import { isExpired } from './delegations.js'
Expand All @@ -21,7 +20,6 @@ export class AgentData {
constructor(data, options = {}) {
this.meta = data.meta
this.principal = data.principal
this.sessionPrincipal = data.sessionPrincipal
this.spaces = data.spaces
this.delegations = data.delegations
this.currentSpace = data.currentSpace
Expand All @@ -40,7 +38,6 @@ export class AgentData {
{
meta: { name: 'agent', type: 'device', ...init.meta },
principal: init.principal ?? (await EdSigner.generate()),
sessionPrincipal: init.sessionPrincipal,
spaces: init.spaces ?? new Map(),
delegations: init.delegations ?? new Map(),
currentSpace: init.currentSpace,
Expand Down Expand Up @@ -80,10 +77,6 @@ export class AgentData {
meta: raw.meta,
// @ts-expect-error for some reason TS thinks this is a EdSigner
principal: Signer.from(raw.principal),
// @ts-expect-error TODO figure out the types for this too
sessionPrincipal: raw.sessionPrincipal
? DID.parse(raw.sessionPrincipal)
: undefined,
currentSpace: raw.currentSpace,
spaces: raw.spaces,
delegations: dels,
Expand All @@ -100,7 +93,6 @@ export class AgentData {
const raw = {
meta: this.meta,
principal: this.principal.toArchive(),
sessionPrincipal: this.sessionPrincipal?.did(),
currentSpace: this.currentSpace,
spaces: this.spaces,
delegations: new Map(),
Expand Down Expand Up @@ -135,14 +127,6 @@ export class AgentData {
await this.#save(this.export())
}

/**
* @param {import('@ucanto/interface').Principal<import('@ucanto/interface').DID<'mailto'>>} principal
*/
async setSessionPrincipal(principal) {
this.sessionPrincipal = principal
await this.#save(this.export())
}

/**
* @param {import('@ucanto/interface').Delegation} delegation
* @param {import('./types').DelegationMeta} [meta]
Expand Down
82 changes: 32 additions & 50 deletions packages/access-client/src/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as CAR from '@ucanto/transport/car'
import * as CBOR from '@ucanto/transport/cbor'
import * as HTTP from '@ucanto/transport/http'
import * as ucanto from '@ucanto/core'
import { URI } from '@ucanto/validator'
import { URI, DID as DIDValidator } from '@ucanto/validator'
import { Peer } from './awake/peer.js'
import * as Space from '@web3-storage/capabilities/space'
import * as Access from '@web3-storage/capabilities/access'
Expand All @@ -25,22 +25,13 @@ import {
canDelegateCapability,
} from './delegations.js'
import { AgentData, getSessionProof } from './agent-data.js'
import { createDidMailtoFromEmail } from './utils/did-mailto.js'

export { AgentData }

const HOST = 'https://access.web3.storage'
const PRINCIPAL = DID.parse('did:web:web3.storage')

/**
*
* @param {string} email
* @returns {Ucanto.Principal<Ucanto.DID<'mailto'>>}
*/
function emailToSessionPrincipal(email) {
const parts = email.split('@').map((s) => encodeURIComponent(s))
return DID.parse(`did:mailto:${parts[1]}:${parts[0]}`)
}

/**
* @param {Ucanto.Signer<Ucanto.DID<'key'>>} issuer
* @param {Ucanto.DID} space
Expand Down Expand Up @@ -190,10 +181,6 @@ export class Agent {
return this.#data.spaces
}

get account() {
return this.#data.sessionPrincipal
}

did() {
return this.#data.principal.did()
}
Expand Down Expand Up @@ -500,18 +487,16 @@ export class Agent {
* Request authorization of a session allowing this agent to issue UCANs
* signed by the passed email address.
*
* @param {string} email
* @param {`${string}@${string}`} email
* @param {object} [opts]
* @param {AbortSignal} [opts.signal]
*/
async authorize(email, opts) {
const sessionPrincipal = emailToSessionPrincipal(email)

const res = await this.invokeAndExecute(Access.authorize, {
audience: this.connection.id,
with: this.issuer.did(),
nb: {
iss: sessionPrincipal.did(),
iss: createDidMailtoFromEmail(email),
att: [{ can: 'store/*' }, { can: 'provider/add' }, { can: 'upload/*' }],
},
})
Expand All @@ -533,7 +518,6 @@ export class Agent {
}

await this.addProof(sessionDelegation)
this.#data.setSessionPrincipal(sessionPrincipal)

// claim delegations here because we will need an ucan/attest from the service to
// pair with the session delegation we just claimed to make it work
Expand Down Expand Up @@ -581,26 +565,21 @@ export class Agent {

/**
* @param {Ucanto.DID<'key'>} space
* @param {Ucanto.Principal<Ucanto.DID<'mailto'>>} account
* @param {Ucanto.DID<'web'>} provider - e.g. 'did:web:staging.web3.storage'
*/
async addProvider(space) {
const sessionPrincipal = this.#data.sessionPrincipal

if (!sessionPrincipal) {
throw new Error('cannot add provider, please authorize first')
}

async addProvider(space, account, provider) {
return this.invokeAndExecute(Provider.add, {
audience: this.connection.id,
with: sessionPrincipal.did(),
with: account.did(),
proofs: this.proofs([
{
can: 'provider/add',
with: sessionPrincipal.did(),
with: account.did(),
},
]),
nb: {
// TODO probably need to make it possible to pass other providers in
provider: 'did:web:staging.web3.storage',
provider,
consumer: space,
},
})
Expand All @@ -609,22 +588,11 @@ export class Agent {
/**
*
* @param {Ucanto.DID<'key'>} space
* @param {Ucanto.Principal<Ucanto.DID<'mailto'>>} account
*/
async delegateSpaceAccessToAccount(space) {
const sessionPrincipal = this.#data.sessionPrincipal

if (!sessionPrincipal) {
throw new Error(
'cannot add delegate space access to account, please authorize first'
)
}

async delegateSpaceAccessToAccount(space, account) {
const spaceSaysAccountCanAdminSpace =
await createIssuerSaysAccountCanAdminSpace(
this.issuer,
space,
sessionPrincipal
)
await createIssuerSaysAccountCanAdminSpace(this.issuer, space, account)
return this.invokeAndExecute(Access.delegate, {
audience: this.connection.id,
with: space,
Expand Down Expand Up @@ -652,12 +620,26 @@ export class Agent {
*
* It also adds a full space delegation to the service in the voucher/claim invocation to allow for recovery
*
* @param {string} email
* @param {object} [opts]
* @param {AbortSignal} [opts.signal]
* @param {Ucanto.DID<'web'>} [opts.provider] - provider to register - defaults to this.connection.id
*/
async registerSpace(opts) {
async registerSpace(email, opts) {
const space = this.currentSpace()
const spaceMeta = space ? this.#data.spaces.get(space) : undefined
const provider =
opts?.provider ||
(() => {
const service = this.connection.id.did()
if (DIDValidator.match({ method: 'web' }).is(service)) {
// connection.id did is a valid provider value. Try using that.
return service
}
throw new Error(
`unable to determine provider to use to register space. Pass opts.provider`
)
})()

if (!space || !spaceMeta) {
throw new Error('No space selected')
Expand All @@ -666,14 +648,14 @@ export class Agent {
if (spaceMeta && spaceMeta.isRegistered) {
throw new Error('Space already registered with web3.storage.')
}
const providerResult = await this.addProvider(
/** @type {Ucanto.DID<'key'>} */ (space)
)
const account = { did: () => createDidMailtoFromEmail(email) }
const providerResult = await this.addProvider(space, account, provider)
if (providerResult.error) {
throw new Error(providerResult.message, { cause: providerResult })
}
const delegateSpaceAccessResult = await this.delegateSpaceAccessToAccount(
space
space,
account
)
if (delegateSpaceAccessResult.error) {
// @ts-ignore it's very weird that this is throwing an error but line 692 above does not - ignore for now
Expand Down
2 changes: 0 additions & 2 deletions packages/access-client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ export type CIDString = string
export interface AgentDataModel {
meta: AgentMeta
principal: Signer<DID<'key'>>
sessionPrincipal?: Principal<Ucanto.DID<'mailto'>>
currentSpace?: DID<'key'>
spaces: Map<DID, SpaceMeta>
delegations: Map<CIDString, { meta: DelegationMeta; delegation: Delegation }>
Expand All @@ -184,7 +183,6 @@ export type AgentDataExport = Pick<
'meta' | 'currentSpace' | 'spaces'
> & {
principal: SignerArchive<DID, SigAlg>
sessionPrincipal?: string
delegations: Map<
CIDString,
{
Expand Down
15 changes: 15 additions & 0 deletions packages/access-client/src/utils/did-mailto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @param {string} email
* @returns {`did:mailto:${string}:${string}`}
*/
export function createDidMailtoFromEmail(email) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please export this from the package so I can use it in w3ui?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed to our feature branch as 0cc4e47

const emailParts = email.split('@')
if (emailParts.length !== 2) {
throw new Error(`unexpected email ${email}`)
}
const [local, domain] = emailParts
const did = /** @type {const} */ (
`did:mailto:${encodeURIComponent(domain)}:${encodeURIComponent(local)}`
)
return did
}