-
Notifications
You must be signed in to change notification settings - Fork 7
/
up-client.js
141 lines (126 loc) · 4.22 KB
/
up-client.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { connect } from '@ucanto/client'
import { CAR, HTTP } from '@ucanto/transport'
import * as DID from '@ipld/dag-ucan/did'
import * as Signer from '@ucanto/principal/ed25519'
import { AgentData } from '@web3-storage/access/agent'
import { Client } from '@web3-storage/w3up-client'
import { MailSlurp } from "mailslurp-client"
import { fileURLToPath } from 'node:url'
import dotenv from 'dotenv'
import * as BlobCapabilities from '@web3-storage/capabilities/blob'
dotenv.config({ path: fileURLToPath(new URL('../../.env', import.meta.url)) })
/**
*
* @param {string} email
* @param {string} accessServiceUrl
*/
function getAuthLinkFromEmail (email, accessServiceUrl) {
// forgive me for I have s̵i̵n̴n̴e̵d̴ ̸a̸n̵d̷ ̷p̶a̵r̵s̵e̸d̷ Ȟ̷̞T̷̢̈́M̸̼̿L̴̎ͅ ̵̗̍ẅ̵̝́ï̸ͅt̴̬̅ḫ̸̔ ̵͚̔ŗ̵͊e̸͍͐g̶̜͒ė̷͖x̴̱̌
// TODO we should update the email and add an ID to this element to make this more robust - tracked in https://github.com/web3-storage/w3infra/issues/208
const link = email.match(/<a href="([^"]*)".*Verify email address/)[1]
if (!link){
throw new Error(`Could not find email verification link in ${email}`)
}
return link
}
export async function createMailSlurpInbox() {
const apiKey = process.env.MAILSLURP_API_KEY
const mailslurp = new MailSlurp({ apiKey })
const inbox = await mailslurp.inboxController.createInbox({})
return {
mailslurp,
id: inbox.id,
email: inbox.emailAddress
}
}
export async function createNewClient(uploadServiceUrl) {
const principal = await Signer.generate()
const data = await AgentData.create({ principal })
return new Client(data, {
serviceConf: {
upload: getUploadServiceConnection(uploadServiceUrl),
access: getAccessServiceConnection(uploadServiceUrl)
},
})
}
export async function setupNewClient (uploadServiceUrl, options = {}) {
// create an inbox
const { mailslurp, id: inboxId, email } = options.inbox || await createMailSlurpInbox()
const client = await createNewClient(uploadServiceUrl)
const timeoutMs = process.env.MAILSLURP_TIMEOUT ? parseInt(process.env.MAILSLURP_TIMEOUT) : 60_000
const authorizePromise = client.login(email)
const [account] = await Promise.all([
authorizePromise,
(async () => {
// click link in email
const latestEmail = await mailslurp.waitForLatestEmail(inboxId, timeoutMs)
const authLink = getAuthLinkFromEmail(latestEmail.body, uploadServiceUrl)
const res = await fetch(authLink, { method: 'POST' })
if (!res.ok) {
throw new Error('failed to authenticate by clickling on auth link from e-mail')
}
})()
])
if (!client.currentSpace()) {
const space = await client.createSpace("test space")
await account.provision(space.did())
await space.save()
}
return { client, account }
}
/**
* @param {Client} client
* @param {string} serviceUrl
* @param {string} capability
*/
export function getServiceProps (client, serviceUrl, capability) {
// Get invocation config
const resource = client.agent.currentSpace()
if (!resource) {
throw new Error(
'missing current space: use createSpace() or setCurrentSpace()'
)
}
const connection = getUploadServiceConnection(serviceUrl)
return {
connection,
conf: {
issuer: client.agent.issuer,
with: resource,
proofs: client.agent.proofs(
[BlobCapabilities.add.can].map((can) => ({ can, with: resource }))
),
audience: DID.parse('did:web:staging.web3.storage')
}
}
}
/**
* @param {string} serviceUrl
*/
function getAccessServiceConnection(serviceUrl) {
const accessServiceURL = new URL(serviceUrl)
const accessServicePrincipal = DID.parse('did:web:staging.web3.storage')
return connect({
id: accessServicePrincipal,
codec: CAR.outbound,
channel: HTTP.open({
url: accessServiceURL,
method: 'POST'
}),
})
}
/**
* @param {string} serviceUrl
*/
function getUploadServiceConnection(serviceUrl) {
const uploadServiceURL = new URL(serviceUrl)
const uploadServicePrincipal = DID.parse('did:web:staging.web3.storage')
return connect({
id: uploadServicePrincipal,
codec: CAR.outbound,
channel: HTTP.open({
url: uploadServiceURL,
method: 'POST'
})
})
}