[bugfix] return 400 Bad Request on more cases of malformed AS data (#2399)

This commit is contained in:
kim 2023-11-30 16:22:34 +00:00 committed by GitHub
commit eb170003b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 1493 additions and 1013 deletions

View file

@ -328,29 +328,6 @@ func ExtractAttributedToURI(i WithAttributedTo) (*url.URL, error) {
return nil, gtserror.New("couldn't find iri for attributed to")
}
// ExtractPublished extracts the published time from the given
// WithPublished. Will return an error if the published property
// is not set, is not a time.Time, or is zero.
func ExtractPublished(i WithPublished) (time.Time, error) {
t := time.Time{}
publishedProp := i.GetActivityStreamsPublished()
if publishedProp == nil {
return t, gtserror.New("published prop was nil")
}
if !publishedProp.IsXMLSchemaDateTime() {
return t, gtserror.New("published prop was not date time")
}
t = publishedProp.Get()
if t.IsZero() {
return t, gtserror.New("published time was zero")
}
return t, nil
}
// ExtractIconURI extracts the first URI it can find from
// the given WithIcon which links to a supported image file.
// Input will look something like this:

View file

@ -416,6 +416,12 @@ type WithOutbox interface {
SetActivityStreamsOutbox(vocab.ActivityStreamsOutboxProperty)
}
// WithSharedInbox represents an activity with ActivityStreamsSharedInboxProperty
type WithSharedInbox interface {
GetActivityStreamsSharedInbox() vocab.ActivityStreamsSharedInboxProperty
SetActivityStreamsSharedInbox(vocab.ActivityStreamsSharedInboxProperty)
}
// WithFollowing represents an activity with ActivityStreamsFollowingProperty
type WithFollowing interface {
GetActivityStreamsFollowing() vocab.ActivityStreamsFollowingProperty

View file

@ -55,14 +55,10 @@ func MustSet[W, T any](fn func(W, T) error, with W, value T) {
// GetJSONLDId returns the ID of 'with', or nil.
func GetJSONLDId(with WithJSONLDId) *url.URL {
idProp := with.GetJSONLDId()
if idProp == nil {
if idProp == nil || !idProp.IsXMLSchemaAnyURI() {
return nil
}
id := idProp.Get()
if id == nil {
return nil
}
return id
return idProp.Get()
}
// SetJSONLDId sets the given URL to the JSONLD ID of 'with'.
@ -70,9 +66,9 @@ func SetJSONLDId(with WithJSONLDId, id *url.URL) {
idProp := with.GetJSONLDId()
if idProp == nil {
idProp = streams.NewJSONLDIdProperty()
with.SetJSONLDId(idProp)
}
idProp.SetIRI(id)
with.SetJSONLDId(idProp)
}
// SetJSONLDIdStr sets the given string to the JSONLDID of 'with'. Returns error
@ -139,14 +135,46 @@ func AppendBcc(with WithBcc, bcc ...*url.URL) {
}, bcc...)
}
// GetActor returns the IRIs contained in the Actor property of 'with'. Panics on entries with missing ID.
func GetActor(with WithActor) []*url.URL {
// GetURL returns the IRIs contained in the URL property of 'with'.
func GetURL(with WithURL) []*url.URL {
urlProp := with.GetActivityStreamsUrl()
if urlProp == nil || urlProp.Len() == 0 {
return nil
}
urls := make([]*url.URL, 0, urlProp.Len())
for i := 0; i < urlProp.Len(); i++ {
at := urlProp.At(i)
if at.IsXMLSchemaAnyURI() {
u := at.GetXMLSchemaAnyURI()
urls = append(urls, u)
}
}
return urls
}
// AppendURL appends the given URLs to the URL property of 'with'.
func AppendURL(with WithURL, url ...*url.URL) {
if len(url) == 0 {
return
}
urlProp := with.GetActivityStreamsUrl()
if urlProp == nil {
urlProp = streams.NewActivityStreamsUrlProperty()
with.SetActivityStreamsUrl(urlProp)
}
for _, u := range url {
urlProp.AppendXMLSchemaAnyURI(u)
}
}
// GetActorIRIs returns the IRIs contained in the Actor property of 'with'.
func GetActorIRIs(with WithActor) []*url.URL {
actorProp := with.GetActivityStreamsActor()
return getIRIs[vocab.ActivityStreamsActorPropertyIterator](actorProp)
}
// AppendActor appends the given IRIs to the Actor property of 'with'.
func AppendActor(with WithActor, actor ...*url.URL) {
// AppendActorIRIs appends the given IRIs to the Actor property of 'with'.
func AppendActorIRIs(with WithActor, actor ...*url.URL) {
appendIRIs(func() Property[vocab.ActivityStreamsActorPropertyIterator] {
actorProp := with.GetActivityStreamsActor()
if actorProp == nil {
@ -157,7 +185,25 @@ func AppendActor(with WithActor, actor ...*url.URL) {
}, actor...)
}
// GetAttributedTo returns the IRIs contained in the AttributedTo property of 'with'. Panics on entries with missing ID.
// GetObjectIRIs returns the IRIs contained in the Object property of 'with'.
func GetObjectIRIs(with WithObject) []*url.URL {
objectProp := with.GetActivityStreamsObject()
return getIRIs[vocab.ActivityStreamsObjectPropertyIterator](objectProp)
}
// AppendObjectIRIs appends the given IRIs to the Object property of 'with'.
func AppendObjectIRIs(with WithObject) {
appendIRIs(func() Property[vocab.ActivityStreamsObjectPropertyIterator] {
objectProp := with.GetActivityStreamsObject()
if objectProp == nil {
objectProp = streams.NewActivityStreamsObjectProperty()
with.SetActivityStreamsObject(objectProp)
}
return objectProp
})
}
// GetAttributedTo returns the IRIs contained in the AttributedTo property of 'with'.
func GetAttributedTo(with WithAttributedTo) []*url.URL {
attribProp := with.GetActivityStreamsAttributedTo()
return getIRIs[vocab.ActivityStreamsAttributedToPropertyIterator](attribProp)
@ -175,7 +221,7 @@ func AppendAttributedTo(with WithAttributedTo, attribTo ...*url.URL) {
}, attribTo...)
}
// GetInReplyTo returns the IRIs contained in the InReplyTo property of 'with'. Panics on entries with missing ID.
// GetInReplyTo returns the IRIs contained in the InReplyTo property of 'with'.
func GetInReplyTo(with WithInReplyTo) []*url.URL {
replyProp := with.GetActivityStreamsInReplyTo()
return getIRIs[vocab.ActivityStreamsInReplyToPropertyIterator](replyProp)
@ -193,10 +239,105 @@ func AppendInReplyTo(with WithInReplyTo, replyTo ...*url.URL) {
}, replyTo...)
}
// GetInbox returns the IRI contained in the Inbox property of 'with'.
func GetInbox(with WithInbox) *url.URL {
inboxProp := with.GetActivityStreamsInbox()
if inboxProp == nil || !inboxProp.IsIRI() {
return nil
}
return inboxProp.GetIRI()
}
// SetInbox sets the given IRI on the Inbox property of 'with'.
func SetInbox(with WithInbox, inbox *url.URL) {
inboxProp := with.GetActivityStreamsInbox()
if inboxProp == nil {
inboxProp = streams.NewActivityStreamsInboxProperty()
with.SetActivityStreamsInbox(inboxProp)
}
inboxProp.SetIRI(inbox)
}
// GetOutbox returns the IRI contained in the Outbox property of 'with'.
func GetOutbox(with WithOutbox) *url.URL {
outboxProp := with.GetActivityStreamsOutbox()
if outboxProp == nil || !outboxProp.IsIRI() {
return nil
}
return outboxProp.GetIRI()
}
// SetOutbox sets the given IRI on the Outbox property of 'with'.
func SetOutbox(with WithOutbox, outbox *url.URL) {
outboxProp := with.GetActivityStreamsOutbox()
if outboxProp == nil {
outboxProp = streams.NewActivityStreamsOutboxProperty()
with.SetActivityStreamsOutbox(outboxProp)
}
outboxProp.SetIRI(outbox)
}
// GetFollowers returns the IRI contained in the Following property of 'with'.
func GetFollowing(with WithFollowing) *url.URL {
followProp := with.GetActivityStreamsFollowing()
if followProp == nil || !followProp.IsIRI() {
return nil
}
return followProp.GetIRI()
}
// SetFollowers sets the given IRI on the Following property of 'with'.
func SetFollowing(with WithFollowing, following *url.URL) {
followProp := with.GetActivityStreamsFollowing()
if followProp == nil {
followProp = streams.NewActivityStreamsFollowingProperty()
with.SetActivityStreamsFollowing(followProp)
}
followProp.SetIRI(following)
}
// GetFollowers returns the IRI contained in the Followers property of 'with'.
func GetFollowers(with WithFollowers) *url.URL {
followProp := with.GetActivityStreamsFollowers()
if followProp == nil || !followProp.IsIRI() {
return nil
}
return followProp.GetIRI()
}
// SetFollowers sets the given IRI on the Followers property of 'with'.
func SetFollowers(with WithFollowers, followers *url.URL) {
followProp := with.GetActivityStreamsFollowers()
if followProp == nil {
followProp = streams.NewActivityStreamsFollowersProperty()
with.SetActivityStreamsFollowers(followProp)
}
followProp.SetIRI(followers)
}
// GetFeatured returns the IRI contained in the Featured property of 'with'.
func GetFeatured(with WithFeatured) *url.URL {
featuredProp := with.GetTootFeatured()
if featuredProp == nil || !featuredProp.IsIRI() {
return nil
}
return featuredProp.GetIRI()
}
// SetFeatured sets the given IRI on the Featured property of 'with'.
func SetFeatured(with WithFeatured, featured *url.URL) {
featuredProp := with.GetTootFeatured()
if featuredProp == nil {
featuredProp = streams.NewTootFeaturedProperty()
with.SetTootFeatured(featuredProp)
}
featuredProp.SetIRI(featured)
}
// GetPublished returns the time contained in the Published property of 'with'.
func GetPublished(with WithPublished) time.Time {
publishProp := with.GetActivityStreamsPublished()
if publishProp == nil {
if publishProp == nil || !publishProp.IsXMLSchemaDateTime() {
return time.Time{}
}
return publishProp.Get()
@ -215,7 +356,7 @@ func SetPublished(with WithPublished, published time.Time) {
// GetEndTime returns the time contained in the EndTime property of 'with'.
func GetEndTime(with WithEndTime) time.Time {
endTimeProp := with.GetActivityStreamsEndTime()
if endTimeProp == nil {
if endTimeProp == nil || !endTimeProp.IsXMLSchemaDateTime() {
return time.Time{}
}
return endTimeProp.Get()
@ -240,7 +381,8 @@ func GetClosed(with WithClosed) []time.Time {
closed := make([]time.Time, 0, closedProp.Len())
for i := 0; i < closedProp.Len(); i++ {
at := closedProp.At(i)
if t := at.GetXMLSchemaDateTime(); !t.IsZero() {
if at.IsXMLSchemaDateTime() {
t := at.GetXMLSchemaDateTime()
closed = append(closed, t)
}
}
@ -265,7 +407,7 @@ func AppendClosed(with WithClosed, closed ...time.Time) {
// GetVotersCount returns the integer contained in the VotersCount property of 'with', if found.
func GetVotersCount(with WithVotersCount) int {
votersProp := with.GetTootVotersCount()
if votersProp == nil {
if votersProp == nil || !votersProp.IsXMLSchemaNonNegativeInteger() {
return 0
}
return votersProp.Get()
@ -281,6 +423,25 @@ func SetVotersCount(with WithVotersCount, count int) {
votersProp.Set(count)
}
// GetDiscoverable returns the boolean contained in the Discoverable property of 'with'.
func GetDiscoverable(with WithDiscoverable) bool {
discoverProp := with.GetTootDiscoverable()
if discoverProp == nil || !discoverProp.IsXMLSchemaBoolean() {
return false
}
return discoverProp.Get()
}
// SetDiscoverable sets the given boolean on the Discoverable property of 'with'.
func SetDiscoverable(with WithDiscoverable, discoverable bool) {
discoverProp := with.GetTootDiscoverable()
if discoverProp == nil {
discoverProp = streams.NewTootDiscoverableProperty()
with.SetTootDiscoverable(discoverProp)
}
discoverProp.Set(discoverable)
}
func getIRIs[T TypeOrIRI](prop Property[T]) []*url.URL {
if prop == nil || prop.Len() == 0 {
return nil

View file

@ -42,7 +42,7 @@ func (suite *ResolveTestSuite) TestResolveDocumentAsAccountable() {
b := []byte(suite.typeToJson(suite.document1))
accountable, err := ap.ResolveAccountable(context.Background(), b)
suite.True(gtserror.WrongType(err))
suite.True(gtserror.IsWrongType(err))
suite.EqualError(err, "ResolveAccountable: cannot resolve vocab type *typedocument.ActivityStreamsDocument as accountable")
suite.Nil(accountable)
}

View file

@ -491,6 +491,46 @@ func (suite *InboxPostTestSuite) TestPostEmptyCreate() {
)
}
func (suite *InboxPostTestSuite) TestPostCreateMalformedBlock() {
var (
blockingAcc = suite.testAccounts["remote_account_1"]
blockedAcc = suite.testAccounts["local_account_1"]
activityID = blockingAcc.URI + "/some-new-activity/01FG9C441MCTW3R2W117V2PQK3"
)
block := streams.NewActivityStreamsBlock()
// set the actor property to the block-ing account's URI
actorProp := streams.NewActivityStreamsActorProperty()
actorIRI := testrig.URLMustParse(blockingAcc.URI)
actorProp.AppendIRI(actorIRI)
block.SetActivityStreamsActor(actorProp)
// set the ID property to the blocks's URI
idProp := streams.NewJSONLDIdProperty()
idProp.Set(testrig.URLMustParse(activityID))
block.SetJSONLDId(idProp)
// set the object property with MISSING block-ed URI.
objectProp := streams.NewActivityStreamsObjectProperty()
block.SetActivityStreamsObject(objectProp)
// set the TO property to the target account's IRI
toProp := streams.NewActivityStreamsToProperty()
toIRI := testrig.URLMustParse(blockedAcc.URI)
toProp.AppendIRI(toIRI)
block.SetActivityStreamsTo(toProp)
suite.inboxPost(
block,
blockingAcc,
blockedAcc,
http.StatusBadRequest,
`{"error":"Bad Request: malformed incoming activity"}`,
suite.signatureCheck,
)
}
func (suite *InboxPostTestSuite) TestPostFromBlockedAccount() {
var (
requestingAccount = suite.testAccounts["remote_account_1"]

View file

@ -34,7 +34,7 @@ var SentinelError = errors.New("BUG: error should not be returned") //nolint:rev
// ignoreErrors is an error matching function used to signal which errors
// the result caches should NOT hold onto. these amount to anything non-permanent.
func ignoreErrors(err error) bool {
return !errorsv2.Comparable(
return !errorsv2.IsV2(
err,
// the only cacheable errs,

View file

@ -43,7 +43,7 @@ func (s *sender) sendTemplate(template string, subject string, data any, toAddre
}
if err := smtp.SendMail(s.hostAddress, s.auth, s.from, toAddresses, msg); err != nil {
return gtserror.SetType(err, gtserror.TypeSMTP)
return gtserror.SetSMTP(err)
}
return nil

View file

@ -175,7 +175,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountWithUnknownUsername()
"thisaccountdoesnotexist",
config.GetHost(),
)
suite.True(gtserror.Unretrievable(err))
suite.True(gtserror.IsUnretrievable(err))
suite.EqualError(err, db.ErrNoEntries.Error())
suite.Nil(fetchedAccount)
}
@ -189,7 +189,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountWithUnknownUsernameDom
"thisaccountdoesnotexist",
"localhost:8080",
)
suite.True(gtserror.Unretrievable(err))
suite.True(gtserror.IsUnretrievable(err))
suite.EqualError(err, db.ErrNoEntries.Error())
suite.Nil(fetchedAccount)
}
@ -202,7 +202,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountWithUnknownUserURI() {
fetchingAccount.Username,
testrig.URLMustParse("http://localhost:8080/users/thisaccountdoesnotexist"),
)
suite.True(gtserror.Unretrievable(err))
suite.True(gtserror.IsUnretrievable(err))
suite.EqualError(err, db.ErrNoEntries.Error())
suite.Nil(fetchedAccount)
}

View file

@ -229,7 +229,7 @@ func (d *Dereferencer) DereferenceStatusAncestors(ctx context.Context, username
l.Warnf("orphaned status: http error dereferencing parent: %v)", err)
return nil
case gtserror.Unretrievable(err):
case gtserror.IsUnretrievable(err):
// Not retrievable for some other reason, so just
// bail for now; we can try again later if necessary.
l.Warnf("orphaned status: parent unretrievable: %v)", err)
@ -354,7 +354,7 @@ stackLoop:
// - any http type error for a new status returns unretrievable
_, statusable, _, err := d.getStatusByURI(ctx, username, itemIRI)
if err != nil {
if !gtserror.Unretrievable(err) {
if !gtserror.IsUnretrievable(err) {
l.Errorf("error dereferencing remote status %s: %v", itemIRI, err)
}
continue itemLoop

View file

@ -200,13 +200,18 @@ func (f *federatingActor) PostInboxScheme(ctx context.Context, w http.ResponseWr
//
// Post the activity to the Actor's inbox and trigger side effects .
if err := f.sideEffectActor.PostInbox(ctx, inboxID, activity); err != nil {
// Special case: We know it is a bad request if the object or
// target properties needed to be populated, but weren't.
// Special case: We know it is a bad request if the object or target
// props needed to be populated, or we failed parsing activity details.
// Send the rejection to the peer.
if errors.Is(err, pub.ErrObjectRequired) || errors.Is(err, pub.ErrTargetRequired) {
// Log the original error but return something a bit more generic.
log.Warnf(ctx, "malformed incoming activity: %v", err)
const text = "malformed activity: missing Object and / or Target"
if errors.Is(err, pub.ErrObjectRequired) ||
errors.Is(err, pub.ErrTargetRequired) ||
gtserror.IsMalformed(err) {
// Log malformed activities to help debug.
l = l.WithField("activity", activity)
l.Warnf("malformed incoming activity: %v", err)
const text = "malformed incoming activity"
return false, gtserror.NewErrorBadRequest(errors.New(text), text)
}
@ -234,7 +239,7 @@ func (f *federatingActor) PostInboxScheme(ctx context.Context, w http.ResponseWr
// This check may be removed when the `Exists()` func
// is updated, and/or federating callbacks are handled
// properly.
if !errorsv2.Comparable(
if !errorsv2.IsV2(
err,
db.ErrAlreadyExists,
db.ErrNoEntries,

View file

@ -113,7 +113,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,
// If an actor URI has been set, create a new ID
// based on actor (i.e. followER not the followEE).
if uri := ap.GetActor(follow); len(uri) == 1 {
if uri := ap.GetActorIRIs(follow); len(uri) == 1 {
if actorAccount, err := f.state.DB.GetAccountByURI(ctx, uri[0].String()); err == nil {
newID, err := id.NewRandomULID()
if err != nil {

View file

@ -35,39 +35,36 @@ const (
errorTypeKey
unrtrvableKey
wrongTypeKey
// Types returnable from Type(...).
TypeSMTP ErrorType = "smtp" // smtp (mail)
smtpKey
malformedKey
)
// Unretrievable checks error for a stored "unretrievable" flag.
//
// Unretrievable indicates that a call to retrieve a resource
// IsUnretrievable indicates that a call to retrieve a resource
// (account, status, attachment, etc) could not be fulfilled,
// either because it was not found locally, or because some
// prerequisite remote resource call failed, making it impossible
// to return the item.
func Unretrievable(err error) bool {
func IsUnretrievable(err error) bool {
_, ok := errors.Value(err, unrtrvableKey).(struct{})
return ok
}
// SetUnretrievable will wrap the given error to store an "unretrievable"
// flag, returning wrapped error. See "Unretrievable" for example use-cases.
// flag, returning wrapped error. See Unretrievable() for example use-cases.
func SetUnretrievable(err error) error {
return errors.WithValue(err, unrtrvableKey, struct{}{})
}
// WrongType checks error for a stored "wrong type" flag. Wrong type
// IsWrongType checks error for a stored "wrong type" flag. Wrong type
// indicates that an ActivityPub URI returned a type we weren't expecting:
// Statusable instead of Accountable, or vice versa, for example.
func WrongType(err error) bool {
func IsWrongType(err error) bool {
_, ok := errors.Value(err, wrongTypeKey).(struct{})
return ok
}
// SetWrongType will wrap the given error to store a "wrong type" flag,
// returning wrapped error. See "WrongType" for example use-cases.
// returning wrapped error. See IsWrongType() for example use-cases.
func SetWrongType(err error) error {
return errors.WithValue(err, wrongTypeKey, struct{}{})
}
@ -86,29 +83,41 @@ func WithStatusCode(err error, code int) error {
return errors.WithValue(err, statusCodeKey, code)
}
// NotFound checks error for a stored "not found" flag. For example
// an error from an outgoing HTTP request due to DNS lookup.
func NotFound(err error) bool {
// IsNotFound checks error for a stored "not found" flag. For
// example an error from an outgoing HTTP request due to DNS lookup.
func IsNotFound(err error) bool {
_, ok := errors.Value(err, notFoundKey).(struct{})
return ok
}
// SetNotFound will wrap the given error to store a "not found" flag,
// returning wrapped error. See NotFound() for example use-cases.
// returning wrapped error. See IsNotFound() for example use-cases.
func SetNotFound(err error) error {
return errors.WithValue(err, notFoundKey, struct{}{})
}
// Type checks error for a stored "type" value. For example
// an error from sending an email may set a value of "smtp"
// to indicate this was an SMTP error.
func Type(err error) ErrorType {
s, _ := errors.Value(err, errorTypeKey).(ErrorType)
return s
// IsSMTP checks error for a stored "smtp" flag. For
// example an error from outgoing SMTP email attempt.
func IsSMTP(err error) bool {
_, ok := errors.Value(err, smtpKey).(struct{})
return ok
}
// SetType will wrap the given error to store a "type" value,
// returning wrapped error. See Type() for example use-cases.
func SetType(err error, errType ErrorType) error {
return errors.WithValue(err, errorTypeKey, errType)
// SetSMTP will wrap the given error to store an "smtp" flag,
// returning wrapped error. See IsSMTP() for example use-cases.
func SetSMTP(err error) error {
return errors.WithValue(err, smtpKey, struct{}{})
}
// IsMalformed checks error for a stored "malformed" flag. For
// example an error from an incoming ActivityStreams type conversion.
func IsMalformed(err error) bool {
_, ok := errors.Value(err, malformedKey).(struct{})
return ok
}
// SetMalformed will wrap the given error to store a "malformed" flag,
// returning wrapped error. See IsMalformed() for example use-cases.
func SetMalformed(err error) error {
return errors.WithValue(err, malformedKey, struct{}{})
}

View file

@ -61,7 +61,7 @@ func newfAt(calldepth int, msgf string, args ...any) error {
}
}
// caller fetches the calling function name, skipping 'depth'. Results are cached per PC.
// caller fetches the calling function name, skipping 'depth'.
func caller(depth int) string {
var pcs [1]uintptr

View file

@ -39,13 +39,16 @@ type WithCode interface {
// Unwrap returns the original error.
// This should *NEVER* be returned to a client as it may contain sensitive information.
Unwrap() error
// Error serializes the original internal error for debugging within the GoToSocial logs.
// This should *NEVER* be returned to a client as it may contain sensitive information.
Error() string
// Safe returns the API-safe version of the error for serialization towards a client.
// There's not much point logging this internally because it won't contain much helpful information.
Safe() string
// Code returns the status code for serving to a client.
// Code returns the status code for serving to a client.
Code() int
}

View file

@ -294,7 +294,7 @@ func (c *Client) DoSigned(r *http.Request, sign SignFunc) (rsp *http.Response, e
_ = rsp.Body.Close()
rsp = nil
} else if errorsv2.Comparable(err,
} else if errorsv2.IsV2(err,
context.DeadlineExceeded,
context.Canceled,
ErrBodyTooLarge,

View file

@ -22,7 +22,7 @@ import (
"strings"
)
// Caller fetches the calling function name, skipping 'depth'. Results are cached per PC.
// Caller fetches the calling function name, skipping 'depth'.
func Caller(depth int) string {
var pcs [1]uintptr

29
internal/log/format.go Normal file
View file

@ -0,0 +1,29 @@
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// 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 log
import "codeberg.org/gruf/go-kv/format"
// VarDump returns a serialized, useful log / error output of given variable.
func VarDump(a any) string {
buf := getBuf()
format.Appendf(buf, "{:v}", a)
s := string(buf.B)
putBuf(buf)
return s
}

View file

@ -95,7 +95,7 @@ func (p *ProcessingEmoji) load(ctx context.Context) (*gtsmodel.Emoji, bool, erro
defer func() {
// This is only done when ctx NOT cancelled.
done = err == nil || !errors.Comparable(err,
done = err == nil || !errors.IsV2(err,
context.Canceled,
context.DeadlineExceeded,
)

View file

@ -115,7 +115,7 @@ func (p *ProcessingMedia) load(ctx context.Context) (*gtsmodel.MediaAttachment,
defer func() {
// This is only done when ctx NOT cancelled.
done = err == nil || !errorsv2.Comparable(err,
done = err == nil || !errorsv2.IsV2(err,
context.Canceled,
context.DeadlineExceeded,
)

View file

@ -20,6 +20,7 @@ package middleware
import (
"fmt"
"net/http"
"runtime"
"time"
"codeberg.org/gruf/go-bytesize"
@ -56,7 +57,10 @@ func Logger(logClientIP bool) gin.HandlerFunc {
_ = c.Error(err)
// Dump a stacktrace to error log
callers := errors.GetCallers(3, 10)
pcs := make([]uintptr, 10)
n := runtime.Callers(3, pcs)
iter := runtime.CallersFrames(pcs[:n])
callers := errors.Callers(gatherFrames(iter, n))
log.WithContext(c.Request.Context()).
WithField("stacktrace", callers).Error(err)
}
@ -80,8 +84,9 @@ func Logger(logClientIP bool) gin.HandlerFunc {
}
// Create log entry with fields
l := log.WithContext(c.Request.Context()).
WithFields(fields...)
l := log.New()
l = l.WithContext(c.Request.Context())
l = l.WithFields(fields...)
// Default is info
lvl := level.INFO
@ -119,3 +124,19 @@ func Logger(logClientIP bool) gin.HandlerFunc {
c.Next()
}
}
// gatherFrames gathers runtime frames from a frame iterator.
func gatherFrames(iter *runtime.Frames, n int) []runtime.Frame {
if iter == nil {
return nil
}
frames := make([]runtime.Frame, 0, n)
for {
f, ok := iter.Next()
if !ok {
break
}
frames = append(frames, f)
}
return frames
}

View file

@ -47,7 +47,7 @@ func (p *Processor) EmailTest(ctx context.Context, account *gtsmodel.Account, to
}
if err := p.emailSender.SendTestEmail(toAddress, testData); err != nil {
if errorType := gtserror.Type(err); errorType == gtserror.TypeSMTP {
if gtserror.IsSMTP(err) {
// An error occurred during the SMTP part.
// We should indicate this to the caller, as
// it will likely help them debug the issue.

View file

@ -382,7 +382,7 @@ func (p *Processor) accountsByNamestring(
if err != nil {
// Check for semi-expected error types.
// On one of these, we can continue.
if !gtserror.Unretrievable(err) && !gtserror.WrongType(err) {
if !gtserror.IsUnretrievable(err) && !gtserror.IsWrongType(err) {
err = gtserror.Newf("error looking up @%s@%s as account: %w", username, domain, err)
return gtserror.NewErrorInternalError(err)
}
@ -491,7 +491,7 @@ func (p *Processor) byURI(
if err != nil {
// Check for semi-expected error types.
// On one of these, we can continue.
if !gtserror.Unretrievable(err) && !gtserror.WrongType(err) {
if !gtserror.IsUnretrievable(err) && !gtserror.IsWrongType(err) {
err = gtserror.Newf("error looking up %s as account: %w", uri, err)
return gtserror.NewErrorInternalError(err)
}
@ -509,7 +509,7 @@ func (p *Processor) byURI(
if err != nil {
// Check for semi-expected error types.
// On one of these, we can continue.
if !gtserror.Unretrievable(err) && !gtserror.WrongType(err) {
if !gtserror.IsUnretrievable(err) && !gtserror.IsWrongType(err) {
err = gtserror.Newf("error looking up %s as status: %w", uri, err)
return gtserror.NewErrorInternalError(err)
}

View file

@ -92,7 +92,7 @@ func (p *Processor) Lookup(
false, // never resolve!
)
if err != nil {
if gtserror.Unretrievable(err) {
if gtserror.IsUnretrievable(err) {
// ErrNotRetrievable is fine, just wrap it in
// a 404 to indicate we couldn't find anything.
err := fmt.Errorf("%s not found", query)

File diff suppressed because it is too large Load diff

View file

@ -363,7 +363,7 @@ func (suite *ASToInternalTestSuite) TestParseFlag3() {
report, err := suite.typeconverter.ASFlagToReport(context.Background(), asFlag)
suite.Nil(report)
suite.EqualError(err, "ASFlagToReport: account with uri http://localhost:8080/users/mr_e_man could not be found in the db")
suite.EqualError(err, "ASFlagToReport: error getting target account http://localhost:8080/users/mr_e_man from database: sql: no rows in result set")
}
func (suite *ASToInternalTestSuite) TestParseFlag4() {
@ -388,7 +388,7 @@ func (suite *ASToInternalTestSuite) TestParseFlag4() {
report, err := suite.typeconverter.ASFlagToReport(context.Background(), asFlag)
suite.Nil(report)
suite.EqualError(err, "ASFlagToReport: flaggable objects contained no recognizable target account uri")
suite.EqualError(err, "ASFlagToReport: missing target account uri for http://fossbros-anonymous.io/db22128d-884e-4358-9935-6a7c3940535d")
}
func (suite *ASToInternalTestSuite) TestParseFlag5() {

View file

@ -1713,7 +1713,7 @@ func (c *Converter) PollVoteToASCreate(
ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(create), id)
// Set Create actor appropriately.
ap.AppendActor(create, authorIRI)
ap.AppendActorIRIs(create, authorIRI)
// Set publish time for activity.
ap.SetPublished(create, vote.CreatedAt)

View file

@ -19,7 +19,6 @@ package typeutils
import (
"context"
"errors"
"fmt"
"net/url"
"path"
@ -27,7 +26,6 @@ import (
"strconv"
"strings"
"github.com/superseriousbusiness/gotosocial/internal/ap"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@ -94,22 +92,6 @@ func misskeyReportInlineURLs(content string) []*url.URL {
return urls
}
// getURI is a shortcut/util function for extracting
// the JSONLDId URI of an Activity or Object.
func getURI(withID ap.WithJSONLDId) (*url.URL, string, error) {
idProp := withID.GetJSONLDId()
if idProp == nil {
return nil, "", errors.New("id prop was nil")
}
if !idProp.IsIRI() {
return nil, "", errors.New("id prop was not an IRI")
}
id := idProp.Get()
return id, id.String(), nil
}
// placeholdUnknownAttachments separates any attachments with type `unknown`
// out of the given slice, and returns an `<aside>` tag containing links to
// those attachments, as well as the slice of remaining "known" attachments.

View file

@ -103,7 +103,7 @@ func wrapStatusableInActivity(activity ap.Activityable, status ap.Statusable, ir
appendStatusableToActivity(activity, status, iriOnly)
ap.AppendTo(activity, ap.GetTo(status)...)
ap.AppendCc(activity, ap.GetCc(status)...)
ap.AppendActor(activity, ap.GetAttributedTo(status)...)
ap.AppendActorIRIs(activity, ap.GetAttributedTo(status)...)
ap.SetPublished(activity, ap.GetPublished(status))
}