Ghost Shell

JavaScript NOASSERTION

Stars
0
Forks
0
Downloads
N/A
Open Issues
0
Files main

Repository Files

Loading file structure...
src/pages/master-password.jsx
import React from "react";
import DashboardLayout from "@/layouts/dashboard";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { invoke } from "@/lib/tauri";
import {
  LockIcon,
  Loader2,
  CheckCircle2,
  AlertTriangle,
  Shield,
} from "lucide-react";

export default function MasterPassword() {
  const [currentMaster, setCurrentMaster] = React.useState("");
  const [newMaster, setNewMaster] = React.useState("");
  const [confirmMaster, setConfirmMaster] = React.useState("");
  const [loading, setLoading] = React.useState(false);
  const [success, setSuccess] = React.useState("");
  const [error, setError] = React.useState("");

  const handleUpdateMaster = async (e) => {
    e.preventDefault();
    if (newMaster !== confirmMaster) {
      setError("New passwords do not match.");
      return;
    }
    setLoading(true);
    setSuccess("");
    setError("");
    try {
      await invoke("change_master_password", {
        oldPassphrase: currentMaster,
        newPassphrase: newMaster,
      });
      setSuccess(
        "Master password changed. All local credentials and keys have been re-encrypted.",
      );
      setCurrentMaster("");
      setNewMaster("");
      setConfirmMaster("");
    } catch (err) {
      setError(String(err));
    } finally {
      setLoading(false);
    }
  };

  return (
    <DashboardLayout>
      <div className="h-full flex items-start justify-center gap-6 min-h-0">
        <div className="space-y-4 mx-auto max-w-xl w-full">
          <div className="p-8 flex flex-col items-center justify-center gap-4 text-center">
            <div className="flex items-center gap-3 border-b pb-4 w-full">
              <div className="size-10 bg-primary/20 rounded-md flex items-center justify-center shrink-0 border border-primary/30">
                <LockIcon className="size-5 text-primary" />
              </div>
              <div className="text-left">
                <h2 className="text-lg font-semibold text-foreground leading-none">
                  Master Password
                </h2>
                <p className="text-xs text-muted-foreground mt-1">
                  Update your local vault passphrase and re-encrypt stored data.
                </p>
              </div>
            </div>

            <div className="w-full space-y-4 py-2 text-left">
              <div className="flex flex-col gap-2 bg-muted p-4 rounded-lg">
                <div className="flex items-center gap-2 text-primary">
                  <Shield className="size-5 shrink-0" />
                  <span className="text-sm font-semibold">Security notice</span>
                </div>
                <p className="text-xs leading-relaxed text-muted-foreground mt-1">
                  Changing your master password re-encrypts all local host
                  records, SSH private keys, and keychain entries on this device.
                </p>
              </div>

              <form onSubmit={handleUpdateMaster} className="space-y-4">
                {success && (
                  <div className="p-4 rounded-lg flex items-start gap-3 text-xs leading-relaxed border bg-primary/10 border-primary/20 text-primary-foreground">
                    <CheckCircle2 className="size-4 shrink-0 text-primary" />
                    <span>{success}</span>
                  </div>
                )}

                {error && (
                  <div className="p-4 rounded-lg flex items-start gap-3 text-xs leading-relaxed border bg-destructive/10 border-destructive/20 text-destructive">
                    <AlertTriangle className="size-4 shrink-0 text-destructive" />
                    <span>{error}</span>
                  </div>
                )}

                <div className="space-y-1.5">
                  <Label htmlFor="current-master" className="text-xs">
                    Current Master Password
                  </Label>
                  <Input
                    id="current-master"
                    type="password"
                    required
                    value={currentMaster}
                    onChange={(e) => setCurrentMaster(e.target.value)}
                    placeholder="••••••••"
                    className="h-9 text-xs"
                    disabled={loading}
                  />
                </div>

                <div className="space-y-1.5">
                  <Label htmlFor="new-master" className="text-xs">
                    New Master Password
                  </Label>
                  <Input
                    id="new-master"
                    type="password"
                    required
                    value={newMaster}
                    onChange={(e) => setNewMaster(e.target.value)}
                    placeholder="••••••••"
                    className="h-9 text-xs"
                    disabled={loading}
                  />
                </div>

                <div className="space-y-1.5">
                  <Label htmlFor="confirm-master" className="text-xs">
                    Confirm New Master Password
                  </Label>
                  <Input
                    id="confirm-master"
                    type="password"
                    required
                    value={confirmMaster}
                    onChange={(e) => setConfirmMaster(e.target.value)}
                    placeholder="••••••••"
                    className="h-9 text-xs"
                    disabled={loading}
                  />
                </div>

                <div className="pt-2">
                  <Button
                    type="submit"
                    className="w-full"
                    size="lg"
                    disabled={loading}
                  >
                    {loading && <Loader2 className="size-4 mr-2 animate-spin" />}
                    {loading ? "Updating..." : "Update Master Password"}
                  </Button>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
    </DashboardLayout>
  );
}