Skip to content

Commit

Permalink
feat: encrypet mnemonic
Browse files Browse the repository at this point in the history
  • Loading branch information
AricRedemption committed Sep 3, 2024
1 parent 3f21e55 commit 69e4466
Show file tree
Hide file tree
Showing 17 changed files with 268 additions and 253 deletions.
31 changes: 10 additions & 21 deletions src/components/ResetModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import useStorage from '@/lib/storage'
import { PASSWORD_KEY } from '@/lib/password'
import { Checkbox } from '@/components/ui/checkbox'
import { XMarkIcon } from '@heroicons/vue/20/solid'
import { V3_WALLETS_STORAGE_KEY } from '@/lib/storage/key'
import { V3_ENCRYPTED_WALLETS_STORAGE_KEY } from '@/lib/storage/key'
defineProps<{
show: boolean
Expand All @@ -24,7 +24,7 @@ const checkedAll = computed(() => checked1.value && checked2.value && checked3.v
const disconnect = async () => {
emit('update:show', false)
await storage.delete(PASSWORD_KEY)
await storage.delete(V3_WALLETS_STORAGE_KEY)
await storage.delete(V3_ENCRYPTED_WALLETS_STORAGE_KEY)
window.location.reload()
}
Expand All @@ -44,10 +44,8 @@ const close = () => {
<Teleport to="main" v-if="show">
<div class="absolute inset-0 isolate z-50 flex items-end bg-black/20 backdrop-blur-sm flex-col overflow-hidden">
<div class="grow w-full" @click="close"></div>
<div
:data-state="modalState"
class="data-[state=open]:animate-drawer-modal-up data-[state=closed]:animate-drawer-modal-down"
>
<div :data-state="modalState"
class="data-[state=open]:animate-drawer-modal-up data-[state=closed]:animate-drawer-modal-down">
<div class="rounded-t-xl bg-white p-4 pb-8">
<div class="flex items-center justify-between border-b border-gray-100 pb-4">
<span class="text-base">Reset Wallet</span>
Expand Down Expand Up @@ -83,27 +81,18 @@ const close = () => {
To confirm wallet reset, please enter:
<span class="text-red-500">RESET</span>
</p>
<input
type="text"
class="w-full rounded-lg focus:outline-blue-primary border p-4 text-sm"
v-model="resetText"
placeholder="RESET"
/>
<input type="text" class="w-full rounded-lg focus:outline-blue-primary border p-4 text-sm"
v-model="resetText" placeholder="RESET" />
</div>

<div class="flex items-center justify-center gap-2">
<button
class="w-30 h-12 bg-blue-light text-blue-primary rounded-3xl text-ss"
@click="$emit('update:show', false)"
>
<button class="w-30 h-12 bg-blue-light text-blue-primary rounded-3xl text-ss"
@click="$emit('update:show', false)">
Cancel
</button>
<button
@click="disconnect"
:disabled="!checkedAll"
<button @click="disconnect" :disabled="!checkedAll"
class="w-30 h-12 bg-red-600 text-white rounded-3xl text-ss"
:class="[checkedAll ? 'cursor-pointer' : 'cursor-not-allowed opacity-50 saturate-50']"
>
:class="[checkedAll ? 'cursor-pointer' : 'cursor-not-allowed opacity-50 saturate-50']">
Reset
</button>
</div>
Expand Down
14 changes: 12 additions & 2 deletions src/lib/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { fetchUtxos } from '@/queries/utxos'
import { notifyContent } from '@/lib/notify-content'
import { generateRandomString } from '@/lib/helpers'
import { getBtcNetwork, getNetwork } from '@/lib/network'
import { getActiveWalletOnlyAccount, getCurrentWallet } from './wallet'
import { getActiveWalletOnlyAccount, getCurrentWallet, getV3EncryptedWallets } from './wallet'
import type { V1Account, V2Account, Chain, ChainDetail } from './types'
import { ScriptType, Chain as UtxoChain } from '@metalet/utxo-wallet-service'
import { fetchSpaceBalance, fetchBtcBalance, doNothing } from '@/queries/balance'
Expand Down Expand Up @@ -128,7 +128,17 @@ export async function getAccount(accountId: string): Promise<V2Account | undefin
}

export async function getCurrentAccountId() {
return await storage.get(CURRENT_ACCOUNT_ID)
const currentAccountId = await storage.get(CURRENT_ACCOUNT_ID)
if (!currentAccountId) {
const wallets = await getV3EncryptedWallets()
if (wallets.length && wallets[0].accounts.length) {
await setCurrentAccountId(wallets[0].accounts[0].id)
return wallets[0].accounts[0].id
} else {
throw new Error('current account id not found')
}
}
return currentAccountId
}

export async function setCurrentAccountId(accountId: string) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,7 @@ export function decrypt(encryptedText: string, password: string) {
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
return decryptedStr.toString()
}

export function hashWithSha256(data: string) {
return CryptoJS.SHA256(data).toString()
}
14 changes: 5 additions & 9 deletions src/lib/lock.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import useStorage from './storage'
import { IS_DEV } from '@/data/config'
import { notifyBg } from './notify-bg'
import usePasswordStore from '@/stores/PasswordStore'
import { checkPassword, hasPassword } from './password'
import { checkPassword, hasPassword, getEncryptedPassword } from './password'

const storage = useStorage()
const { password, setPassword } = usePasswordStore()

const LOCK_KEY = 'locked'
const LAST_LOCK_TIME_KEY = 'LAST_LOCK_TIME'
Expand All @@ -27,9 +25,7 @@ export async function unlock(password: string) {
if (!isCorrect) {
throw new Error('Password incorrect')
}
if (IS_DEV) {
setPassword(password)
} else {
if (!IS_DEV) {
await notifyBg('setPassword')(password)
}
await storage.set(LOCK_KEY, false)
Expand All @@ -50,10 +46,10 @@ export async function setLastLockTime() {
return await storage.set(LAST_LOCK_TIME_KEY, Date.now())
}

export async function getPassword() {
export async function getPassword():Promise<string> {
if (IS_DEV) {
return password.value
return (await getEncryptedPassword()) || ''
} else {
return await notifyBg('getPassword')()
return (await notifyBg('getPassword')()) || ''
}
}
89 changes: 67 additions & 22 deletions src/lib/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
getLegacyAccounts,
getCurrentAccountId,
} from './account'
import { getPassword } from './lock'

const storage = useStorage()

Expand Down Expand Up @@ -125,7 +126,11 @@ async function needEncryptV3(): Promise<boolean> {
}
const v3Wallets = await getV3Wallets()
const v3EncryptedWallets = await getV3EncryptedWallets()
const needed = v3Wallets.some((mne) => !v3EncryptedWallets.includes(mne))
const v3EncryptedMnemonics = v3EncryptedWallets.map((encryptedWallet) => encryptedWallet.mnemonic)
const password = await getPassword()
const needed = v3Wallets.some((wallet) => !v3EncryptedMnemonics.includes(encrypt(wallet.mnemonic, password)))

console.log('needEncryptV3', needed)

if (!needed) {
await storage.set(ACCOUNT_V3_Encrypted_KEY, true)
Expand Down Expand Up @@ -339,7 +344,9 @@ export async function migrateToV2() {
}

export async function needMigrate() {
return (await needMigrateV1ToV2()) || (await needMigrateV0ToV2()) || (await needMigrateV2ToV3())
return (
(await needMigrateV1ToV2()) || (await needMigrateV0ToV2()) || (await needMigrateV2ToV3()) || (await needEncryptV3())
)
}

async function migrateV2ToV3(): Promise<MigrateResult> {
Expand Down Expand Up @@ -467,44 +474,82 @@ async function migrateV2ToV3(): Promise<MigrateResult> {
}

export async function migrateToV3() {
const title = 'Migrate V2 account'
const { code, message: description } = await migrateV2ToV3()
if (code === MigrateResultCode.FAILED) {
toast({ title, toastType: 'fail', description })
} else if (code === MigrateResultCode.SUCCESS) {
toast({ title, toastType: 'success', description })
} else if (code === MigrateResultCode.UNDO) {
toast({ title, toastType: 'info', description })
if (await needMigrateV2ToV3()) {
const title = 'Migrate V2 account'
const { code, message: description } = await migrateV2ToV3()
if (code === MigrateResultCode.FAILED) {
toast({ title, toastType: 'fail', description })
} else if (code === MigrateResultCode.SUCCESS) {
toast({ title, toastType: 'success', description })
} else if (code === MigrateResultCode.UNDO) {
toast({ title, toastType: 'info', description })
}
}
}

async function encryptV3Accounts(password: string) {
async function encryptV3Accounts(): Promise<MigrateResult> {
const v3Wallets = await getV3Wallets()
const v3EncryptedWallets = await getV3EncryptedWallets()

const encryptedMnemonics = new Set(v3EncryptedWallets.map((wallet) => wallet.mnemonic))

let totalEncryptions = v3Wallets.length
let successfulEncryptions = 0
let alreadyEncryptedCount = 0
let failedEncryptions = 0

const password = await getPassword()

v3Wallets.forEach((wallet) => {
if (!encryptedMnemonics.has(wallet.mnemonic)) {
v3EncryptedWallets.push({ ...wallet, mnemonic: encrypt(wallet.mnemonic, password) })
try {
if (!encryptedMnemonics.has(encrypt(wallet.mnemonic, password))) {
v3EncryptedWallets.push({ ...wallet, mnemonic: encrypt(wallet.mnemonic, password) })
successfulEncryptions++
} else {
alreadyEncryptedCount++
}
} catch (e: any) {
addMigrateErrorAccount(wallet.mnemonic, JSON.stringify(wallet), 'V3', e)
failedEncryptions++
}
})

setV3EncryptedWalletsStorage(
v3EncryptedWallets.reduce<Record<string, V3Wallet>>((acc, wallet) => {
acc[wallet.id] = wallet
return acc
}, {})
)
}

export async function encryptV2Accounts(password: string): Promise<void> {
const v2Accounts = await getV2AccountsObj()
console.log('v2Accounts', v2Accounts)
let code = MigrateResultCode.UNDO
if (failedEncryptions === totalEncryptions) {
code = MigrateResultCode.FAILED
} else if (successfulEncryptions > 0 && failedEncryptions === 0) {
code = MigrateResultCode.SUCCESS
}

const encryptedText = encrypt(JSON.stringify(v2Accounts), password)
console.log('encryptedText', encryptedText)
return {
code,
message: `
Encryption Summary:\n
- Total Wallets Processed: ${totalEncryptions}\n
- Successful Encryptions: ${successfulEncryptions}\n
- Already Encrypted Wallets: ${alreadyEncryptedCount}\n
- Failed Encryptions: ${failedEncryptions}
`,
}
}

const decryptedText = decrypt(encryptedText, password)
console.log('decryptedText', decryptedText)
console.log('JSON decryptedText', JSON.parse(decryptedText))
export async function migrateToV3Encrypted() {
if (await needEncryptV3()) {
const title = 'Encrypt V3 wallet'
const { code, message: description } = await encryptV3Accounts()
if (code === MigrateResultCode.FAILED) {
toast({ title, toastType: 'fail', description })
} else if (code === MigrateResultCode.SUCCESS) {
toast({ title, toastType: 'success', description })
} else if (code === MigrateResultCode.UNDO) {
toast({ title, toastType: 'info', description })
}
}
}
1 change: 1 addition & 0 deletions src/lib/storage/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export const WALLET_NUM = 'wallet_num'
export const CURRENT_WALLET_ID = 'currentWalletId'
export const V3_WALLETS_STORAGE_KEY = 'wallets_v3'
export const V3_ENCRYPTED_WALLETS_STORAGE_KEY = 'encrypted_wallets_v3'
export const V3_ENCRYPTED_WALLETS_STORAGE_BACKUP_KEY = 'encrypted_wallets_v3_backup'
Loading

0 comments on commit 69e4466

Please sign in to comment.