Skip to content
67 linesCodeBlameRaw
1/**
2 * Regenerating a token: a new secret for it, everything else kept, the
3 * old secret refused from then on. For rotating a token without remaking
4 * it, or replacing one that may have leaked. The page's action answers
5 * `intent=regenerate` with `{ secret, token }`, shown once by `TokenCreated`.
6 */
7import { RefreshCw } from "lucide-react";
8import { useState } from "react";
9import { Form } from "react-router";
10
11import {
12 AlertDialog,
13 AlertDialogAction,
14 AlertDialogCancel,
15 AlertDialogContent,
16 AlertDialogDescription,
17 AlertDialogFooter,
18 AlertDialogHeader,
19 AlertDialogTitle,
20 AlertDialogTrigger,
21} from "./ui/alert-dialog";
22import { Button } from "./ui/button";
23import { SelectField } from "./ui/select";
24import { DEFAULT_EXPIRY_DAYS, EXPIRY_DAYS, describeDays } from "../lib/access-tokens";
25
26export function RegenerateToken({ name }: { name: string }) {
27 const [expires, setExpires] = useState(String(DEFAULT_EXPIRY_DAYS));
28 const options = [...EXPIRY_DAYS.map((days) => ({ value: String(days), label: describeDays(days) })), { value: "never", label: "No expiration" }];
29 return (
30 <section className="rounded-xl border border-line p-4">
31 <h2 className="text-sm font-medium">Regenerate this token</h2>
32 <p className="mt-1 text-xs text-muted">
33 A new secret, with the same name, permissions and reach. Anything using the old one stops working at once, until you give it the new
34 one.
35 </p>
36 <div className="mt-3 flex flex-wrap items-center gap-2">
37 <SelectField aria-label="Expires" className="w-40" value={expires} onValueChange={setExpires} options={options} />
38 <AlertDialog>
39 <AlertDialogTrigger asChild>
40 <Button variant="outline">
41 <RefreshCw size={14} />
42 Regenerate
43 </Button>
44 </AlertDialogTrigger>
45 <AlertDialogContent>
46 <Form method="post" className="grid gap-4">
47 <input type="hidden" name="intent" value="regenerate" />
48 <input type="hidden" name="expires" value={expires} />
49 <AlertDialogHeader>
50 <AlertDialogTitle>Regenerate {name}?</AlertDialogTitle>
51 <AlertDialogDescription>
52 Its old secret stops working now. The new one is shown once, and {expires === "never" ? "does not expire" : `expires in ${describeDays(Number(expires))}`}.
53 </AlertDialogDescription>
54 </AlertDialogHeader>
55 <AlertDialogFooter>
56 <AlertDialogCancel>Cancel</AlertDialogCancel>
57 <AlertDialogAction asChild>
58 <button type="submit">Regenerate token</button>
59 </AlertDialogAction>
60 </AlertDialogFooter>
61 </Form>
62 </AlertDialogContent>
63 </AlertDialog>
64 </div>
65 </section>
66 );
67}