···2728let verify_2fa_code ~(actor : Data_store.Types.actor) ~code db =
29 let did = actor.did in
30- let%lwt totp_valid = Totp.verify_login_code ~did ~code db in
31- if totp_valid then Lwt.return_ok ()
32 else
33- let%lwt backup_valid = Totp.Backup_codes.verify_and_consume ~did ~code db in
34- if backup_valid then Lwt.return_ok ()
35 else
36- match%lwt Two_factor.verify_email_code_by_did ~did ~code db with
37- | Ok _ ->
38- Lwt.return_ok ()
39- | Error e ->
40- Lwt.return_error e
000004142let handler =
43 Xrpc.handler (fun {req; db; _} ->
···59 Lwt_result.catch @@ fun () -> Data_store.try_login ~id ~password db
60 with
61 | Ok (Some actor) -> (
62- let is_2fa_enabled =
63- actor.email_2fa_enabled = 1 || actor.totp_verified_at <> None
64 in
65 if not is_2fa_enabled then complete_login actor
66 else
···78 in
79 (* only send code to email if email is the only method *)
80 let%lwt () =
81- if methods.email && not methods.totp then
00082 let%lwt session_token =
83 Two_factor.create_pending_session ~did:actor.did db
84 in
···2728let verify_2fa_code ~(actor : Data_store.Types.actor) ~code db =
29 let did = actor.did in
30+ let%lwt sk_valid = Security_key.verify_login ~did ~code db in
31+ if sk_valid then Lwt.return_ok ()
32 else
33+ let%lwt totp_valid = Totp.verify_login_code ~did ~code db in
34+ if totp_valid then Lwt.return_ok ()
35 else
36+ let%lwt backup_valid =
37+ Totp.Backup_codes.verify_and_consume ~did ~code db
38+ in
39+ if backup_valid then Lwt.return_ok ()
40+ else
41+ match%lwt Two_factor.verify_email_code_by_did ~did ~code db with
42+ | Ok _ ->
43+ Lwt.return_ok ()
44+ | Error e ->
45+ Lwt.return_error e
4647let handler =
48 Xrpc.handler (fun {req; db; _} ->
···64 Lwt_result.catch @@ fun () -> Data_store.try_login ~id ~password db
65 with
66 | Ok (Some actor) -> (
67+ let%lwt is_2fa_enabled =
68+ Two_factor.is_2fa_enabled ~did:actor.did db
69 in
70 if not is_2fa_enabled then complete_login actor
71 else
···83 in
84 (* only send code to email if email is the only method *)
85 let%lwt () =
86+ if
87+ methods.email && (not methods.totp)
88+ && not methods.security_key
89+ then
90 let%lwt session_token =
91 Two_factor.create_pending_session ~did:actor.did db
92 in
···1+CREATE TABLE IF NOT EXISTS security_keys (
2+ id INTEGER PRIMARY KEY,
3+ did TEXT NOT NULL,
4+ name TEXT NOT NULL DEFAULT 'Security Key',
5+ secret BLOB NOT NULL,
6+ counter INTEGER NOT NULL DEFAULT 0,
7+ created_at INTEGER NOT NULL,
8+ last_used_at INTEGER,
9+ verified_at INTEGER,
10+ FOREIGN KEY (did) REFERENCES actors(did) ON DELETE CASCADE
11+);
12+13+CREATE INDEX IF NOT EXISTS security_keys_did_idx ON security_keys(did);