[chore] improved router logging, recovery and error handling (#705)

* move panic recovery to logging middleware, improve logging + panic recovery logic

Signed-off-by: kim <grufwub@gmail.com>

* remove dead code

Signed-off-by: kim <grufwub@gmail.com>

* remove skip paths code

Signed-off-by: kim <grufwub@gmail.com>

* re-enable log quoting

Signed-off-by: kim <grufwub@gmail.com>

* use human-friendly bytesize in logging body size

Signed-off-by: kim <grufwub@gmail.com>

* only disable quoting in debug builds

Signed-off-by: kim <grufwub@gmail.com>

* use logrus level instead of debug.DEBUG() to enable/disable quoting

Signed-off-by: kim <grufwub@gmail.com>

* shutup linter

Signed-off-by: kim <grufwub@gmail.com>

* fix instance tests

Signed-off-by: kim <grufwub@gmail.com>

* fix gin test contexts created with missing engine HTML renderer

Signed-off-by: kim <grufwub@gmail.com>

* add note regarding not logging query parameters

Signed-off-by: kim <grufwub@gmail.com>

* better explain 'DisableQuoting' logic

Signed-off-by: kim <grufwub@gmail.com>

* add license text

Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2022-07-12 08:32:20 +01:00 committed by GitHub
parent a465cefb8c
commit 6934ae378a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 526 additions and 190 deletions

1
go.mod
View file

@ -3,6 +3,7 @@ module github.com/superseriousbusiness/gotosocial
go 1.18
require (
codeberg.org/gruf/go-bytesize v0.2.1
codeberg.org/gruf/go-byteutil v1.0.2
codeberg.org/gruf/go-cache/v2 v2.1.1
codeberg.org/gruf/go-debug v1.2.0

2
go.sum
View file

@ -43,6 +43,8 @@ codeberg.org/gruf/go-bitutil v1.0.1/go.mod h1:3ezHnADoiRJs9jgn65AEZ3HY7dsabAYLmm
codeberg.org/gruf/go-bytes v1.0.0/go.mod h1:1v/ibfaosfXSZtRdW2rWaVrDXMc9E3bsi/M9Ekx39cg=
codeberg.org/gruf/go-bytes v1.0.2 h1:malqE42Ni+h1nnYWBUAJaDDtEzF4aeN4uPN8DfMNNvo=
codeberg.org/gruf/go-bytes v1.0.2/go.mod h1:1v/ibfaosfXSZtRdW2rWaVrDXMc9E3bsi/M9Ekx39cg=
codeberg.org/gruf/go-bytesize v0.2.1 h1:nbAta3FCYe3Q18osqg8Ylk/naOopdqEKiKMpo6KTpAA=
codeberg.org/gruf/go-bytesize v0.2.1/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
codeberg.org/gruf/go-byteutil v1.0.0/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
codeberg.org/gruf/go-byteutil v1.0.2 h1:OesVyK5VKWeWdeDR00zRJ+Oy8hjXx1pBhn7WVvcZWVE=
codeberg.org/gruf/go-byteutil v1.0.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=

View file

@ -82,7 +82,7 @@ func (suite *AccountStandardTestSuite) TearDownTest() {
}
func (suite *AccountStandardTestSuite) newContext(recorder *httptest.ResponseRecorder, requestMethod string, requestBody []byte, requestPath string, bodyContentType string) *gin.Context {
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))

View file

@ -31,6 +31,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type BlockTestSuite struct {
@ -40,7 +41,7 @@ type BlockTestSuite struct {
func (suite *BlockTestSuite) TestBlockSelf() {
testAcct := suite.testAccounts["local_account_1"]
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedAccount, testAcct)
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])

View file

@ -31,6 +31,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type FollowTestSuite struct {
@ -40,7 +41,7 @@ type FollowTestSuite struct {
func (suite *FollowTestSuite) TestFollowSelf() {
testAcct := suite.testAccounts["local_account_1"]
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedAccount, testAcct)
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])

View file

@ -100,7 +100,7 @@ func (suite *AdminStandardTestSuite) TearDownTest() {
}
func (suite *AdminStandardTestSuite) newContext(recorder *httptest.ResponseRecorder, requestMethod string, requestBody []byte, requestPath string, bodyContentType string) *gin.Context {
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["admin_account"])
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["admin_account"]))

View file

