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

Encrypted device sync #1373

Merged
merged 72 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
44604bc
user vault
riccardobl Sep 7, 2024
071a67a
code cleanup and fixes
riccardobl Sep 7, 2024
0cfbbca
improve ui
riccardobl Sep 7, 2024
4f3fbee
prevent name collisions between users on the same device
riccardobl Sep 7, 2024
33128cf
some improvements
riccardobl Sep 8, 2024
f23f750
implement storage migration
riccardobl Sep 9, 2024
99db743
comments and cleanup
riccardobl Sep 9, 2024
aded982
make connect button primary instead of warning
riccardobl Sep 9, 2024
f17cb6c
move show passphrase in new line (improvement for small screen devices)
riccardobl Sep 9, 2024
730ce9e
Merge branch 'master' into uservault
riccardobl Sep 9, 2024
6ed9cfa
Merge branch 'master' into pr/1373
ekzyis Sep 11, 2024
efbcac3
make show passphrase field readOnly
riccardobl Sep 13, 2024
93e6bd4
fixes
riccardobl Sep 19, 2024
41a0c6b
fix vault key unsync
riccardobl Sep 19, 2024
d9b7277
implicit migration
riccardobl Sep 19, 2024
9213770
move device sync under general tab
riccardobl Sep 19, 2024
8031bc3
fix locally disabled wallets and default wallet selection
riccardobl Sep 19, 2024
49b4a71
improve text
riccardobl Sep 19, 2024
4b73171
remove useless SSR check
riccardobl Sep 19, 2024
8fcc7c5
Merge branch 'master' into uservault
ekzyis Sep 20, 2024
1ed8c2a
add auth checks
riccardobl Sep 20, 2024
8327269
Merge branch 'master' into uservault
riccardobl Sep 21, 2024
79e1821
Rename variables
ekzyis Sep 20, 2024
51d8272
Fix missing await
ekzyis Sep 20, 2024
d03fda2
Refactor local<>vault storage interface
ekzyis Sep 20, 2024
d2450e9
Fix missing dependency for useZap
ekzyis Sep 21, 2024
afad3e4
Assume JSON during encryption and decryption
ekzyis Sep 22, 2024
7cf0466
Fix stale value from cache served on next fetches
ekzyis Sep 22, 2024
bc0fde5
Add wallet.perDevice field
ekzyis Sep 22, 2024
330b7a6
Remove debug buttons
ekzyis Sep 22, 2024
3015e8e
Rename userVault -> vault
ekzyis Sep 22, 2024
34c492d
Update console.log's
ekzyis Sep 22, 2024
d982c96
revert some of the migration and key handling changes. restore debug …
riccardobl Sep 22, 2024
253373f
Fix existing wallets not loaded
ekzyis Sep 23, 2024
c737845
Pass in localOnly and generate localStorageKey once
ekzyis Sep 23, 2024
59c8f1c
Small refactor of migration
ekzyis Sep 23, 2024
8631bc2
Fix wallet drag and drop
ekzyis Sep 24, 2024
2a283f5
Add passphrase copy button
ekzyis Sep 24, 2024
7f437ac
Fix priorityOnly -> skipTests
ekzyis Sep 24, 2024
bc5bc8c
Disable autocompletion for reset confirmation prompt
ekzyis Sep 24, 2024
6361e93
Show wrong passphrase as input error
ekzyis Sep 24, 2024
92b987d
Move code into components/device-sync.js
ekzyis Sep 24, 2024
213f652
Import/export passphrase via QR code
ekzyis Sep 24, 2024
fa0c066
Fix modal back button invisible in light mode
ekzyis Sep 24, 2024
9653ec0
Fix modal closed even on connect error
ekzyis Sep 24, 2024
f8ce344
Use me-2 for cancel/close button
ekzyis Sep 24, 2024
472c559
Some rephrasing
ekzyis Sep 24, 2024
d40d997
Fix wallet detach
ekzyis Sep 24, 2024
2a880fa
Merge branch 'master' into uservault
ekzyis Sep 24, 2024
6a6981f
Remove debug buttons
ekzyis Sep 24, 2024
7907cdf
Fix QR code scan in dark mode
ekzyis Sep 24, 2024
f0a27f7
Don't allow custom passphrases
ekzyis Sep 25, 2024
4dbcde3
More rephrasing
ekzyis Sep 25, 2024
2a1c24b
Only use schema if not enabled
ekzyis Sep 25, 2024
418bd0c
Fix typo in comment
ekzyis Sep 25, 2024
a922010
Replace 'generate passphrase' button with reload icon
ekzyis Sep 28, 2024
614a1cc
Add comment about IV reuse in GCM
ekzyis Sep 28, 2024
e56e530
Use 600k iterations as recommended by OWASP
ekzyis Sep 28, 2024
7b0fbf2
Set extractable to false where not needed
ekzyis Sep 28, 2024
07ba619
use-vault fallbacks to local storage only for anonymous users
riccardobl Sep 30, 2024
0688b07
fix localStorage reset on logout
riccardobl Sep 30, 2024
7f1efe4
Merge branch 'master' into uservault
huumn Sep 30, 2024
b019e69
add copy button
riccardobl Oct 1, 2024
b26c578
move reset out of modals
riccardobl Oct 1, 2024
98089bd
hide server side errors
riccardobl Oct 1, 2024
b181916
hardened passphrase storage
riccardobl Oct 1, 2024
08c8996
do not show passphrase even if hardened storage is disabled (ie. inde…
riccardobl Oct 1, 2024
6bf5ff2
show qr code button on passphrase creation
riccardobl Oct 1, 2024
7fb3a5b
use toast for serverside error
riccardobl Oct 1, 2024
ada65bc
Move key (de)serialization burden to get/setLocalKey functions
riccardobl Oct 1, 2024
3908547
password textarea and remove qr
huumn Oct 1, 2024
1e5ca82
don't print plaintext vault values into console
huumn Oct 1, 2024
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
3 changes: 2 additions & 1 deletion api/resolvers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import chainFee from './chainFee'
import { GraphQLScalarType, Kind } from 'graphql'
import { createIntScalar } from 'graphql-scalar'
import paidAction from './paidAction'
import vault from './vault'

const date = new GraphQLScalarType({
name: 'Date',
Expand Down Expand Up @@ -55,4 +56,4 @@ const limit = createIntScalar({

export default [user, item, message, wallet, lnurl, notifications, invite, sub,
upload, search, growth, rewards, referrals, price, admin, blockHeight, chainFee,
{ JSONObject }, { Date: date }, { Limit: limit }, paidAction]
{ JSONObject }, { Date: date }, { Limit: limit }, paidAction, vault]
115 changes: 115 additions & 0 deletions api/resolvers/vault.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { E_VAULT_KEY_EXISTS, GqlAuthenticationError, GqlInputError } from '@/lib/error'

export default {
Query: {
getVaultEntry: async (parent, { key }, { me, models }) => {
if (!me) {
throw new GqlAuthenticationError()
}
if (!key) {
throw new GqlInputError('must have key')
}
const k = await models.vault.findUnique({
where: {
userId_key: {
key,
userId: me.id
}
}
})
return k
}
},

Mutation: {
setVaultKeyHash: async (parent, { 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) {
throw new GqlInputError('vault key already set', E_VAULT_KEY_EXISTS)
} else {
return true
}
} else {
await models.user.update({
where: { id: me.id },
data: { vaultKeyHash: hash }
})
}
return true
},
setVaultEntry: async (parent, { key, value, skipIfSet }, { me, models }) => {
if (!me) {
throw new GqlAuthenticationError()
}
if (!key) {
throw new GqlInputError('must have key')
}
if (!value) {
throw new GqlInputError('must have value')
}
if (skipIfSet) {
const existing = await models.vault.findUnique({
where: {
userId_key: {
userId: me.id,
key
}
}
})
if (existing) {
return false
}
}
await models.vault.upsert({
where: {
userId_key: {
userId: me.id,
key
}
},
update: {
value
},
create: {
key,
value,
userId: me.id
}
})
return true
},
unsetVaultEntry: async (parent, { key }, { me, models }) => {
if (!me) {
throw new GqlAuthenticationError()
}
if (!key) {
throw new GqlInputError('must have key')
}
await models.vault.deleteMany({
where: {
userId: me.id,
key
}
})
return true
},
clearVault: async (parent, args, { me, models }) => {
if (!me) {
throw new GqlAuthenticationError()
}
await models.user.update({
where: { id: me.id },
data: { vaultKeyHash: '' }
})
await models.vault.deleteMany({ where: { userId: me.id } })
return true
}
}
}
3 changes: 2 additions & 1 deletion api/typeDefs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import admin from './admin'
import blockHeight from './blockHeight'
import chainFee from './chainFee'
import paidAction from './paidAction'
import vault from './vault'

const common = gql`
type Query {
Expand All @@ -38,4 +39,4 @@ const common = gql`
`

export default [common, user, item, itemForward, message, wallet, lnurl, notifications, invite,
sub, upload, growth, rewards, referrals, price, admin, blockHeight, chainFee, paidAction]
sub, upload, growth, rewards, referrals, price, admin, blockHeight, chainFee, paidAction, vault]
1 change: 1 addition & 0 deletions api/typeDefs/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export default gql`
withdrawMaxFeeDefault: Int!
autoWithdrawThreshold: Int
autoWithdrawMaxFeePercent: Float
vaultKeyHash: String
}

type UserOptional {
Expand Down
22 changes: 22 additions & 0 deletions api/typeDefs/vault.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { gql } from 'graphql-tag'

export default gql`
type Vault {
id: ID!
key: String!
value: String!
createdAt: Date!
updatedAt: Date!
}

extend type Query {
getVaultEntry(key: String!): Vault
}

extend type Mutation {
setVaultEntry(key: String!, value: String!, skipIfSet: Boolean): Boolean
unsetVaultEntry(key: String!): Boolean
clearVault: Boolean
setVaultKeyHash(hash: String!): String
}
`
2 changes: 1 addition & 1 deletion components/cancel-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Button from 'react-bootstrap/Button'
export default function CancelButton ({ onClick }) {
const router = useRouter()
return (
<Button className='me-4 text-muted nav-link fw-bold' variant='link' onClick={onClick || (() => router.back())}>cancel</Button>
<Button className='me-2 text-muted nav-link fw-bold' variant='link' onClick={onClick || (() => router.back())}>cancel</Button>
)
}
Loading
Loading