diff --git a/src/components/dapp/dapp-approval-drawer.tsx b/src/components/dapp/dapp-approval-drawer.tsx
index 9b6b816..c4c697c 100644
--- a/src/components/dapp/dapp-approval-drawer.tsx
+++ b/src/components/dapp/dapp-approval-drawer.tsx
@@ -35,6 +35,7 @@ import {
import AddressLabel from '@/components/address-label'
import { useTxTypeDescription } from '@/hooks/use-tx-type-description'
import { isWalletLocked } from '@/lib/lock'
+import IdnWarningBadge from '@/components/idn-warning-badge'
import { validateVaultPassphrase } from '@/lib/vault'
import { toast } from 'sonner'
@@ -72,7 +73,9 @@ const DappApprovalDrawer = () => {
useEffect(() => {
const syncLockState = () => {
- setLocked(isWalletLocked())
+ const nowLocked = isWalletLocked()
+ if (nowLocked) setPassphrase('')
+ setLocked(nowLocked)
}
syncLockState()
@@ -286,6 +289,7 @@ const DappApprovalDrawer = () => {
{t('dapp.approval.origin')}
diff --git a/src/components/idn-warning-badge.tsx b/src/components/idn-warning-badge.tsx
new file mode 100644
index 0000000..c737320
--- /dev/null
+++ b/src/components/idn-warning-badge.tsx
@@ -0,0 +1,18 @@
+import { TriangleAlertIcon } from 'lucide-react'
+import { useTranslation } from 'react-i18next'
+import { hasIdnHostname } from '@/lib/utils'
+
+type Props = { origin: string }
+
+const IdnWarningBadge = ({ origin }: Props) => {
+ const { t } = useTranslation()
+ if (!hasIdnHostname(origin)) return null
+ return (
+
+
+ {t('dapp.idnWarning')}
+
+ )
+}
+
+export default IdnWarningBadge
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index f4f9db5..cc3f273 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -149,6 +149,15 @@ export const formatAddressLabel = (
return `${name} (${truncated})`
}
+export const hasIdnHostname = (origin: string): boolean => {
+ try {
+ const { hostname } = new URL(origin)
+ return hostname.includes('xn--') || /[^a-z0-9.-]/i.test(hostname)
+ } catch {
+ return false
+ }
+}
+
export type ExplorerObject = 'tx'
export const compareBigIntDesc = (a: string, b: string): number => {
diff --git a/src/locales/en.json b/src/locales/en.json
index be160e0..154aa88 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -471,6 +471,7 @@
"importVault": "Import vault backup"
},
"dapp": {
+ "idnWarning": "Internationalized domain",
"approval": {
"title": "Connection request",
"connectTitle": "Connection request",
diff --git a/src/pages/manage-accounts.tsx b/src/pages/manage-accounts.tsx
index 823c6ba..2ed267b 100644
--- a/src/pages/manage-accounts.tsx
+++ b/src/pages/manage-accounts.tsx
@@ -22,6 +22,7 @@ import {
repairDuplicateVaultEntries,
setOnboarded,
} from '@/lib/vault'
+import { isWalletLocked } from '@/lib/lock'
import AccountListItem from '@/components/pages/manage-accounts/account-list-item'
import AddAccountDrawer from '@/components/pages/manage-accounts/add-account-drawer'
import RenameAccountDrawer from '@/components/pages/manage-accounts/rename-account-drawer'
@@ -126,6 +127,19 @@ const ManageAccounts = () => {
}
}, [refreshFromCache])
+ useEffect(() => {
+ const onLock = () => {
+ if (!isWalletLocked()) return
+ setRevealedSeed('')
+ setSeedTarget(null)
+ setPassphraseInput('')
+ setPassphrasePromptOpen(false)
+ setPendingAction(null)
+ }
+ window.addEventListener('wallet-lock-updated', onLock)
+ return () => window.removeEventListener('wallet-lock-updated', onLock)
+ }, [])
+
const balanceQueries = useQueries({
queries: orderedAccounts.map((account) => ({
queryKey: ['qubic', 'balance', account.identity],
diff --git a/src/pages/onboarding/create-wallet.tsx b/src/pages/onboarding/create-wallet.tsx
index e19f06a..71f881b 100644
--- a/src/pages/onboarding/create-wallet.tsx
+++ b/src/pages/onboarding/create-wallet.tsx
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { generateSeed, isSeedLike } from '@/lib/seed'
import { validatePassphraseStrength } from '@/lib/passphrase'
-import { setUnlocked } from '@/lib/lock'
+import { isWalletLocked, setUnlocked } from '@/lib/lock'
import {
openBrowserVault,
setOnboarded,
@@ -63,6 +63,18 @@ const CreateWallet = ({
setHasConfirmedSeedBackup(false)
}
+ useEffect(() => {
+ const onLock = () => {
+ if (!isWalletLocked()) return
+ setSeed('')
+ setPassphrase('')
+ setConfirmPassphrase('')
+ setHasConfirmedSeedBackup(false)
+ }
+ window.addEventListener('wallet-lock-updated', onLock)
+ return () => window.removeEventListener('wallet-lock-updated', onLock)
+ }, [])
+
useEffect(() => {
let isActive = true
diff --git a/src/pages/onboarding/import-seed.tsx b/src/pages/onboarding/import-seed.tsx
index 5da7e35..607346e 100644
--- a/src/pages/onboarding/import-seed.tsx
+++ b/src/pages/onboarding/import-seed.tsx
@@ -1,4 +1,4 @@
-import { useMemo, useState } from 'react'
+import { useEffect, useMemo, useState } from 'react'
import { identityFromSeed } from '@qubic-labs/core'
import { ArrowLeftIcon, ArrowRightIcon, KeyRoundIcon } from 'lucide-react'
import { useNavigate } from 'react-router-dom'
@@ -16,7 +16,7 @@ import {
isAccountNameTaken,
saveCachedAccounts,
} from '@/lib/accounts'
-import { setUnlocked } from '@/lib/lock'
+import { isWalletLocked, setUnlocked } from '@/lib/lock'
import {
openBrowserVault,
setOnboarded,
@@ -73,6 +73,17 @@ const ImportSeed = ({
setDerivedIdentity(null)
}
+ useEffect(() => {
+ const onLock = () => {
+ if (!isWalletLocked()) return
+ setSeed('')
+ setPassphrase('')
+ setDerivedIdentity(null)
+ }
+ window.addEventListener('wallet-lock-updated', onLock)
+ return () => window.removeEventListener('wallet-lock-updated', onLock)
+ }, [])
+
const handleSeedChange = (value: string) => {
setSeed(normalizeSeedInput(value))
if (step === 1 && status) {
diff --git a/src/pages/settings/connected-sites.tsx b/src/pages/settings/connected-sites.tsx
index 630d275..382d6b1 100644
--- a/src/pages/settings/connected-sites.tsx
+++ b/src/pages/settings/connected-sites.tsx
@@ -18,6 +18,7 @@ import {
} from '@/lib/dapp/storage'
import { useAccountNames } from '@/hooks/use-account-names'
import { truncateString } from '@/lib/utils'
+import IdnWarningBadge from '@/components/idn-warning-badge'
const ConnectedSites = () => {
const { t } = useTranslation()
@@ -87,6 +88,7 @@ const ConnectedSites = () => {
{site.origin}
+
{t('settings.connectedSites.connectedAt', {
date: new Date(site.connectedAt).toLocaleString(),