@ -111,7 +111,7 @@ func (suite *AuthStandardTestSuite) TearDownTest() {
func (suite *AuthStandardTestSuite) newContext(requestMethod string, requestPath string, requestBody []byte, bodyContentType string) (*gin.Context, *httptest.ResponseRecorder) {
// create the recorder and gin test context
recorder := httptest.NewRecorder()
ctx, engine := gin.CreateTestContext(recorder)
ctx, engine := testrig.CreateGinTestContext(recorder, nil)
// load templates into the engine
testrig.ConfigureTemplatesWithGin(engine, "../../../../web/template")

View file

@ -126,7 +126,7 @@ func (suite *ServeFileTestSuite) TestServeOriginalFileSuccessful() {
suite.NotNil(targetAttachment)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAttachment.URL, nil)
ctx.Request.Header.Set("accept", "*/*")
@ -172,7 +172,7 @@ func (suite *ServeFileTestSuite) TestServeSmallFileSuccessful() {
suite.NotNil(targetAttachment)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAttachment.Thumbnail.URL, nil)
ctx.Request.Header.Set("accept", "*/*")

View file

@ -96,7 +96,7 @@ func (suite *FollowRequestStandardTestSuite) TearDownTest() {
}
func (suite *FollowRequestStandardTestSuite) newContext(recorder *httptest.ResponseRecorder, requestMethod string, requestBody []byte, requestPath string, bodyContentType string) *gin.Context {
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))

View file

@ -98,27 +98,29 @@ func (suite *InstanceStandardTestSuite) TearDownTest() {
testrig.StandardStorageTeardown(suite.storage)
}
func (suite *InstanceStandardTestSuite) newContext(recorder *httptest.ResponseRecorder, requestMethod string, requestBody []byte, requestPath string, bodyContentType string) *gin.Context {
ctx, _ := gin.CreateTestContext(recorder)
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["admin_account"])
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["admin_account"]))
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["admin_account"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["admin_account"])
func (suite *InstanceStandardTestSuite) newContext(recorder *httptest.ResponseRecorder, method string, path string, body []byte, contentType string, auth bool) *gin.Context {
protocol := config.GetProtocol()
host := config.GetHost()
baseURI := fmt.Sprintf("%s://%s", protocol, host)
requestURI := fmt.Sprintf("%s/%s", baseURI, requestPath)
requestURI := fmt.Sprintf("%s/%s", baseURI, path)
ctx.Request = httptest.NewRequest(requestMethod, requestURI, bytes.NewReader(requestBody)) // the endpoint we're hitting
req := httptest.NewRequest(method, requestURI, bytes.NewReader(body)) // the endpoint we're hitting
if bodyContentType != "" {
ctx.Request.Header.Set("Content-Type", bodyContentType)
if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
ctx.Request.Header.Set("accept", "application/json")
req.Header.Set("accept", "application/json")
ctx, _ := testrig.CreateGinTestContext(recorder, req)
if auth {
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["admin_account"])
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["admin_account"]))
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["admin_account"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["admin_account"])
}
return ctx
}

View file

@ -49,7 +49,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
// call the handler
suite.instanceModule.InstanceUpdatePATCHHandler(ctx)
@ -79,7 +79,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
// call the handler
suite.instanceModule.InstanceUpdatePATCHHandler(ctx)
@ -109,7 +109,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
// call the handler
suite.instanceModule.InstanceUpdatePATCHHandler(ctx)
@ -137,7 +137,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch4() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
// call the handler
suite.instanceModule.InstanceUpdatePATCHHandler(ctx)
@ -166,7 +166,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch5() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))
@ -200,7 +200,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
// call the handler
suite.instanceModule.InstanceUpdatePATCHHandler(ctx)
@ -230,7 +230,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch7() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, instance.InstanceInformationPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPath, bodyBytes, w.FormDataContentType(), true)
// call the handler
suite.instanceModule.InstanceUpdatePATCHHandler(ctx)

View file

