mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-28 05:03:32 -06:00
[bugfix] return 400 Bad Request on more cases of malformed AS data (#2399)
This commit is contained in:
parent
5fd2e427bb
commit
eb170003b8
47 changed files with 1493 additions and 1013 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
2
internal/cache/util.go
vendored
2
internal/cache/util.go
vendored
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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{}{})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
29
internal/log/format.go
Normal 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
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue