diff --git a/internal/db/application.go b/internal/db/application.go index 5a4068431..1011698bf 100644 --- a/internal/db/application.go +++ b/internal/db/application.go @@ -36,42 +36,42 @@ type Application interface { // DeleteApplicationByClientID deletes the application with corresponding client_id value from the database. DeleteApplicationByClientID(ctx context.Context, clientID string) error - // GetClientByID ... + // GetClientByID fetches the application client from database with ID. GetClientByID(ctx context.Context, id string) (*gtsmodel.Client, error) - // PutClient ... + // PutClient puts the given application client in the database. PutClient(ctx context.Context, client *gtsmodel.Client) error - // DeleteClientByID ... + // DeleteClientByID deletes the application client from database with ID. DeleteClientByID(ctx context.Context, id string) error - // GetAllTokens ... + // GetAllTokens fetches all client oauth tokens from database. GetAllTokens(ctx context.Context) ([]*gtsmodel.Token, error) - // GetTokenByID ... + // GetTokenByID fetches the client oauth token from database with ID. GetTokenByID(ctx context.Context, id string) (*gtsmodel.Token, error) - // GetTokenByCode ... + // GetTokenByCode fetches the client oauth token from database with code. GetTokenByCode(ctx context.Context, code string) (*gtsmodel.Token, error) - // GetTokenByAccess ... + // GetTokenByAccess fetches the client oauth token from database with access code. GetTokenByAccess(ctx context.Context, access string) (*gtsmodel.Token, error) - // GetTokenByRefresh ... + // GetTokenByRefresh fetches the client oauth token from database with refresh code. GetTokenByRefresh(ctx context.Context, refresh string) (*gtsmodel.Token, error) - // PutToken ... + // PutToken puts given client oauth token in the database. PutToken(ctx context.Context, token *gtsmodel.Token) error - // DeleteTokenByID ... + // DeleteTokenByID deletes client oauth token from database with ID. DeleteTokenByID(ctx context.Context, id string) error - // DeleteTokenByCode ... + // DeleteTokenByCode deletes client oauth token from database with code. DeleteTokenByCode(ctx context.Context, code string) error - // DeleteTokenByAccess ... + // DeleteTokenByAccess deletes client oauth token from database with access code. DeleteTokenByAccess(ctx context.Context, access string) error - // DeleteTokenByRefresh ... + // DeleteTokenByRefresh deletes client oauth token from database with refresh code. DeleteTokenByRefresh(ctx context.Context, refresh string) error } diff --git a/internal/gtsmodel/token.go b/internal/gtsmodel/token.go index fd640abde..0586ae68a 100644 --- a/internal/gtsmodel/token.go +++ b/internal/gtsmodel/token.go @@ -19,7 +19,8 @@ import "time" -// Token is a translation of the gotosocial token with the ExpiresIn fields replaced with ExpiresAt. +// Token is a translation of the gotosocial token +// with the ExpiresIn fields replaced with ExpiresAt. type Token struct { ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created diff --git a/internal/httpclient/client.go b/internal/httpclient/client.go index 10fba5d42..445c6a9e5 100644 --- a/internal/httpclient/client.go +++ b/internal/httpclient/client.go @@ -178,6 +178,9 @@ func New(cfg Config) *Client { return &c } +// RoundTrip allows httpclient.Client{} to be used as an http.Transport{}, just calling Client{}.Do(). +func (c *Client) RoundTrip(r *http.Request) (rsp *http.Response, err error) { return c.Do(r) } + // Do will essentially perform http.Client{}.Do() with retry-backoff functionality. func (c *Client) Do(r *http.Request) (rsp *http.Response, err error) { diff --git a/internal/webpush/realsender.go b/internal/webpush/realsender.go index 8b3a1bd66..4c4657957 100644 --- a/internal/webpush/realsender.go +++ b/internal/webpush/realsender.go @@ -33,30 +33,20 @@ "github.com/superseriousbusiness/gotosocial/internal/filter/usermute" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" - "github.com/superseriousbusiness/gotosocial/internal/httpclient" "github.com/superseriousbusiness/gotosocial/internal/log" "github.com/superseriousbusiness/gotosocial/internal/state" "github.com/superseriousbusiness/gotosocial/internal/text" "github.com/superseriousbusiness/gotosocial/internal/typeutils" ) -// realSender is the production Web Push sender, backed by an HTTP client, DB, and worker pool. +// realSender is the production Web Push sender, +// backed by an HTTP client, DB, and worker pool. type realSender struct { httpClient *http.Client state *state.State converter *typeutils.Converter } -// NewRealSender creates a Sender from an http.Client instead of an httpclient.Client. -// This should only be used by NewSender and in tests. -func NewRealSender(httpClient *http.Client, state *state.State, converter *typeutils.Converter) Sender { - return &realSender{ - httpClient: httpClient, - state: state, - converter: converter, - } -} - func (r *realSender) Send( ctx context.Context, notification *gtsmodel.Notification, @@ -329,13 +319,3 @@ func formatNotificationBody(apiNotification *apimodel.Notification) string { func firstNBytesTrimSpace(s string, n int) string { return strings.TrimSpace(text.FirstNBytesByWords(strings.TrimSpace(s), n)) } - -// gtsHTTPClientRoundTripper helps wrap a GtS HTTP client back into a regular HTTP client, -// so that webpush-go can use our IP filters, bad hosts list, and retries. -type gtsHTTPClientRoundTripper struct { - httpClient *httpclient.Client -} - -func (r *gtsHTTPClientRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { - return r.httpClient.Do(request) -} diff --git a/internal/webpush/realsender_test.go b/internal/webpush/realsender_test.go index c94bbbb8e..8446fc47d 100644 --- a/internal/webpush/realsender_test.go +++ b/internal/webpush/realsender_test.go @@ -24,6 +24,9 @@ "testing" "time" + // for go:linkname + _ "unsafe" + "github.com/stretchr/testify/suite" "github.com/superseriousbusiness/gotosocial/internal/cleaner" "github.com/superseriousbusiness/gotosocial/internal/db" @@ -120,7 +123,7 @@ func (suite *RealSenderStandardTestSuite) SetupTest() { suite.oauthServer = testrig.NewTestOauthServer(suite.db) suite.emailSender = testrig.NewEmailSender("../../web/template/", nil) - suite.webPushSender = webpush.NewRealSender( + suite.webPushSender = newSenderWith( &http.Client{ Transport: suite, }, @@ -261,3 +264,6 @@ func (suite *RealSenderStandardTestSuite) TestServerError() { func TestRealSenderStandardTestSuite(t *testing.T) { suite.Run(t, &RealSenderStandardTestSuite{}) } + +//go:linkname newSenderWith github.com/superseriousbusiness/gotosocial/internal/webpush.newSenderWith +func newSenderWith(*http.Client, *state.State, *typeutils.Converter) webpush.Sender diff --git a/internal/webpush/sender.go b/internal/webpush/sender.go index 5331f049a..060118019 100644 --- a/internal/webpush/sender.go +++ b/internal/webpush/sender.go @@ -30,7 +30,9 @@ // Sender can send Web Push notifications. type Sender interface { - // Send queues up a notification for delivery to all of an account's Web Push subscriptions. + + // Send queues up a notification for delivery to + // all of an account's Web Push subscriptions. Send( ctx context.Context, notification *gtsmodel.Notification, @@ -41,14 +43,26 @@ type Sender interface { // NewSender creates a new sender from an HTTP client, DB, and worker pool. func NewSender(httpClient *httpclient.Client, state *state.State, converter *typeutils.Converter) Sender { - return NewRealSender( - &http.Client{ - Transport: >sHTTPClientRoundTripper{ - httpClient: httpClient, - }, - // Other fields are already set on the http.Client inside the httpclient.Client. + return &realSender{ + httpClient: &http.Client{ + // Pass in our wrapped httpclient.Client{} + // type as http.Transport{} in order to take + // advantage of retries, SSF protection etc. + Transport: httpClient, + + // Other http.Client{} fields are already + // set in embedded httpclient.Client{}. }, - state, - converter, - ) + state: state, + converter: converter, + } +} + +// an internal function purely existing for the webpush test package to link to and use a custom http.Client{}. +func newSenderWith(client *http.Client, state *state.State, converter *typeutils.Converter) Sender { //nolint:unused + return &realSender{ + httpClient: client, + state: state, + converter: converter, + } }