Skip to content

Commit

Permalink
fix: vault export
Browse files Browse the repository at this point in the history
  • Loading branch information
pwltr committed Mar 20, 2023
1 parent fa55c3a commit c6245de
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ build = "src/build.rs"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
otp = { git = "https://github.com/TimDumol/rust-otp" }
tauri = { version = "1.2.4", features = ["clipboard-write-text", "fs-all", "path-all", "shell-open", "updater"] }
tauri = { version = "1.2.4", features = ["clipboard-write-text", "dialog-open", "dialog-save", "fs-all", "path-all", "shell-open", "updater"] }
tauri-plugin-stronghold = { path = "../tauri-plugin-stronghold" }

[build-dependencies]
Expand Down
5 changes: 5 additions & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
"clipboard": {
"writeText": true
},
"dialog": {
"all": false,
"open": true,
"save": true
},
"shell": {
"execute": false,
"open": true
Expand Down
8 changes: 3 additions & 5 deletions src/components/Codes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const Codes = () => {

const generateTokens = async (items: ListEntry[]) => {
const promises = items.map((item) => generateTOTP(item.secret))
const tokens = (await Promise.all(promises)) as string[]
const tokens = await Promise.all(promises)
const itemsWithTokens = items.map((item, index) => ({
...item,
issuer: tokens[index] ? item.issuer : t('codes.invalid'),
Expand Down Expand Up @@ -102,12 +102,10 @@ const Codes = () => {
const reset = () => {
// set normal interval
setDelay(INTERVAL_STANDARD)

// reset progressbar
setAnimate(false)

setTimeout(() => {
setAnimate(true)
}, 0)
setTimeout(() => setAnimate(true), 10)
}

if (isLoading) {
Expand Down
6 changes: 3 additions & 3 deletions src/components/Import.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ const Import = () => {
const handleExportVault = async () => {
try {
await exportCodes()
toast.success(t('toasts.exported'))
toast.success(t('toasts.exportSuccess'))
} catch (err) {
console.error(err)
toast.error(t('toasts.emptyExport'))
const error = err as Error
toast.error(t(`toasts.${error.message}`))
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/components/modals/Reset.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import toast from 'react-hot-toast'
import Button from '@mui/material/Button'
Expand All @@ -7,6 +8,7 @@ import { useLocalStorage } from '~/hooks'
import Modal, { Buttons } from '~/components/Modal'

const ResetModal = ({ open, onClose }: { open: boolean; onClose: () => void }) => {
const navigate = useNavigate()
const { t } = useTranslation()
const [, setIsPasswordSet] = useLocalStorage('isPasswordSet', false)

Expand All @@ -17,6 +19,7 @@ const ResetModal = ({ open, onClose }: { open: boolean; onClose: () => void }) =
setIsPasswordSet(false)
toast.success(t('toasts.reset'))
onClose()
navigate('/')
} catch (err) {
console.error(err)
toast.error(t('toasts.error'))
Expand Down
6 changes: 4 additions & 2 deletions src/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@
"toasts": {
"copied": "In Zwischenablage kopiert",
"imported": "Tresor erfolgreich importiert",
"exported": "Tresor exportiert.",
"emptyExport": "Tresor ist leer.",
"exportSuccess": "Tresor exportiert.",
"exportEmpty": "Tresor ist leer.",
"exportCancelled": "Export abgebrochen.",
"exportFailed": "Export fehlgeschlagen.",
"passwordSet": "Passwort aktualisiert.",
"passwordReset": "Passwortschutz entfernt.",
"reset": "Tresor gelöscht.",
Expand Down
6 changes: 4 additions & 2 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@
"toasts": {
"copied": "Copied to clipboard",
"imported": "Vault imported successfully",
"exported": "Vault exported.",
"emptyExport": "Vault is empty.",
"exportSuccess": "Vault exported.",
"exportEmpty": "Vault is empty.",
"exportCancelled": "Export cancelled.",
"exportFailed": "Export failed.",
"passwordSet": "Password changed.",
"passwordReset": "Password protection removed.",
"reset": "Vault reset.",
Expand Down
38 changes: 20 additions & 18 deletions src/utils/codes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ChangeEvent } from 'react'
import { save } from '@tauri-apps/api/dialog'
import { invoke } from '@tauri-apps/api/tauri'
import { writeTextFile } from '@tauri-apps/api/fs'

import { vault } from '~/App'
import { generateUUID } from '~/utils'
Expand All @@ -9,7 +11,7 @@ export type ImportFormat = 'aegis' | 'authy' | 'google' | 'tauthy'

export const generateTOTP = async (secret: string) => {
try {
return await invoke('generate_totp', { argument: secret })
return await invoke<string>('generate_totp', { argument: secret })
} catch (err) {
console.error('error from backend:', err)
}
Expand Down Expand Up @@ -131,13 +133,9 @@ export const exportCodes = async () => {
const entries = await vault.getVault()

if (entries.length === 0) {
throw Error('Nothing to export')
throw Error('exportEmpty')
}

const file = new Blob([JSON.stringify(entries)], {
type: 'application/json',
})

const date = new Date(Date.now())
.toLocaleDateString('en-US', {
year: '2-digit',
Expand All @@ -146,18 +144,22 @@ export const exportCodes = async () => {
})
.replace(/[^\w\s]/gi, '')

const file = JSON.stringify(entries)
const fileName = `tauthy_export_${date}.json`
// TODO: add error handling
downloadFile(file, fileName)
// TODO: return file path
return 'Vault exported'
}
const filePath = await save({
defaultPath: fileName,
filters: [{ name: 'JSON', extensions: ['json'] }],
})

if (!filePath) {
throw Error('exportCancelled')
}

try {
await writeTextFile(filePath, file)
} catch (err) {
throw Error('exportFailed')
}

export const downloadFile = (file: Blob, name: string) => {
const a = document.createElement('a')
a.href = URL.createObjectURL(file)
a.download = name
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
return 'exportSuccess'
}
9 changes: 9 additions & 0 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,12 @@ export const imageToBase64 = (url: string) => {
.then((response) => response.arrayBuffer())
.then(base64ToBrowser)
}

export const downloadFile = (file: Blob, name: string) => {
const a = document.createElement('a')
a.href = URL.createObjectURL(file)
a.download = name
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}

0 comments on commit c6245de

Please sign in to comment.