diff --git a/scraper/api_request_utils.go b/scraper/api_request_utils.go index 70ae32e..8db5438 100644 --- a/scraper/api_request_utils.go +++ b/scraper/api_request_utils.go @@ -24,6 +24,53 @@ type API struct { CSRFToken string } +type api_outstruct struct { + Cookies []*http.Cookie + UserHandle UserHandle + IsAuthenticated bool + GuestToken string + CSRFToken string +} + +var TWITTER_BASE_URL = url.URL{Scheme: "https", Host: "twitter.com"} + +func (api API) MarshalJSON() ([]byte, error) { + result, err := json.Marshal(api_outstruct{ + Cookies: api.Client.Jar.Cookies(&TWITTER_BASE_URL), + UserHandle: api.UserHandle, + IsAuthenticated: api.IsAuthenticated, + GuestToken: api.GuestToken, + CSRFToken: api.CSRFToken, + }) + if err != nil { + return result, fmt.Errorf("Unable to JSONify the api:\n %w", err) + } + return result, nil +} + +func (api *API) UnmarshalJSON(data []byte) error { + var in_struct api_outstruct + err := json.Unmarshal(data, &in_struct) + if err != nil { + return fmt.Errorf("Unable to unmarshal:\n %w", err) + } + cookie_jar, err := cookiejar.New(nil) + if err != nil { + panic(err) + } + cookie_jar.SetCookies(&TWITTER_BASE_URL, in_struct.Cookies) + api.IsAuthenticated = in_struct.IsAuthenticated + api.GuestToken = in_struct.GuestToken + api.UserHandle = in_struct.UserHandle + + api.Client = http.Client{ + Timeout: 10 * time.Second, + Jar: cookie_jar, + } + api.CSRFToken = in_struct.CSRFToken + return nil +} + func (api API) add_authentication_headers(req *http.Request) { // Params for every request req.Header.Set("Authorization", "Bearer "+BEARER_TOKEN) diff --git a/scraper/authentication_test.go b/scraper/authentication_test.go index 388a9ce..bb6d981 100644 --- a/scraper/authentication_test.go +++ b/scraper/authentication_test.go @@ -1,13 +1,21 @@ package scraper_test import ( - . "offline_twitter/scraper" + "encoding/json" "testing" + "time" + "net/http" + "net/http/cookiejar" + + "github.com/go-test/deep" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + . "offline_twitter/scraper" ) +// TODO authentication: this has to be removed and replaced with an integration test once the feature is stable-ish func TestAuthentication(t *testing.T) { assert := assert.New(t) require := require.New(t) @@ -28,3 +36,41 @@ func TestAuthentication(t *testing.T) { require.NoError(err) assert.True(len(trove.Tweets) > 0) } + +// An API object should serialize and then deserialize to give the same session state from before. +func TestJsonifyApi(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + cookie_jar, err := cookiejar.New(nil) + require.NoError(err) + cookie_jar.SetCookies(&TWITTER_BASE_URL, []*http.Cookie{ + {Name: "name1", Value: "name1", Secure: true}, + {Name: "name2", Value: "name2", HttpOnly: true}, + }) + api := API{ + UserHandle: UserHandle("userhandle"), + IsAuthenticated: true, + GuestToken: "guest token", + Client: http.Client{ + Timeout: 10 * time.Second, + Jar: cookie_jar, + }, + CSRFToken: "csrf token", + } + + bytes, err := json.Marshal(api) + require.NoError(err) + var new_api API + err = json.Unmarshal(bytes, &new_api) + require.NoError(err) + + cookies := api.Client.Jar.Cookies(&TWITTER_BASE_URL) + + assert.Equal(cookies[0].Name, "name1") + assert.Equal(cookies[0].Value, "name1") + + if diff := deep.Equal(api, new_api); diff != nil { + t.Error(diff) + } +}