82 lines
2.4 KiB
OCaml
82 lines
2.4 KiB
OCaml
open Pusk.Net
|
|
open Pusk.Utils
|
|
|
|
type credentials =
|
|
{ username : string
|
|
; password : string
|
|
}
|
|
|
|
let inject_username session_id creds =
|
|
(* Find username input *)
|
|
let strat = CSS "input[name='text']" in
|
|
let input_username =
|
|
match find session_id strat with
|
|
| [] -> raise (Any (fmt "Username input not found"))
|
|
| _ as l ->
|
|
if List.length l > 1
|
|
then raise (Any "Too many elements found as the username input")
|
|
else List.nth l 0
|
|
in
|
|
(* Insert the username *)
|
|
send_keys session_id input_username creds.username;
|
|
Unix.sleep 1;
|
|
send_keys session_id input_username Keys.return;
|
|
Unix.sleep 3
|
|
;;
|
|
|
|
let rec _inject_password session_id creds try_count =
|
|
if try_count == 0 then raise (Any "Password input not found");
|
|
let input_password =
|
|
match find session_id (CSS "input[name='password']") with
|
|
| [] ->
|
|
(* Retry to inject username with the second page *)
|
|
inject_username session_id creds;
|
|
_inject_password session_id creds (try_count - 1);
|
|
None
|
|
| _ as l ->
|
|
if List.length l > 1
|
|
then raise (Any "Too many elements found as the password input")
|
|
else Some (List.nth l 0)
|
|
in
|
|
match input_password with
|
|
| Some input ->
|
|
(* Insert password *)
|
|
send_keys session_id input creds.password;
|
|
Unix.sleep 1;
|
|
send_keys session_id input Keys.return;
|
|
Unix.sleep 3
|
|
| None -> ()
|
|
;;
|
|
|
|
let inject_password session_id creds = _inject_password session_id creds 1
|
|
|
|
let inject_2fa session_id secret input =
|
|
let code =
|
|
match secret with
|
|
| Some seed -> Twostep.TOTP.code ~secret:seed ()
|
|
| None -> raise (Any "No TOTP code given, but 2FA code required")
|
|
in
|
|
(* Insert 2FA code *)
|
|
send_keys session_id input code;
|
|
Unix.sleep 1;
|
|
send_keys session_id input Keys.return;
|
|
Unix.sleep 5
|
|
;;
|
|
|
|
let login_twitter ctx username password secret =
|
|
(* Navigate to login page and wait for page loaded*)
|
|
ignore (navigate ctx.session_id "https://twitter.com/i/flow/login");
|
|
Unix.sleep 5;
|
|
let creds = { username; password } in
|
|
(* Insert the username *)
|
|
inject_username ctx.session_id creds;
|
|
(* Find password input *)
|
|
inject_password ctx.session_id creds;
|
|
(* Detection and injection of 2FA code if needed *)
|
|
match find ctx.session_id (CSS "input[name='text']") with
|
|
| [] -> print_endline "Doesn't use 2FA as no input found"
|
|
| _ as l ->
|
|
if List.length l > 1
|
|
then raise (Any "Too many elements found as 2FA input")
|
|
else inject_2fa ctx.session_id secret (List.nth l 0)
|
|
;;
|