mirror of
https://github.com/p-stream/p-stream.git
synced 2026-01-11 20:10:32 +00:00
Handle device name decryption errors gracefully
Added error handling for device name decryption in Avatar, LinksDropdown, Settings, and DeviceListPart components. If decryption fails, a fallback 'Unknown device' message is shown using a new translation key. This improves user experience by preventing crashes or blank fields when device name decryption fails.
This commit is contained in:
parent
a76f25fcea
commit
c329118e50
5 changed files with 47 additions and 9 deletions
|
|
@ -981,6 +981,7 @@
|
|||
},
|
||||
"devices": {
|
||||
"deviceNameLabel": "Device name",
|
||||
"unknownDevice": "Unknown device, error decrypting name",
|
||||
"failed": "Failed to load sessions",
|
||||
"removeDevice": "Remove",
|
||||
"title": "Devices"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import classNames from "classnames";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { base64ToBuffer, decryptData } from "@/backend/accounts/crypto";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
|
|
@ -55,11 +56,22 @@ export function UserAvatar(props: {
|
|||
: null,
|
||||
[auth],
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!auth.account || auth.account === null) return null;
|
||||
|
||||
const deviceName = bufferSeed
|
||||
? decryptData(auth.account.deviceName, bufferSeed)
|
||||
? (() => {
|
||||
try {
|
||||
return decryptData(auth.account.deviceName, bufferSeed);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"Failed to decrypt device name in Avatar, using fallback:",
|
||||
error,
|
||||
);
|
||||
return t("settings.account.devices.unknownDevice");
|
||||
}
|
||||
})()
|
||||
: "...";
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -257,7 +257,17 @@ export function LinksDropdown(props: { children: React.ReactNode }) {
|
|||
{deviceName && bufferSeed ? (
|
||||
<DropdownLink className="text-white" href="/settings">
|
||||
<UserAvatar />
|
||||
{decryptData(deviceName, bufferSeed)}
|
||||
{(() => {
|
||||
try {
|
||||
return decryptData(deviceName, bufferSeed);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"Failed to decrypt device name in LinksDropdown, using fallback:",
|
||||
error,
|
||||
);
|
||||
return t("settings.account.unknownDevice");
|
||||
}
|
||||
})()}
|
||||
</DropdownLink>
|
||||
) : (
|
||||
<DropdownLink href="/login" icon={Icons.RISING_STAR} highlight>
|
||||
|
|
|
|||
|
|
@ -490,8 +490,14 @@ export function SettingsPage() {
|
|||
const updateNickname = useAuthStore((s) => s.setAccountNickname);
|
||||
const decryptedName = useMemo(() => {
|
||||
if (!account) return "";
|
||||
return decryptData(account.deviceName, base64ToBuffer(account.seed));
|
||||
}, [account]);
|
||||
try {
|
||||
return decryptData(account.deviceName, base64ToBuffer(account.seed));
|
||||
} catch (error) {
|
||||
console.warn("Failed to decrypt device name, using fallback:", error);
|
||||
// Return a fallback device name if decryption fails
|
||||
return t("settings.account.devices.unknownDevice");
|
||||
}
|
||||
}, [account, t]);
|
||||
|
||||
const backendUrl = useBackendUrl();
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,16 @@ export function DeviceListPart(props: {
|
|||
const deviceListSorted = useMemo(() => {
|
||||
if (!seed) return [];
|
||||
let list = sessions.map((session) => {
|
||||
const decryptedName = decryptData(session.device, base64ToBuffer(seed));
|
||||
let decryptedName: string;
|
||||
try {
|
||||
decryptedName = decryptData(session.device, base64ToBuffer(seed));
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Failed to decrypt device name for session ${session.id}:`,
|
||||
error,
|
||||
);
|
||||
decryptedName = t("settings.account.devices.unknownDevice");
|
||||
}
|
||||
return {
|
||||
current: session.id === currentSessionId,
|
||||
id: session.id,
|
||||
|
|
@ -88,7 +97,7 @@ export function DeviceListPart(props: {
|
|||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
return list;
|
||||
}, [seed, sessions, currentSessionId]);
|
||||
}, [seed, sessions, currentSessionId, t]);
|
||||
if (!seed) return null;
|
||||
|
||||
return (
|
||||
|
|
@ -96,10 +105,10 @@ export function DeviceListPart(props: {
|
|||
<Heading2 border className="mt-0 mb-9">
|
||||
{t("settings.account.devices.title")}
|
||||
</Heading2>
|
||||
{props.error ? (
|
||||
<p>{t("settings.account.devices.failed")}</p>
|
||||
) : props.loading ? (
|
||||
{props.loading ? (
|
||||
<Loading />
|
||||
) : props.error && deviceListSorted.length === 0 ? (
|
||||
<p>{t("settings.account.devices.failed")}</p>
|
||||
) : (
|
||||
<div className="space-y-5">
|
||||
{deviceListSorted.map((session) => (
|
||||
|
|
|
|||
Loading…
Reference in a new issue