@ -26,7 +26,7 @@ import (
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/render"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/instance"
"github.com/superseriousbusiness/gotosocial/internal/config"
@ -40,7 +40,8 @@ type InstancePeersGetTestSuite struct {
func (suite *InstancePeersGetTestSuite) TestInstancePeersGetNoParams() {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, r := testrig.CreateGinTestContext(recorder, nil)
r.HTMLRender = render.HTMLDebug{}
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s", baseURI, instance.InstancePeersPath)
@ -63,11 +64,9 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetNoParamsUnauthorized
config.SetInstanceExposePeers(false)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s", baseURI, instance.InstancePeersPath)
ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil)
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", false)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -88,7 +87,7 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetNoParamsAuthorized()
recorder := httptest.NewRecorder()
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s", baseURI, instance.InstancePeersPath)
ctx := suite.newContext(recorder, http.MethodGet, []byte{}, requestURI, "")
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", true)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -105,11 +104,9 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetNoParamsAuthorized()
func (suite *InstancePeersGetTestSuite) TestInstancePeersGetOnlySuspended() {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s?filter=suspended", baseURI, instance.InstancePeersPath)
ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil)
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", false)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -128,11 +125,9 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetOnlySuspendedUnautho
config.SetInstanceExposeSuspended(false)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s?filter=suspended", baseURI, instance.InstancePeersPath)
ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil)
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", false)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -153,7 +148,7 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetOnlySuspendedAuthori
recorder := httptest.NewRecorder()
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s?filter=suspended", baseURI, instance.InstancePeersPath)
ctx := suite.newContext(recorder, http.MethodGet, []byte{}, requestURI, "")
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", true)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -170,11 +165,9 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetOnlySuspendedAuthori
func (suite *InstancePeersGetTestSuite) TestInstancePeersGetAll() {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s?filter=suspended,open", baseURI, instance.InstancePeersPath)
ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil)
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", false)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -202,11 +195,9 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetAllWithObfuscated()
suite.NoError(err)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s?filter=suspended,open", baseURI, instance.InstancePeersPath)
ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil)
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", false)
suite.instanceModule.InstancePeersGETHandler(ctx)
@ -223,11 +214,9 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetAllWithObfuscated()
func (suite *InstancePeersGetTestSuite) TestInstancePeersGetFunkyParams() {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
baseURI := fmt.Sprintf("%s://%s", config.GetProtocol(), config.GetHost())
requestURI := fmt.Sprintf("%s/%s?filter=aaaaaaaaaaaaaaaaa,open", baseURI, instance.InstancePeersPath)
ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil)
ctx := suite.newContext(recorder, http.MethodGet, requestURI, nil, "", true)
suite.instanceModule.InstancePeersGETHandler(ctx)

View file

@ -30,7 +30,6 @@ import (
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/suite"
mediamodule "github.com/superseriousbusiness/gotosocial/internal/api/client/media"
@ -130,7 +129,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessful() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -218,7 +217,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateLongDescription() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -265,7 +264,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateTooShortDescription() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])

View file

@ -130,7 +130,7 @@ func (suite *MediaUpdateTestSuite) TestUpdateImage() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -195,7 +195,7 @@ func (suite *MediaUpdateTestSuite) TestUpdateImageShortDescription() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])

View file

