Catalyst / admin/Apex 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Apex

public

Bid Management and Orchestration Tool with AI Capability

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
Apex / Synapse-Apexv2 / frontend / src / pages / MfaEnroll.tsx 1994 B · main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { useEffect, useState } from "react";
import { api } from "../lib/api";
import { useAuth } from "../lib/auth";

export default function MfaEnroll({ optional = false }: { optional?: boolean }) {
  const { refresh } = useAuth();
  const [data, setData] = useState<any>(null);
  const [otp, setOtp] = useState("");
  const [err, setErr] = useState("");

  async function start() {
    setErr("");
    setData(await api.post("/auth/mfa/enroll"));
  }

  useEffect(() => {
    if (!optional) start();
  }, []);

  async function verify(e: React.FormEvent) {
    e.preventDefault();
    setErr("");
    try {
      await api.post("/auth/mfa/verify", { otp });
      await refresh();
    } catch (e: any) {
      setErr(e.message);
    }
  }

  return (
    <div className="login-wrap">
      <div className="card login-card" style={{ width: 420 }}>
        <h1>Set up multi-factor authentication</h1>
        <p className="muted">
          {optional
            ? "Add an authenticator app for extra security."
            : "Your administrator requires MFA. Scan the QR code with an authenticator app, then enter a code to confirm."}
        </p>
        {!data && optional && <button onClick={start}>Begin enrolment</button>}
        {data && (
          <>
            <div dangerouslySetInnerHTML={{ __html: data.qr_svg }} style={{ maxWidth: 200 }} />
            <p className="muted" style={{ fontSize: 12 }}>Secret: {data.secret}</p>
            <p style={{ fontSize: 12 }}>
              Recovery codes (store safely): <br />
              <code>{data.recovery_codes.join("  ")}</code>
            </p>
            <form onSubmit={verify}>
              <label>Enter a 6-digit code to confirm</label>
              <input value={otp} onChange={(e) => setOtp(e.target.value)} autoFocus />
              {err && <div className="err">{err}</div>}
              <button style={{ marginTop: 12 }}>Confirm</button>
            </form>
          </>
        )}
      </div>
    </div>
  );
}