From 140024e9034c0e679f33023d2e216e62f169db09 Mon Sep 17 00:00:00 2001 From: Jaeger Aquila Date: Sat, 10 Dec 2022 14:33:27 -0500 Subject: [PATCH] initial login code --- scraper/api_request_utils.go | 126 ++++++++++++++++++++++++++++++++- scraper/authentication_test.go | 14 ++++ 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 scraper/authentication_test.go diff --git a/scraper/api_request_utils.go b/scraper/api_request_utils.go index 85dbb39..02d859f 100644 --- a/scraper/api_request_utils.go +++ b/scraper/api_request_utils.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "net/url" + "strings" "time" log "github.com/sirupsen/logrus" @@ -35,14 +36,137 @@ func NewGuestSession() API { func (api *API) LogIn(username string, password string) { // TODO authentication: Log in and save the authentication token(s), set `IsAuthenticated = true` + loginURL := "https://twitter.com/i/api/1.1/onboarding/task.json" + + result := make(map[string]interface{}) + err := api.do_http_POST(loginURL+"?flow_name=login", "", &result) + if err != nil { + panic(err) + } + + flow_token, is_ok := result["flow_token"] + if !is_ok { + panic("No flow token.") + } + flow_token_string := flow_token.(string) + + fmt.Println(flow_token.(string)) + + login_body := `{"flow_token":"` + flow_token_string + `", "subtask_inputs": [{"subtask_id": "LoginJsInstrumentationSubtask", "js_instrumentation": {"response": "{\"rf\":{\"a560cdc18ff70ce7662311eac0f2441dd3d3ed27c354f082f587e7a30d1a7d5f\":72,\"a8e890b5fec154e7af62d8f529fbec5942dfdd7ad41597245b71a3fbdc9a180d\":176,\"a3c24597ad4c862773c74b9194e675e96a7607708f6bbd0babcfdf8b109ed86d\":-161,\"af9847e2cd4e9a0ca23853da4b46bf00a2e801f98dc819ee0dd6ecc1032273fa\":-8},\"s\":\"hOai7h2KQi4RBGKSYLUhH0Y0fBm5KHIJgxD5AmNKtwP7N8gpVuAqP8o9n2FpCnNeR1d6XbB0QWkGAHiXkKao5PhaeXEZgPJU1neLcVgTnGuFzpjDnGutCUgYaxNiwUPfDX0eQkgr_q7GWmbB7yyYPt32dqSd5yt-KCpSt7MOG4aFmGf11xWE4MTpXfkefbnX4CwZeEFKQQYzJptOvmUWa7qI0A69BSOs7HZ_4Wry2TwB9k03Q_S-MDZAZ3yB_L7WoosVVb1e84YWgaLWWzqhz4C77jDy6isT8EKSWKWnVctsIcaqM_wMV8AiYa5lr0_WkN5TwK9h0vDOTS1obOZuhAAAAYTZan_3\"}", "link": "next_link"}}]}` + + err = api.do_http_POST(loginURL, login_body, &result) + if err != nil { + panic(err) + } + + flow_token, is_ok = result["flow_token"] + if !is_ok { + panic("No flow token.") + } + flow_token_string = flow_token.(string) + + fmt.Println(flow_token_string) + + login_body = `{"flow_token":"` + flow_token_string + `","subtask_inputs":[{"subtask_id":"LoginEnterUserIdentifierSSO","settings_list":{"setting_responses":[{"key":"user_identifier","response_data":{"text_data":{"result":"` + username + `"}}}],"link":"next_link"}}]}` + + err = api.do_http_POST(loginURL, login_body, &result) + if err != nil { + panic(err) + } + + flow_token, is_ok = result["flow_token"] + if !is_ok { + panic("No flow token.") + } + flow_token_string = flow_token.(string) + + fmt.Println(flow_token_string) + + login_body = `{"flow_token":"` + flow_token_string + `","subtask_inputs":[{"subtask_id":"LoginEnterPassword","enter_password":{"password":"` + password + `","link":"next_link"}}]}` + + err = api.do_http_POST(loginURL, login_body, &result) + if err != nil { + panic(err) + } + + flow_token, is_ok = result["flow_token"] + if !is_ok { + panic("No flow token.") + } + flow_token_string = flow_token.(string) + + fmt.Println(flow_token_string) + + login_body = `{"flow_token":"` + flow_token_string + `","subtask_inputs":[{"subtask_id":"AccountDuplicationCheck","check_logged_in_account":{"link":"AccountDuplicationCheck_false"}}]}` + + err = api.do_http_POST(loginURL, login_body, &result) + if err != nil { + panic(err) + } + panic("TODO") } +func (api *API) do_http_POST(url string, body string, result interface{}) error { + client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest("POST", url, strings.NewReader(body)) + if err != nil { + return fmt.Errorf("Error initializing HTTP POST request:\n %w", err) + } + + // Params for every request + req.Header.Set("Authorization", "Bearer "+BEARER_TOKEN) + req.Header.Set("x-twitter-client-language", "en") + req.Header.Set("content-type", "application/json") + + if api.IsAuthenticated { + // TODO authentication: add authentication headers/params + } else { + // Not authenticated; use guest token + if api.GuestToken == "" { + panic("No guest token set!") + } + req.Header.Set("X-Guest-Token", api.GuestToken) + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("Error executing HTTP POST request:\n %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + content, err := io.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + responseHeaders := "" + for header := range resp.Header { + responseHeaders += fmt.Sprintf(" %s: %s\n", header, resp.Header.Get(header)) + } + return fmt.Errorf("HTTP %s\n%s\n%s", resp.Status, responseHeaders, content) + } + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("Error reading response body:\n %w", err) + } + log.Debug(string(respBody)) + + err = json.Unmarshal(respBody, result) + if err != nil { + return fmt.Errorf("Error parsing API response:\n %w", err) + } + return nil + +} + func (api API) do_http(url string, cursor string, result interface{}) error { client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequest("GET", url, nil) if err != nil { - return fmt.Errorf("Error initializing HTTP request:\n %w", err) + return fmt.Errorf("Error initializing HTTP GET request:\n %w", err) } if cursor != "" { diff --git a/scraper/authentication_test.go b/scraper/authentication_test.go new file mode 100644 index 0000000..96f6dd6 --- /dev/null +++ b/scraper/authentication_test.go @@ -0,0 +1,14 @@ +package scraper_test + +import ( + "offline_twitter/scraper" + "testing" +) + +func TestAuthentication(t *testing.T) { + username := "offline_twatter" + password := "S1pKIW#eRT016iA@OFcK" + + api := scraper.NewGuestSession() + api.LogIn(username, password) +}