-
-
Notifications
You must be signed in to change notification settings - Fork 128
/
Copy pathvault.js
75 lines (65 loc) · 2.43 KB
/
vault.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
import { E_VAULT_KEY_EXISTS, GqlAuthenticationError, GqlInputError } from '@/lib/error'
import { getWalletByType } from '@/wallets/common'
import { deleteVault, hasVault, vaultNewSchematoTypedef, vaultPrismaFragments } from '@/wallets/vault'
export default {
Query: {
getVaultEntries: async (parent, args, { me, models }) => {
if (!me) throw new GqlAuthenticationError()
const wallets = await models.wallet.findMany({
where: { userId: me.id },
include: vaultPrismaFragments.include()
})
const vaultEntries = []
for (const wallet of wallets) {
vaultEntries.push(...vaultNewSchematoTypedef(wallet).vaultEntries)
}
return vaultEntries
}
},
Mutation: {
// atomic vault migration
updateVaultKey: async (parent, { entries, hash }, { me, models }) => {
if (!me) throw new GqlAuthenticationError()
if (!hash) throw new GqlInputError('hash required')
const { vaultKeyHash: oldKeyHash } = await models.user.findUnique({ where: { id: me.id } })
if (oldKeyHash) {
if (oldKeyHash === hash) {
return true
}
throw new GqlInputError('vault key already set', E_VAULT_KEY_EXISTS)
}
return await models.$transaction(async tx => {
const wallets = await tx.wallet.findMany({ where: { userId: me.id } })
for (const wallet of wallets) {
const def = getWalletByType(wallet.type)
await tx.wallet.update({
where: { id: wallet.id },
data: {
[def.walletField]: {
update: vaultPrismaFragments.upsert({ ...wallet, vaultEntries: entries })
}
}
})
}
// optimistic concurrency control: make sure the user's vault key didn't change while we were updating the wallets
await tx.user.update({
where: { id: me.id, vaultKeyHash: oldKeyHash },
data: { vaultKeyHash: hash }
})
return true
})
},
clearVault: async (parent, args, { me, models }) => {
if (!me) throw new GqlAuthenticationError()
const txs = []
txs.push(models.user.update({
where: { id: me.id },
data: { vaultKeyHash: '' }
}))
const wallets = await models.wallet.findMany({ where: { userId: me.id } })
txs.push(...wallets.filter(hasVault).map(wallet => deleteVault(models, wallet)))
await models.$transaction(txs)
return true
}
}
}