From 67acbe0355fe444f65ed55e8f1344dd10553d82f Mon Sep 17 00:00:00 2001 From: Wukong Sun Date: Tue, 8 Apr 2025 15:04:11 +0800 Subject: [PATCH 1/2] fixup! fix: mf-6682 format datetime --- .../modals/RestoreBackupModal/RestoreBackupDialog.tsx | 2 +- .../pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx b/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx index facebb29f18d..cc509fb605b5 100644 --- a/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx +++ b/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx @@ -190,7 +190,7 @@ export const RestoreBackupDialog = memo(function Resto fontSize={12} lineHeight="16px" color={theme.palette.maskColor.third}> - {formatDateTime(new Date(Number(uploadedAt)), 'yyyy-mm-dd HH:mm')} + {formatDateTime(new Date(Number(uploadedAt)), 'yyyy-MM-dd hh:mm')} } diff --git a/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx b/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx index fcdb3b84fbd8..32c08372e813 100644 --- a/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx +++ b/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx @@ -125,14 +125,12 @@ export const Component = memo(function GoogleDriveRecovery() { selectable selectedFileId={selectedFile?.id} onSelect={setSelectedFile} - onDownload={downloadAndMerge} - onMerge={async (file) => { + onMerge={downloadAndMerge} + onDownload={async (file) => { const blob = await googleDriveClient.downloadFile(file.id) const url = URL.createObjectURL(blob) downloadBackup(url, file.name) - Promise.resolve().then(() => { - URL.revokeObjectURL(url) - }) + URL.revokeObjectURL(url) }} /> From 5fe1d424cdf8284c0f2c8e4784ae58dd45fb39d4 Mon Sep 17 00:00:00 2001 From: Wukong Sun Date: Wed, 9 Apr 2025 10:45:58 +0800 Subject: [PATCH 2/2] fix: mf-6688 do not encrypt/decrypt with account for google drive --- .../BackupPreviewDialog.tsx | 59 +++++++++++-------- .../RestoreBackupDialog.tsx | 20 +++++-- .../SetupPersona/Backup/Cloud/GoogleDrive.tsx | 10 ++-- .../SetupPersona/Backup/Cloud/Preview.tsx | 6 +- .../SetupPersona/CloudBackupPreview/index.tsx | 10 +--- .../Recovery/Cloud/GoogleDrive.tsx | 2 + 6 files changed, 60 insertions(+), 47 deletions(-) diff --git a/packages/mask/dashboard/modals/BackupPreviewModal/BackupPreviewDialog.tsx b/packages/mask/dashboard/modals/BackupPreviewModal/BackupPreviewDialog.tsx index 6c5e0ccc2f9b..2e0e7c2adfe7 100644 --- a/packages/mask/dashboard/modals/BackupPreviewModal/BackupPreviewDialog.tsx +++ b/packages/mask/dashboard/modals/BackupPreviewModal/BackupPreviewDialog.tsx @@ -5,7 +5,6 @@ import { Trans } from '@lingui/react/macro' import { encryptBackup } from '@masknet/backup-format' import { Icons } from '@masknet/icons' import { InjectedDialog, LoadingStatus } from '@masknet/shared' -import type { BackupAccountType } from '@masknet/shared-base' import { DashboardRoutes } from '@masknet/shared-base' import { ActionButton, makeStyles, useCustomSnackbar } from '@masknet/theme' import { encode } from '@msgpack/msgpack' @@ -14,7 +13,6 @@ import { memo, useCallback, useMemo, useRef } from 'react' import { Controller } from 'react-hook-form' import { useNavigate } from 'react-router-dom' import { useAsyncFn, useUpdateEffect } from 'react-use' -import { UserContext } from '../../../shared-ui/index.js' import { PersonasBackupPreview, WalletsBackupPreview } from '../../components/BackupPreview/index.js' import PasswordField from '../../components/PasswordField/index.js' import { useBackupFormState, type BackupFormInputs } from '../../hooks/useBackupFormState.js' @@ -59,10 +57,12 @@ const useStyles = makeStyles()((theme) => ({ export interface BackupPreviewDialogProps { open: boolean isUpload?: boolean - code: string - type: BackupAccountType account: string - abstract?: string + /** + * MaskNetwork backup use account + password as password since legacy version. + * Will be removed in the future when we remove MaskNetwork backup. + */ + encryptWithAccount: boolean title?: React.ReactNode | string uploadButtonLabel?: React.ReactNode | string onClose: () => void @@ -71,10 +71,8 @@ export interface BackupPreviewDialogProps { export const BackupPreviewDialog = memo(function BackupPreviewDialog({ open, isUpload, - code, - type, account, - abstract, + encryptWithAccount, title, uploadButtonLabel, onClose, @@ -84,7 +82,6 @@ export const BackupPreviewDialog = memo(function Backu const controllerRef = useRef(null) const { classes, theme } = useStyles() const navigate = useNavigate() - const { updateUser } = UserContext.useContainer() const { hasPassword, backupWallets, @@ -117,7 +114,8 @@ export const BackupPreviewDialog = memo(function Backu excludeWallet: !backupWallets, }) - const encrypted = await encryptBackup(encode(account + data.backupPassword), encode(file)) + const password = encryptWithAccount ? account + data.backupPassword : data.backupPassword + const encrypted = await encryptBackup(encode(password), encode(file)) const controller = new AbortController() controllerRef.current = controller await onUpload?.(encrypted, controller.signal) @@ -132,7 +130,18 @@ export const BackupPreviewDialog = memo(function Backu if ((error as any).status === 400) navigate(DashboardRoutes.BackupCloud, { replace: true }) } }, - [code, hasPassword, backupWallets, abstract, code, account, type, _, navigate, updateUser], + [ + backupWallets, + hasPassword, + encryptWithAccount, + account, + onUpload, + showSnackbar, + onClose, + setError, + _, + navigate, + ], ) const handleClose = useCallback(() => { @@ -207,19 +216,21 @@ export const BackupPreviewDialog = memo(function Backu : }, [ + uploadLoading, + classes.container, + classes.icon, loading, previewInfo, control, - _, - errors.backupPassword?.message, - errors.paymentPassword?.message, backupWallets, setBackupWallets, + hasPassword, isUpload, - theme, - value, - uploadLoading, - classes, + theme.palette.maskColor.danger, + _, + errors.backupPassword?.message, + errors.paymentPassword?.message, + clearErrors, ]) const action = useMemo(() => { @@ -246,18 +257,16 @@ export const BackupPreviewDialog = memo(function Backu ) }, [ - backupWallets, - isUpload, - isDirty, - isValid, - hasPassword, - backupWallets, value, + onClose, uploadLoading, handleClose, handleSubmit, handleUploadBackup, - onClose, + isUpload, + isDirty, + isValid, + uploadButtonLabel, ]) return ( diff --git a/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx b/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx index cc509fb605b5..ff321d8bf457 100644 --- a/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx +++ b/packages/mask/dashboard/modals/RestoreBackupModal/RestoreBackupDialog.tsx @@ -49,6 +49,11 @@ export interface RestoreBackupDialogProps { strategy?: 'import' | 'merge' restoreSuccessMessage?: ReactNode restoreErrorMessage?: ReactNode + /** + * MaskNetwork backup use account + password as password since legacy version. + * Will be removed in the future when we remove MaskNetwork backup. + */ + decryptWithAccount: boolean /** * A generator that yield progress of download, * and return the content of the downloaded file at the end @@ -61,6 +66,7 @@ export const RestoreBackupDialog = memo(function Resto open, fileName, account, + decryptWithAccount, uploadedAt, size, strategy = 'import', @@ -96,13 +102,14 @@ export const RestoreBackupDialog = memo(function Resto handleClose() throw err } - }, [handleClose, open, download]) + }, [open, download, showSnackbar, handleClose]) const isImport = strategy === 'import' const [{ loading }, handleRestore] = useAsyncFn(async () => { try { if (!encrypted) return - const decrypted = await decryptBackup(encode(account + backupPassword), encrypted) + const password = decryptWithAccount ? account + backupPassword : backupPassword + const decrypted = await decryptBackup(encode(password), encrypted) const backupJson = JSON.stringify(decode(decrypted)) const summary = await Services.Backup.generateBackupSummary(backupJson) if (summary.isErr()) { @@ -141,13 +148,14 @@ export const RestoreBackupDialog = memo(function Resto } }, [ encrypted, - backupPassword, + decryptWithAccount, account, - isImport, + backupPassword, showSnackbar, + isImport, restoreSuccessMessage, - restoreErrorMessage, onClose, + restoreErrorMessage, ]) return ( @@ -190,7 +198,7 @@ export const RestoreBackupDialog = memo(function Resto fontSize={12} lineHeight="16px" color={theme.palette.maskColor.third}> - {formatDateTime(new Date(Number(uploadedAt)), 'yyyy-MM-dd hh:mm')} + {formatDateTime(new Date(Number(uploadedAt)), 'yyyy-MM-dd HH:mm')} } diff --git a/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/GoogleDrive.tsx b/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/GoogleDrive.tsx index ed1507e9599b..493c6b3c621c 100644 --- a/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/GoogleDrive.tsx +++ b/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/GoogleDrive.tsx @@ -1,6 +1,6 @@ import { Trans } from '@lingui/react/macro' import { Icons } from '@masknet/icons' -import { BackupAccountType, EMPTY_LIST } from '@masknet/shared-base' +import { EMPTY_LIST } from '@masknet/shared-base' import { ActionButton, makeStyles } from '@masknet/theme' import { GoogleDriveClient, type DriveFile } from '@masknet/web3-providers' import { Box, Typography } from '@mui/material' @@ -89,7 +89,7 @@ export const Component = memo(function GoogleDriveBackup() { }) refetch() }, - [googleDriveClient], + [googleDriveClient, refetch], ) const [{ loading: logoutLoading }, logout] = useAsyncFn(async () => { @@ -98,7 +98,7 @@ export const Component = memo(function GoogleDriveBackup() { googleAccount: '', googleToken: '', }) - }, [googleDriveClient]) + }, [googleDriveClient, updateUser]) const mergedFiles = useMemo(() => uniqBy(compact([...files, uploadedFile]), (x) => x.id), [files, uploadedFile]) @@ -108,6 +108,7 @@ export const Component = memo(function GoogleDriveBackup() { const downloadAndMerge = async (file: DriveFile) => { await RestoreBackupModal.openAndWaitForClose({ + decryptWithAccount: false, strategy: 'merge', download: () => { return progressDownload(() => googleDriveClient.requestFile(file.id), file.size ? +file.size : 0) @@ -162,8 +163,7 @@ export const Component = memo(function GoogleDriveBackup() { onClick={() => { if (!user.googleAccount) return BackupPreviewModal.open({ - code: 'google-drive', - type: BackupAccountType.Email, + encryptWithAccount: false, account: user.googleAccount!, isUpload: true, title: Backup to Google Drive, diff --git a/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/Preview.tsx b/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/Preview.tsx index bd825d00501d..2d2dba5017f3 100644 --- a/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/Preview.tsx +++ b/packages/mask/dashboard/pages/SetupPersona/Backup/Cloud/Preview.tsx @@ -1,7 +1,6 @@ import { Trans } from '@lingui/react/macro' import { Icons } from '@masknet/icons' import { EmptyStatus, formatFileSize } from '@masknet/shared' -import type { BackupAccountType } from '@masknet/shared-base' import { DashboardRoutes } from '@masknet/shared-base' import { ActionButton, TextOverflowTooltip, makeStyles } from '@masknet/theme' import { Box, Button, Typography } from '@mui/material' @@ -84,6 +83,7 @@ export const Component = memo(function CloudBackupPreview() { const [{ loading: mergeLoading }, handleMergeClick] = useAsyncFn(async () => { if (!previewInfo.downloadLink || !previewInfo.account || !previewInfo.size || !previewInfo.uploadedAt) return await RestoreBackupModal.openAndWaitForClose({ + decryptWithAccount: true, strategy: 'merge', download: () => progressDownload(previewInfo.downloadLink), fileName: getFileName(previewInfo.downloadLink) || createBackupName(), @@ -96,10 +96,8 @@ export const Component = memo(function CloudBackupPreview() { const handleBackupClick = useCallback(() => { if (!previewInfo.type || !previewInfo.account || !previewInfo.code) return BackupPreviewModal.open({ + encryptWithAccount: true, isUpload: false, - code: previewInfo.code, - abstract: previewInfo.abstract ? previewInfo.abstract : undefined, - type: previewInfo.type as BackupAccountType, account: previewInfo.account, }) }, [previewInfo]) diff --git a/packages/mask/dashboard/pages/SetupPersona/CloudBackupPreview/index.tsx b/packages/mask/dashboard/pages/SetupPersona/CloudBackupPreview/index.tsx index 474f6f1e0b83..48fd170f185c 100644 --- a/packages/mask/dashboard/pages/SetupPersona/CloudBackupPreview/index.tsx +++ b/packages/mask/dashboard/pages/SetupPersona/CloudBackupPreview/index.tsx @@ -1,7 +1,6 @@ import { Trans } from '@lingui/react/macro' import { Icons } from '@masknet/icons' import { EmptyStatus, formatFileSize } from '@masknet/shared' -import type { BackupAccountType } from '@masknet/shared-base' import { DashboardRoutes } from '@masknet/shared-base' import { ActionButton, TextOverflowTooltip, makeStyles } from '@masknet/theme' import { Box, Typography } from '@mui/material' @@ -79,6 +78,7 @@ export const Component = memo(function CloudBackupPreview() { ) return await RestoreBackupModal.openAndWaitForClose({ + decryptWithAccount: true, strategy: 'merge', download: () => progressDownload(previewInfo.downloadLink), fileName: getFileName(previewInfo.downloadLink) || createBackupName(), @@ -91,10 +91,8 @@ export const Component = memo(function CloudBackupPreview() { const handleBackupClick = useCallback(() => { if (!previewInfo.type || !previewInfo.account || !previewInfo.code) return BackupPreviewModal.open({ + encryptWithAccount: true, isUpload: false, - code: previewInfo.code, - abstract: previewInfo.abstract ? previewInfo.abstract : undefined, - type: previewInfo.type as BackupAccountType, account: previewInfo.account, }) }, [previewInfo]) @@ -113,10 +111,8 @@ export const Component = memo(function CloudBackupPreview() { if (!previewInfo.type || !previewInfo.account || !previewInfo.code) return BackupPreviewModal.open({ + encryptWithAccount: true, isUpload: true, - code: previewInfo.code, - abstract: previewInfo.abstract ? previewInfo.abstract : undefined, - type: previewInfo.type as BackupAccountType, account: previewInfo.account, }) }, diff --git a/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx b/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx index 32c08372e813..bbe895fd8b21 100644 --- a/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx +++ b/packages/mask/dashboard/pages/SetupPersona/Recovery/Cloud/GoogleDrive.tsx @@ -88,6 +88,7 @@ export const Component = memo(function GoogleDriveRecovery() { const downloadAndMerge = async (file: DriveFile) => { await RestoreBackupModal.openAndWaitForClose({ + decryptWithAccount: false, strategy: 'merge', download: () => { return progressDownload(() => googleDriveClient.requestFile(file.id), file.size ? +file.size : 0) @@ -144,6 +145,7 @@ export const Component = memo(function GoogleDriveRecovery() { onClick={async () => { if (!user.googleAccount || !selectedFile?.id) return const result = await RestoreBackupModal.openAndWaitForClose({ + decryptWithAccount: false, download: () => { return progressDownload( () => googleDriveClient.requestFile(selectedFile.id),