Handle guest token / session initialization when not connected to internet

This commit is contained in:
Alessio 2024-07-14 13:20:44 -07:00
parent 0fd17f1af0
commit ef15e8a306
7 changed files with 48 additions and 10 deletions

View File

@ -129,7 +129,12 @@ func main() {
scraper.InitApi(profile.LoadSession(scraper.UserHandle(*session_name))) scraper.InitApi(profile.LoadSession(scraper.UserHandle(*session_name)))
// fmt.Printf("Operating as user: @%s\n", scraper.the_api.UserHandle) // fmt.Printf("Operating as user: @%s\n", scraper.the_api.UserHandle)
} else { } else {
scraper.InitApi(scraper.NewGuestSession()) session, err := scraper.NewGuestSession()
if err != nil {
log.Warnf("Unable to initialize guest session! Might be a network issue")
} else {
scraper.InitApi(session)
}
} }
switch operation { switch operation {
@ -222,7 +227,10 @@ func main() {
// - password: twitter account password // - password: twitter account password
func login(username string, password string) { func login(username string, password string) {
// Skip the scraper.the_api variable, just use a local one since no scraping is happening // Skip the scraper.the_api variable, just use a local one since no scraping is happening
api := scraper.NewGuestSession() api, err := scraper.NewGuestSession()
if err != nil {
die(fmt.Sprintf("Unable to create session: %s", err.Error()), false, 1)
}
challenge := api.LogIn(username, password) challenge := api.LogIn(username, password)
if challenge != nil { if challenge != nil {
fmt.Printf("Secondary challenge issued:\n") fmt.Printf("Secondary challenge issued:\n")

View File

@ -42,7 +42,10 @@ func (app *Application) Login(w http.ResponseWriter, r *http.Request) {
panic_if(json.Unmarshal(data, &form)) // TODO: HTTP 400 not 500 panic_if(json.Unmarshal(data, &form)) // TODO: HTTP 400 not 500
form.Validate() form.Validate()
if len(form.FormErrors) == 0 { if len(form.FormErrors) == 0 {
api := scraper.NewGuestSession() api, err := scraper.NewGuestSession()
if err != nil {
panic(err.Error()) // Return it as a toast
}
challenge := api.LogIn(form.Username, form.Password) challenge := api.LogIn(form.Username, form.Password)
if challenge != nil { if challenge != nil {
panic( // Middleware will trap this panic and return an HTMX error toast panic( // Middleware will trap this panic and return an HTMX error toast

View File

@ -62,7 +62,6 @@ func (app *Application) WithMiddlewares() http.Handler {
func (app *Application) SetActiveUser(handle scraper.UserHandle) error { func (app *Application) SetActiveUser(handle scraper.UserHandle) error {
if handle == "no account" { if handle == "no account" {
scraper.InitApi(scraper.NewGuestSession())
app.ActiveUser = get_default_user() app.ActiveUser = get_default_user()
app.IsScrapingDisabled = true // API requests will fail b/c not logged in app.IsScrapingDisabled = true // API requests will fail b/c not logged in
} else { } else {

View File

@ -11,5 +11,8 @@ var (
ErrorIsTombstone = errors.New("tweet is a tombstone") ErrorIsTombstone = errors.New("tweet is a tombstone")
ErrRateLimited = errors.New("rate limited") ErrRateLimited = errors.New("rate limited")
ErrorDMCA = errors.New("video is DMCAed, unable to download (HTTP 403 Forbidden)") ErrorDMCA = errors.New("video is DMCAed, unable to download (HTTP 403 Forbidden)")
ErrRequestTimeout = errors.New("request timed out")
// These are not API errors, but network errors generally
ErrNoInternet = errors.New("no internet connection")
ErrRequestTimeout = errors.New("request timed out")
) )

View File

@ -111,10 +111,10 @@ func (api API) add_authentication_headers(req *http.Request) {
} }
} }
func NewGuestSession() API { func NewGuestSession() (API, error) {
guestAPIString, err := GetGuestToken() guestAPIString, err := GetGuestTokenWithRetries(3, 1*time.Second)
if err != nil { if err != nil {
panic(err) return API{}, err
} }
jar, err := cookiejar.New(nil) jar, err := cookiejar.New(nil)
@ -129,7 +129,7 @@ func NewGuestSession() API {
Jar: jar, Jar: jar,
}, },
CSRFToken: "", CSRFToken: "",
} }, nil
} }
func (api *API) update_csrf_token() { func (api *API) update_csrf_token() {

View File

@ -2,8 +2,11 @@ package scraper
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"log"
"net"
"net/http" "net/http"
"time" "time"
) )
@ -15,7 +18,20 @@ type GuestTokenResponse struct {
var guestToken GuestTokenResponse var guestToken GuestTokenResponse
func GetGuestTokenWithRetries(n int, sleep time.Duration) (ret string, err error) {
for i := 0; i < n; i++ {
ret, err = GetGuestToken()
if err == nil {
return
}
log.Printf("Failed to get guest token: %s\nRetrying...", err.Error())
time.Sleep(sleep)
}
return
}
func GetGuestToken() (string, error) { func GetGuestToken() (string, error) {
// Guest token is still valid; no need for new one
if time.Since(guestToken.RefreshedAt).Hours() < 1 { if time.Since(guestToken.RefreshedAt).Hours() < 1 {
return guestToken.Token, nil return guestToken.Token, nil
} }
@ -29,6 +45,11 @@ func GetGuestToken() (string, error) {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) && dnsErr.Err == "server misbehaving" && dnsErr.Temporary() {
return "", ErrNoInternet
}
return "", fmt.Errorf("Error executing HTTP request:\n %w", err) return "", fmt.Errorf("Error executing HTTP request:\n %w", err)
} }

View File

@ -175,7 +175,11 @@ func ParseSingleUser(apiUser APIUser) (ret User, err error) {
// Calls API#GetUser and returns the parsed result // Calls API#GetUser and returns the parsed result
func GetUser(handle UserHandle) (User, error) { func GetUser(handle UserHandle) (User, error) {
apiUser, err := NewGuestSession().GetUser(handle) session, err := NewGuestSession() // This endpoint works better if you're not logged in
if err != nil {
return User{}, err
}
apiUser, err := session.GetUser(handle)
if apiUser.ScreenName == "" { if apiUser.ScreenName == "" {
if apiUser.IsBanned || apiUser.DoesntExist { if apiUser.IsBanned || apiUser.DoesntExist {
ret := GetUnknownUserWithHandle(handle) ret := GetUnknownUserWithHandle(handle)