Support 2FA

Close #106
This commit is contained in:
Alexander Sheiko 2023-06-12 18:23:26 +03:00
parent d9d8ee67b6
commit 15e5f233b7
2 changed files with 30 additions and 13 deletions

View file

@ -196,6 +196,12 @@ But if you have email confirmation, use email address in addition:
err := scraper.Login("username", "password", "email") err := scraper.Login("username", "password", "email")
``` ```
If you have two-factor authentication, use code:
```golang
err := scraper.Login("username", "password", "code")
```
Status of login can be checked with: Status of login can be checked with:
```golang ```golang

37
auth.go
View file

@ -129,6 +129,8 @@ func (s *Scraper) getFlowToken(data map[string]interface{}) (string, error) {
err = fmt.Errorf("auth error: %v", "LoginEnterAlternateIdentifierSubtask") err = fmt.Errorf("auth error: %v", "LoginEnterAlternateIdentifierSubtask")
} else if info.Subtasks[0].SubtaskID == "LoginAcid" { } else if info.Subtasks[0].SubtaskID == "LoginAcid" {
err = fmt.Errorf("auth error: %v", "LoginAcid") err = fmt.Errorf("auth error: %v", "LoginAcid")
} else if info.Subtasks[0].SubtaskID == "LoginTwoFactorAuthChallenge" {
err = fmt.Errorf("auth error: %v", "LoginTwoFactorAuthChallenge")
} }
} }
@ -157,19 +159,18 @@ func (s *Scraper) IsLoggedIn() bool {
// Login to Twitter // Login to Twitter
// Use Login(username, password) for ordinary login // Use Login(username, password) for ordinary login
// or Login(username, password, email) for login if you have email confirmation // or Login(username, password, email) for login if you have email confirmation
// or Login(username, password, code_for_2FA) for login if you have two-factor authentication
func (s *Scraper) Login(credentials ...string) error { func (s *Scraper) Login(credentials ...string) error {
var username, password, email string var username, password, confirmation string
if len(credentials) == 2 { if len(credentials) < 2 || len(credentials) > 3 {
username = credentials[0]
password = credentials[1]
} else if len(credentials) == 3 {
username = credentials[0]
password = credentials[1]
email = credentials[2]
} else {
return fmt.Errorf("invalid credentials") return fmt.Errorf("invalid credentials")
} }
username, password = credentials[0], credentials[1]
if len(credentials) == 3 {
confirmation = credentials[2]
}
s.setBearerToken(bearerToken2) s.setBearerToken(bearerToken2)
err := s.GetGuestToken() err := s.GetGuestToken()
@ -257,14 +258,24 @@ func (s *Scraper) Login(credentials ...string) error {
} }
flowToken, err = s.getFlowToken(data) flowToken, err = s.getFlowToken(data)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "LoginAcid") { var confirmationSubtask string
// flow acid for _, subtask := range []string{"LoginAcid", "LoginTwoFactorAuthChallenge"} {
if strings.Contains(err.Error(), subtask) {
confirmationSubtask = subtask
break
}
}
if confirmationSubtask != "" {
if confirmation == "" {
return fmt.Errorf("confirmation data required for %v", confirmationSubtask)
}
// flow confirmation
data = map[string]interface{}{ data = map[string]interface{}{
"flow_token": flowToken, "flow_token": flowToken,
"subtask_inputs": []map[string]interface{}{ "subtask_inputs": []map[string]interface{}{
{ {
"subtask_id": "LoginAcid", "subtask_id": confirmationSubtask,
"enter_text": map[string]interface{}{"text": email, "link": "next_link"}, "enter_text": map[string]interface{}{"text": confirmation, "link": "next_link"},
}, },
}, },
} }