(feat): add cache package
All checks were successful
/ build-web (push) Successful in 7m26s
/ build-desktop (linux) (push) Successful in 11m29s
/ build-mobile (push) Successful in 19m15s
/ release (push) Successful in 3m3s

(feat): improve local storage security
(feat): move settings to dedicated settings package
This commit is contained in:
Alois 2026-07-11 22:08:01 +02:00
commit 790a1db788
54 changed files with 1984 additions and 947 deletions

View file

@ -58,7 +58,6 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
<House className="size-4.5" />
</Button>
<Button
// @ts-expect-error TanStack router doesn't properly detect the settings route
onClick={() => navigate({ to: "/settings" })}
className="w-9 h-9 aspect-square rounded-lg"
variant="outline"
@ -195,7 +194,6 @@ export function MobileNavbar() {
</Button>
<Button
onClick={() => {
// @ts-expect-error TanStack router doesn't properly detect the settings route
navigate({ to: "/settings" });
setOpenMobile(false);
}}

View file

@ -80,6 +80,30 @@ export default function Form() {
const uploadRef = React.useRef<HTMLInputElement | null>(null);
const [isDragging, setIsDragging] = React.useState(false);
const { save } = useStorage();
const loginPendingRef = React.useRef(false);
const persistLogin = React.useCallback(
async (userId: number, privateKey: string, domain?: string | null) => {
if (loginPendingRef.current) return false;
loginPendingRef.current = true;
try {
if (domain) await save("omega_url", `https://${domain}/`);
await save("mtp_keyring", privateKey, { secure: true });
await save("session_id", Date.now());
await save("user_id", userId);
window.history.replaceState(
null,
"",
window.location.protocol === "file:" ? "#/" : "/",
);
window.location.reload();
return true;
} finally {
loginPendingRef.current = false;
}
},
[save],
);
// Process dropped files
const processDroppedFile = React.useCallback(
@ -93,20 +117,13 @@ export default function Form() {
const raw = await file.text();
const parsed = parseTuFileContent(raw);
await save("session_id", Date.now());
await save("user_id", parsed.userId);
await save("mtp_keyring", parsed.privateKey);
if (parsed.domain) {
await save("omega_url", `https://${parsed.domain}/`);
}
location.href = "/";
await persistLogin(parsed.userId, parsed.privateKey, parsed.domain);
} catch (error) {
log(0, "login", "red", error);
toast("error", "Failed to load file");
}
},
[save],
[persistLogin],
);
// Handle .tu files
@ -236,20 +253,13 @@ export default function Form() {
const user = parse.data;
await save("session_id", Date.now());
await save("user_id", user.user_id);
await save("mtp_keyring", inputParse.data.mtp_keyring);
if (domain) {
await save("omega_url", `https://${domain}/`);
}
location.href = "/";
await persistLogin(user.user_id, inputParse.data.mtp_keyring, domain);
} catch (error) {
log(0, "login", "red", error);
toast("error", "Failed to fetch user data");
}
},
[save],
[persistLogin],
);
return (
@ -269,15 +279,7 @@ export default function Form() {
const { userId, privateKey, domain } =
parseTuFileContent(decoded);
await save("session_id", Date.now());
await save("user_id", userId);
await save("mtp_keyring", privateKey);
if (domain) {
await save("omega_url", `https://${domain}/`);
}
location.href = "/";
await persistLogin(userId, privateKey, domain);
} catch (error) {
log(0, "login", "red", error);
toast("error", "Failed to parse QR code data");