sipher/src/components/olm/olm-password-dialog.tsx
Nixyan 55e78db2cb chore: update dependencies and enhance OLM password handling
- Updated various dependencies in package.json and bun.lock to their latest versions for improved stability and security.
- Introduced a new ecosystem.config.cjs file for better environment management.
- Enhanced OLM password handling with encryption and decryption functionalities. (Testing)
- Improved UI components for password dialogs to provide better user feedback and error handling.
- Added new database schema for managing nests and roles in the application.
2026-01-14 15:20:38 -03:00

122 lines
No EOL
4.6 KiB
TypeScript

import { useOlmContext } from "@/contexts/olm-context";
import { AlertCircle, Info, KeyRound, ShieldCheck } from "lucide-react";
import { useEffect, useState } from "react";
import { Button } from "../ui/button";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog";
import { Input } from "../ui/input";
export default function OlmPasswordDialog({ userId }: { userId: string }) {
const [needsPassword, setNeedsPassword] = useState(false);
const [password, setPasswordInput] = useState("");
const { setPassword, passwordError, clearPasswordError } = useOlmContext();
useEffect(() => {
// The context handles loading & decrypting the password from sessionStorage.
// We only need to show the dialog if the context doesn't have a password.
// This will be handled by the passwordError effect below.
// For initial load, we check if there's encrypted data - if not, show dialog.
const hasStoredPassword = sessionStorage.getItem(`olm_password_${userId}`);
if (!hasStoredPassword) {
setNeedsPassword(true);
}
// If there IS stored data, the context will decrypt it and load it.
// If decryption fails or password is wrong, passwordError will be set.
}, [userId]);
// Show dialog when there's a password error (wrong password was entered)
useEffect(() => {
if (passwordError) {
setNeedsPassword(true);
setPasswordInput(""); // Clear the input for retry
}
}, [passwordError]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (password.trim()) {
setPassword(password);
setNeedsPassword(false);
}
};
return (
<Dialog open={needsPassword}>
<DialogContent className="sm:max-w-[440px]" showCloseButton={false} onPointerDownOutside={(e) => e.preventDefault()} onEscapeKeyDown={(e) => e.preventDefault()}>
<DialogHeader className="space-y-4">
<div className="flex flex-col items-center text-center space-y-3">
<div className="h-14 w-14 rounded-full bg-primary/10 flex items-center justify-center ring-8 ring-primary/5">
<KeyRound className="h-7 w-7 text-primary" />
</div>
<div className="space-y-2">
<DialogTitle className="text-2xl font-semibold tracking-tight">
Encryption Password Required
</DialogTitle>
<DialogDescription className="text-sm text-muted-foreground max-w-sm">
Enter your encryption password to access this conversation. This may be different from your login password.
</DialogDescription>
</div>
</div>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-6 pt-2">
<div className="space-y-3">
<Input
type="password"
placeholder="Enter your encryption password"
className={`h-11 text-center ${passwordError ? "border-destructive focus-visible:ring-destructive" : ""}`}
autoFocus
value={password}
onChange={(e) => {
setPasswordInput(e.target.value);
if (passwordError) clearPasswordError();
}}
/>
{passwordError && (
<div className="flex items-center gap-2 rounded-md bg-destructive/10 px-3 py-2.5 text-destructive border border-destructive/20">
<AlertCircle className="h-4 w-4 shrink-0" />
<p className="text-xs leading-relaxed">
{passwordError}
</p>
</div>
)}
<div className="space-y-2">
<div className="flex items-center gap-2 rounded-md bg-chart-3/10 px-3 py-2.5 text-chart-3 border border-chart-3/20">
<Info className="h-4 w-4 shrink-0" />
<p className="text-xs leading-relaxed">
You'll be asked to re-enter this password each time you start a new browser session.
<br />
When continuing, the window will be reloaded, please do not close the window or refresh the page by yourself.
</p>
</div>
</div>
<div className="flex items-center gap-2 rounded-md bg-chart-2/10 px-3 py-2.5 text-chart-2 border border-chart-2/20">
<ShieldCheck className="h-4 w-4 shrink-0" />
<p className="text-xs leading-relaxed">
Your password is encrypted before being stored in your browser's session storage using a secure key that cannot be exported.
</p>
</div>
</div>
<div className="flex gap-3">
<Button
type="button"
variant="outline"
onClick={() => setNeedsPassword(false)}
className="flex-1"
>
Cancel
</Button>
<Button
type="submit"
className="flex-1"
disabled={!password.trim()}
>
Continue
</Button>
</div>
</form>
</DialogContent>
</Dialog>
)
}