@ -31,6 +31,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type StatusBoostTestSuite struct {
@ -38,7 +39,6 @@ type StatusBoostTestSuite struct {
}
func (suite *StatusBoostTestSuite) TestPostBoost() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
@ -46,7 +46,7 @@ func (suite *StatusBoostTestSuite) TestPostBoost() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -112,7 +112,7 @@ func (suite *StatusBoostTestSuite) TestPostBoostOwnFollowersOnly() {
testUser := suite.testUsers["local_account_1"]
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, testUser)
@ -170,7 +170,6 @@ func (suite *StatusBoostTestSuite) TestPostBoostOwnFollowersOnly() {
// try to boost a status that's not boostable
func (suite *StatusBoostTestSuite) TestPostUnboostable() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
@ -178,7 +177,7 @@ func (suite *StatusBoostTestSuite) TestPostUnboostable() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -209,7 +208,6 @@ func (suite *StatusBoostTestSuite) TestPostUnboostable() {
// try to boost a status that's not visible to the user
func (suite *StatusBoostTestSuite) TestPostNotVisible() {
// stop local_account_2 following zork
err := suite.db.DeleteByID(context.Background(), suite.testFollows["local_account_2_local_account_1"].ID, &gtsmodel.Follow{})
suite.NoError(err)
@ -221,7 +219,7 @@ func (suite *StatusBoostTestSuite) TestPostNotVisible() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_2"])

View file

@ -28,7 +28,6 @@ import (
"net/url"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
@ -52,13 +51,12 @@ https://docs.gotosocial.org/en/latest/user_guide/posts/#links
// Post a new status with some custom visibility settings
func (suite *StatusCreateTestSuite) TestPostNewStatus() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -108,7 +106,6 @@ func (suite *StatusCreateTestSuite) TestPostNewStatus() {
// mention an account that is not yet known to the instance -- it should be looked up and put in the db
func (suite *StatusCreateTestSuite) TestMentionUnknownAccount() {
// first remove remote account 1 from the database so it gets looked up again
remoteAccount := suite.testAccounts["remote_account_1"]
if err := suite.db.DeleteByID(context.Background(), remoteAccount.ID, &gtsmodel.Account{}); err != nil {
@ -120,7 +117,7 @@ func (suite *StatusCreateTestSuite) TestMentionUnknownAccount() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -150,13 +147,12 @@ func (suite *StatusCreateTestSuite) TestMentionUnknownAccount() {
}
func (suite *StatusCreateTestSuite) TestPostAnotherNewStatus() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -186,13 +182,12 @@ func (suite *StatusCreateTestSuite) TestPostAnotherNewStatus() {
}
func (suite *StatusCreateTestSuite) TestPostNewStatusWithEmoji() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -234,7 +229,7 @@ func (suite *StatusCreateTestSuite) TestReplyToNonexistentStatus() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -266,7 +261,7 @@ func (suite *StatusCreateTestSuite) TestReplyToLocalStatus() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -309,7 +304,7 @@ func (suite *StatusCreateTestSuite) TestAttachNewMediaSuccess() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])

View file

@ -33,6 +33,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type StatusFaveTestSuite struct {
@ -41,7 +42,6 @@ type StatusFaveTestSuite struct {
// fave a status
func (suite *StatusFaveTestSuite) TestPostFave() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
@ -49,7 +49,7 @@ func (suite *StatusFaveTestSuite) TestPostFave() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -90,7 +90,6 @@ func (suite *StatusFaveTestSuite) TestPostFave() {
// try to fave a status that's not faveable
func (suite *StatusFaveTestSuite) TestPostUnfaveable() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
@ -98,7 +97,7 @@ func (suite *StatusFaveTestSuite) TestPostUnfaveable() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])

View file

@ -33,6 +33,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type StatusFavedByTestSuite struct {
@ -47,7 +48,7 @@ func (suite *StatusFavedByTestSuite) TestGetFavedBy() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_2"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_2"])

View file

@ -33,6 +33,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type StatusUnfaveTestSuite struct {
@ -41,7 +42,6 @@ type StatusUnfaveTestSuite struct {
// unfave a status
func (suite *StatusUnfaveTestSuite) TestPostUnfave() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
@ -50,7 +50,7 @@ func (suite *StatusUnfaveTestSuite) TestPostUnfave() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -91,7 +91,6 @@ func (suite *StatusUnfaveTestSuite) TestPostUnfave() {
// try to unfave a status that's already not faved
func (suite *StatusUnfaveTestSuite) TestPostAlreadyNotFaved() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
@ -100,7 +99,7 @@ func (suite *StatusUnfaveTestSuite) TestPostAlreadyNotFaved() {
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])

View file

@ -27,11 +27,11 @@ import (
"net/url"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/user"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
"golang.org/x/crypto/bcrypt"
)
@ -44,7 +44,7 @@ func (suite *PasswordChangeTestSuite) TestPasswordChangePOST() {
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -78,7 +78,7 @@ func (suite *PasswordChangeTestSuite) TestPasswordMissingOldPassword() {
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -105,7 +105,7 @@ func (suite *PasswordChangeTestSuite) TestPasswordIncorrectOldPassword() {
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
@ -133,7 +133,7 @@ func (suite *PasswordChangeTestSuite) TestPasswordWeakNewPassword() {
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])

View file

@ -22,7 +22,6 @@ import (
"context"
"net/http"
"codeberg.org/gruf/go-errors/v2"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
@ -86,47 +85,13 @@ func genericErrorHandler(c *gin.Context, instanceGet func(ctx context.Context, d
// if something goes wrong during the function, it will recover and just try to serve
// an appropriate application/json content-type error.
func ErrorHandler(c *gin.Context, errWithCode gtserror.WithCode, instanceGet func(ctx context.Context, domain string) (*apimodel.Instance, gtserror.WithCode)) {
path := c.Request.URL.Path
if raw := c.Request.URL.RawQuery; raw != "" {
path = path + "?" + raw
}
l := logrus.WithFields(logrus.Fields{
"path": path,
"error": errWithCode.Error(),
})
statusCode := errWithCode.Code()
if statusCode == http.StatusInternalServerError {
l.Error("Internal Server Error")
} else {
l.Debug("handling error")
}
// if we panic for any reason during error handling,
// we should still try to return a basic code
defer func() {
if p := recover(); p != nil {
// Fetch stacktrace up to this point
callers := errors.GetCallers(3, 10)
// Log this panic to the standard log
l = l.WithField("stacktrace", callers)
l.Errorf("recovered from panic: %v", p)
// Respond with determined error code
c.JSON(statusCode, gin.H{"error": errWithCode.Safe()})
}
}()
// discover if we're allowed to serve a nice html error page,
// or if we should just use a json. Normally we would want to
// check for a returned error, but if an error occurs here we
// can just fall back to default behavior (serve json error).
accept, _ := NegotiateAccept(c, HTMLOrJSONAcceptHeaders...)
if statusCode == http.StatusNotFound {
if errWithCode.Code() == http.StatusNotFound {
// use our special not found handler with useful status text
NotFoundHandler(c, instanceGet, accept)
} else {

View file

@ -96,7 +96,7 @@ func (suite *InboxPostTestSuite) TestPostBlock() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodPost, targetURI.String(), body) // the endpoint we're hitting
ctx.Request.Header.Set("Signature", signature)
ctx.Request.Header.Set("Date", dateHeader)
@ -199,7 +199,7 @@ func (suite *InboxPostTestSuite) TestPostUnblock() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodPost, targetURI.String(), body) // the endpoint we're hitting
ctx.Request.Header.Set("Signature", signature)
ctx.Request.Header.Set("Date", dateHeader)
@ -292,7 +292,7 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodPost, targetURI.String(), body) // the endpoint we're hitting
ctx.Request.Header.Set("Signature", signature)
ctx.Request.Header.Set("Date", dateHeader)
@ -416,7 +416,7 @@ func (suite *InboxPostTestSuite) TestPostDelete() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodPost, targetURI.String(), body) // the endpoint we're hitting
ctx.Request.Header.Set("Signature", signature)
ctx.Request.Header.Set("Date", dateHeader)

View file

@ -57,7 +57,7 @@ func (suite *OutboxGetTestSuite) TestGetOutbox() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAccount.OutboxURI, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)
@ -115,7 +115,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxFirstPage() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAccount.OutboxURI+"?page=true", nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)
@ -173,7 +173,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxNextPage() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAccount.OutboxURI+"?page=true&max_id=01F8MHAMCHF6Y650WCRSCP4WMY", nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)

View file

@ -60,7 +60,7 @@ func (suite *RepliesGetTestSuite) TestGetReplies() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetStatus.URI+"/replies", nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)
@ -124,7 +124,7 @@ func (suite *RepliesGetTestSuite) TestGetRepliesNext() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetStatus.URI+"/replies?only_other_accounts=false&page=true", nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)
@ -191,7 +191,7 @@ func (suite *RepliesGetTestSuite) TestGetRepliesLast() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetStatus.URI+"/replies?only_other_accounts=false&page=true&min_id=01FF25D5Q0DH7CHD57CTRS6WK0", nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)

View file

@ -59,7 +59,7 @@ func (suite *StatusGetTestSuite) TestGetStatus() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetStatus.URI, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)
@ -127,7 +127,7 @@ func (suite *StatusGetTestSuite) TestGetStatusLowercase() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, strings.ToLower(targetStatus.URI), nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)

View file

@ -60,7 +60,7 @@ func (suite *UserGetTestSuite) TestGetUser() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAccount.URI, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)
@ -141,7 +141,7 @@ func (suite *UserGetTestSuite) TestGetUserPublicKeyDeleted() {
// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, targetAccount.PublicKeyURI, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/activity+json")
ctx.Request.Header.Set("Signature", signedRequest.SignatureHeader)

View file

@ -26,7 +26,6 @@ import (
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/webfinger"
@ -49,7 +48,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUser() {
requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, host)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, requestPath, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/json")
@ -86,7 +85,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByHo
requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, host)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, requestPath, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/json")
@ -123,7 +122,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByAc
requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, accountDomain)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, requestPath, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/json")
@ -149,7 +148,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithoutAcct() {
requestPath := fmt.Sprintf("/%s?resource=%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, host)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Request = httptest.NewRequest(http.MethodGet, requestPath, nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/json")

View file

@ -41,12 +41,6 @@ func Initialize() error {
out := SplitErrOutputs(os.Stdout, os.Stderr)
logrus.SetOutput(out)
logrus.SetFormatter(&logrus.TextFormatter{
DisableColors: true,
DisableQuote: true,
FullTimestamp: true,
})
// check if a desired log level has been set
if lvl := config.GetLogLevel(); lvl != "" {
level, err := logrus.ParseLevel(lvl)
@ -60,6 +54,18 @@ func Initialize() error {
}
}
// set our custom formatter options
logrus.SetFormatter(&logrus.TextFormatter{
DisableColors: true,
FullTimestamp: true,
// By default, quoting is enabled to help differentiate key-value
// fields in log lines. But when debug (or higher, e.g. trace) logging
// is enabled, we disable this. This allows easier copy-pasting of
// entry fields without worrying about escaped quotes.
DisableQuote: logrus.GetLevel() >= logrus.DebugLevel,
})
// check if syslog has been enabled, and configure it if so
if config.GetSyslogEnabled() {
protocol := config.GetSyslogProtocol()

View file

@ -19,55 +19,78 @@
package router
import (
"fmt"
"net/http"
"os"
"time"
"codeberg.org/gruf/go-bytesize"
"codeberg.org/gruf/go-errors/v2"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
var skipPaths = map[string]interface{}{
"/api/v1/streaming": nil,
}
// loggingMiddleware provides a request logging and panic recovery gin handler.
func loggingMiddleware(c *gin.Context) {
// Initialize the logging fields
fields := make(logrus.Fields, 7)
func loggingMiddleware() gin.HandlerFunc {
logHandler := func(c *gin.Context) {
start := time.Now()
// Determine pre-handler time
before := time.Now()
defer func() {
code := c.Writer.Status()
path := c.Request.URL.Path
raw := c.Request.URL.RawQuery
// Process request
c.Next()
// Log only when path is not being skipped
if _, ok := skipPaths[path]; !ok {
latency := time.Since(start)
clientIP := c.ClientIP()
userAgent := c.Request.UserAgent()
method := c.Request.Method
statusCode := c.Writer.Status()
errorMessage := c.Errors.ByType(gin.ErrorTypePrivate).String()
bodySize := c.Writer.Size()
if raw != "" {
path = path + "?" + raw
if r := recover(); r != nil {
if c.Writer.Status() == 0 {
// No response was written, send a generic Internal Error
c.Writer.WriteHeader(http.StatusInternalServerError)
}
l := logrus.WithFields(logrus.Fields{
"latency": latency,
"clientIP": clientIP,
"userAgent": userAgent,
"method": method,
"statusCode": statusCode,
"path": path,
})
// Append panic information to the request ctx
_ = c.Error(fmt.Errorf("recovered panic: %v", r))
if errorMessage == "" {
l.Infof("[%s] %s: wrote %d bytes", latency, http.StatusText(statusCode), bodySize)
} else {
l.Errorf("[%s] %s: %s", latency, http.StatusText(statusCode), errorMessage)
// Dump a stacktrace to stderr
callers := errors.GetCallers(3, 10)
fmt.Fprintf(os.Stderr, "recovered panic: %v\n%s", r, callers)
}
// NOTE:
// It is very important here that we are ONLY logging
// the request path, and none of the query parameters.
// Query parameters can contain sensitive information
// and could lead to storing plaintext API keys in logs
// Set request logging fields
fields["latency"] = time.Since(before)
fields["clientIP"] = c.ClientIP()
fields["userAgent"] = c.Request.UserAgent()
fields["method"] = c.Request.Method
fields["statusCode"] = code
fields["path"] = path
// Create a log entry with fields
l := logrus.WithFields(fields)
l.Level = logrus.InfoLevel
if code >= 500 {
// This is a server error
l.Level = logrus.ErrorLevel
if len(c.Errors) > 0 {
// Add an error string log field
fields["error"] = c.Errors.String()
}
}
}
return logHandler
// Generate a nicer looking bytecount
size := bytesize.Size(c.Writer.Size())
// Finally, write log entry with status text body size
l.Logf(l.Level, "%s: wrote %s", http.StatusText(code), size)
}()
// Process request
c.Next()
}

View file

@ -143,9 +143,7 @@ func New(ctx context.Context, db db.DB) (Router, error) {
// create the actual engine here -- this is the core request routing handler for gts
engine := gin.New()
engine.Use(gin.RecoveryWithWriter(logrus.StandardLogger().Writer()))
engine.Use(loggingMiddleware())
engine.Use(loggingMiddleware)
// 8 MiB
engine.MaxMultipartMemory = 8 << 20
@ -175,7 +173,7 @@ func New(ctx context.Context, db db.DB) (Router, error) {
LoadTemplateFunctions(engine)
// load templates onto the engine
if err := loadTemplates(engine); err != nil {
if err := LoadTemplates(engine); err != nil {
return nil, err
}

View file

@ -31,7 +31,7 @@ import (
)
// LoadTemplates loads html templates for use by the given engine
func loadTemplates(engine *gin.Engine) error {
func LoadTemplates(engine *gin.Engine) error {
templateBaseDir := config.GetWebTemplateBaseDir()
if templateBaseDir == "" {
return fmt.Errorf("%s cannot be empty and must be a relative or absolute path", config.WebTemplateBaseDirFlag())

37
testrig/gin.go Normal file
View file

@ -0,0 +1,37 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package testrig
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
// CreateGinTextContext creates a new gin.Context suitable for a test, with an instantiated gin.Engine.
func CreateGinTestContext(rw http.ResponseWriter, r *http.Request) (*gin.Context, *gin.Engine) {
ctx, eng := gin.CreateTestContext(rw)
router.LoadTemplateFunctions(eng)
if err := router.LoadTemplates(eng); err != nil {
panic(err)
}
ctx.Request = r
return ctx, eng
}

9
vendor/codeberg.org/gruf/go-bytesize/LICENSE generated vendored Normal file
View file

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2021 gruf
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
vendor/codeberg.org/gruf/go-bytesize/README.md generated vendored Normal file
View file

@ -0,0 +1,3 @@
Byte size formatting and parsing.
todo: more robust tests

306
vendor/codeberg.org/gruf/go-bytesize/bytesize.go generated vendored Normal file
View file

@ -0,0 +1,306 @@
package bytesize
import (
"errors"
"math/bits"
"unsafe"
)
var (
// ErrInvalidUnit is returned when an invalid IEC/SI is provided.
ErrInvalidUnit = errors.New("bytesize: invalid unit")
// ErrInvalidFormat is returned when an invalid size value is provided.
ErrInvalidFormat = errors.New("bytesize: invalid format")
// bunits are the binary unit chars.
units = `kMGTPE`
// iecpows is a precomputed table of 1024^n.
iecpows = [...]float64{
float64(1024), // KiB
float64(1024 * 1024), // MiB
float64(1024 * 1024 * 1024), // GiB
float64(1024 * 1024 * 1024 * 1024), // TiB
float64(1024 * 1024 * 1024 * 1024 * 1024), // PiB
float64(1024 * 1024 * 1024 * 1024 * 1024 * 1024), // EiB
}
// sipows is a precomputed table of 1000^n.
sipows = [...]float64{
float64(1e3), // KB
float64(1e6), // MB
float64(1e9), // GB
float64(1e12), // TB
float64(1e15), // PB
float64(1e18), // EB
}
// bvals is a precomputed table of IEC unit values.
iecvals = [...]uint64{
'k': 1024,
'K': 1024,
'M': 1024 * 1024,
'G': 1024 * 1024 * 1024,
'T': 1024 * 1024 * 1024 * 1024,
'P': 1024 * 1024 * 1024 * 1024 * 1024,
'E': 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
}
// sivals is a precomputed table of SI unit values.
sivals = [...]uint64{
// ASCII numbers _aren't_ valid SI unit values,
// BUT if the space containing a possible unit
// char is checked with this table -- it is valid
// to provide no unit char so unit=1 works.
'0': 1,
'1': 1,
'2': 1,
'3': 1,
'4': 1,
'5': 1,
'6': 1,
'7': 1,
'8': 1,
'9': 1,
'k': 1e3,
'M': 1e6,
'G': 1e9,
'T': 1e12,
'P': 1e15,
'E': 1e18,
}
)
// Size is a casting for uint64 types that provides formatting
// methods for byte sizes in both IEC and SI units.
type Size uint64
// ParseSize will parse a valid Size from given string. Both IEC and SI units are supported.
func ParseSize(s string) (Size, error) {
// Parse units from string
unit, l, err := parseUnit(s)
if err != nil {
return 0, err
}
// Parse remaining string as float
f, n, err := atof64(s[:l])
if err != nil || n != l {
return 0, ErrInvalidFormat
}
return Size(uint64(f) * unit), nil
}
// AppendFormat defaults to using Size.AppendFormatIEC().
func (sz Size) AppendFormat(dst []byte) []byte {
return sz.AppendFormatIEC(dst) // default
}
// AppendFormatSI will append SI formatted size to 'dst'.
func (sz Size) AppendFormatSI(dst []byte) []byte {
if uint64(sz) < 1000 {
dst = itoa(dst, uint64(sz))
dst = append(dst, 'B')
return dst
} // above is fast-path, .appendFormat() is outlined
return sz.appendFormat(dst, 1000, &sipows, "B")
}
// AppendFormatIEC will append IEC formatted size to 'dst'.
func (sz Size) AppendFormatIEC(dst []byte) []byte {
if uint64(sz) < 1024 {
dst = itoa(dst, uint64(sz))
dst = append(dst, 'B')
return dst
} // above is fast-path, .appendFormat() is outlined
return sz.appendFormat(dst, 1024, &iecpows, "iB")
}
// appendFormat will append formatted Size to 'dst', depending on base, powers table and single unit suffix.
func (sz Size) appendFormat(dst []byte, base uint64, pows *[6]float64, sunit string) []byte {
const min = 0.75
// Larger number: get value of
// i / unit size. We have a 'min'
// threshold after which we prefer
// using the unit 1 down
n := bits.Len64(uint64(sz)) / 10
f := float64(sz) / pows[n-1]
if f < min {
f *= float64(base)
n--
}
// Append formatted float with units
dst = ftoa(dst, f)
dst = append(dst, units[n-1])
dst = append(dst, sunit...)
return dst
}
// StringSI returns an SI unit string format of Size.
func (sz Size) StringSI() string {
b := sz.AppendFormatSI(make([]byte, 0, 6))
return *(*string)(unsafe.Pointer(&b))
}
// StringIEC returns an IEC unit string format of Size.
func (sz Size) StringIEC() string {
b := sz.AppendFormatIEC(make([]byte, 0, 7))
return *(*string)(unsafe.Pointer(&b))
}
// String returns a string format of Size, defaults to IEC unit format.
func (sz Size) String() string {
return sz.StringIEC()
}
// parseUnit will parse the byte size unit from string 's'.
func parseUnit(s string) (uint64, int, error) {
var isIEC bool
// Check for string
if len(s) < 1 {
return 0, 0, ErrInvalidFormat
}
// Strip 'byte' unit suffix
if l := len(s) - 1; s[l] == 'B' {
s = s[:l]
// Check str remains
if len(s) < 1 {
return 0, 0, ErrInvalidFormat
}
}
// Strip IEC binary unit suffix
if l := len(s) - 1; s[l] == 'i' {
s = s[:l]
isIEC = true
// Check str remains
if len(s) < 1 {
return 0, 0, ErrInvalidFormat
}
}
// Location of unit char.
l := len(s) - 1
var unit uint64
switch c := int(s[l]); {
// Determine IEC unit in use
case isIEC && c < len(iecvals):
unit = iecvals[c]
if unit == 0 {
return 0, 0, ErrInvalidUnit
}
// Determine SI unit in use
case c < len(sivals):
unit = sivals[c]
switch unit {
case 0:
return 0, 0, ErrInvalidUnit
case 1:
l++
}
}
return unit, l, nil
}
// ftoa appends string formatted 'f' to 'dst', assumed < ~800.
func ftoa(dst []byte, f float64) []byte {
switch i := uint64(f); {
// Append with 2 d.p.
case i < 10:
f *= 10
// Calculate next dec. value
d1 := uint8(uint64(f) % 10)
f *= 10
// Calculate next dec. value
d2 := uint8(uint64(f) % 10)
// Round the final value
if uint64(f*10)%10 > 4 {
d2++
// Overflow, incr 'd1'
if d2 == 10 {
d2 = 0
d1++
// Overflow, incr 'i'
if d1 == 10 {
d1 = 0
i++
}
}
}
// Append decimal value
dst = itoa(dst, i)
dst = append(dst,
'.',
'0'+d1,
'0'+d2,
)
// Append with 1 d.p.
case i < 100:
f *= 10
// Calculate next dec. value
d1 := uint8(uint64(f) % 10)
// Round the final value
if uint64(f*10)%10 > 4 {
d1++
// Overflow, incr 'i'
if d1 == 10 {
d1 = 0
i++
}
}
// Append decimal value
dst = itoa(dst, i)
dst = append(dst, '.', '0'+d1)
// No decimal places
default:
dst = itoa(dst, i)
}
return dst
}
// itoa appends string formatted 'i' to 'dst'.
func itoa(dst []byte, i uint64) []byte {
// Assemble int in reverse order.
var b [4]byte
bp := len(b) - 1
// Append integer
for i >= 10 {
q := i / 10
b[bp] = byte('0' + i - q*10)
bp--
i = q
} // i < 10
b[bp] = byte('0' + i)
return append(dst, b[bp:]...)
}
//go:linkname atof64 strconv.atof64
func atof64(string) (float64, int, error)

3
vendor/modules.txt vendored
View file

@ -7,6 +7,9 @@ codeberg.org/gruf/go-bitutil
# codeberg.org/gruf/go-bytes v1.0.2
## explicit; go 1.14
codeberg.org/gruf/go-bytes
# codeberg.org/gruf/go-bytesize v0.2.1
## explicit; go 1.17
codeberg.org/gruf/go-bytesize
# codeberg.org/gruf/go-byteutil v1.0.2
## explicit; go 1.16
codeberg.org/gruf/go-byteutil