[chore] replaces nested ifs with switch cases, removes defer 'onFail()' being passed to funcs (#3143)

This commit is contained in:
kim 2024-07-27 09:09:02 +00:00 committed by GitHub
parent d9e70b942f
commit ecc114fc00
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -49,14 +49,42 @@ func (d *Dereferencer) isPermittedStatus(
existing *gtsmodel.Status, existing *gtsmodel.Status,
status *gtsmodel.Status, status *gtsmodel.Status,
) ( ) (
bool, // is permitted? permitted bool, // is permitted?
error, err error,
) { ) {
// our failure condition handling switch {
// at the end of this function for case status.Account.IsSuspended():
// the case of permission = false. // we shouldn't reach this point, log to poke devs to investigate.
onFalse := func() (bool, error) { log.Warnf(ctx, "status author suspended: %s", status.AccountURI)
if existing != nil { permitted = false
case status.InReplyTo != nil:
// Status is a reply, check permissivity.
permitted, err = d.isPermittedReply(ctx,
requestUser,
status,
)
if err != nil {
return false, gtserror.Newf("error checking reply permissivity: %w", err)
}
case status.BoostOf != nil:
// Status is a boost, check permissivity.
permitted, err = d.isPermittedBoost(ctx,
requestUser,
status,
)
if err != nil {
return false, gtserror.Newf("error checking boost permissivity: %w", err)
}
default:
// In all other cases
// permit this status.
permitted = true
}
if !permitted && existing != nil {
log.Infof(ctx, "deleting unpermitted: %s", existing.URI) log.Infof(ctx, "deleting unpermitted: %s", existing.URI)
// Delete existing status from database as it's no longer permitted. // Delete existing status from database as it's no longer permitted.
@ -64,55 +92,24 @@ func (d *Dereferencer) isPermittedStatus(
log.Errorf(ctx, "error deleting %s after permissivity fail: %v", existing.URI, err) log.Errorf(ctx, "error deleting %s after permissivity fail: %v", existing.URI, err)
} }
} }
return false, nil
}
if status.Account.IsSuspended() { return
// The status author is suspended,
// this shouldn't have reached here
// but it's a fast check anyways.
log.Debugf(ctx,
"status author %s is suspended",
status.AccountURI,
)
return onFalse()
}
if inReplyTo := status.InReplyTo; inReplyTo != nil {
return d.isPermittedReply(
ctx,
requestUser,
status,
inReplyTo,
onFalse,
)
} else if boostOf := status.BoostOf; boostOf != nil {
return d.isPermittedBoost(
ctx,
requestUser,
status,
boostOf,
onFalse,
)
}
// Nothing else stopping this.
return true, nil
} }
func (d *Dereferencer) isPermittedReply( func (d *Dereferencer) isPermittedReply(
ctx context.Context, ctx context.Context,
requestUser string, requestUser string,
status *gtsmodel.Status, status *gtsmodel.Status,
inReplyTo *gtsmodel.Status,
onFalse func() (bool, error),
) (bool, error) { ) (bool, error) {
// Extract reply from status.
inReplyTo := status.InReplyTo
if inReplyTo.BoostOfID != "" { if inReplyTo.BoostOfID != "" {
// We do not permit replies to // We do not permit replies to
// boost wrapper statuses. (this // boost wrapper statuses. (this
// shouldn't be able to happen). // shouldn't be able to happen).
log.Info(ctx, "rejecting reply to boost wrapper status") log.Info(ctx, "rejecting reply to boost wrapper status")
return onFalse() return false, nil
} }
// Check visibility of local // Check visibility of local
@ -130,7 +127,7 @@ func (d *Dereferencer) isPermittedReply(
// Our status is not visible to the // Our status is not visible to the
// account trying to do the reply. // account trying to do the reply.
if !visible { if !visible {
return onFalse() return false, nil
} }
} }
@ -147,7 +144,7 @@ func (d *Dereferencer) isPermittedReply(
if replyable.Forbidden() { if replyable.Forbidden() {
// Replier is not permitted // Replier is not permitted
// to do this interaction. // to do this interaction.
return onFalse() return false, nil
} }
if replyable.Permitted() && if replyable.Permitted() &&
@ -186,7 +183,7 @@ func (d *Dereferencer) isPermittedReply(
return true, nil return true, nil
} }
return onFalse() return false, nil
} }
// Status claims to be approved, check // Status claims to be approved, check
@ -199,14 +196,12 @@ func (d *Dereferencer) isPermittedReply(
status.URI, status.URI,
inReplyTo.AccountURI, inReplyTo.AccountURI,
); err != nil { ); err != nil {
// Error dereferencing means we couldn't // Error dereferencing means we couldn't
// get the Accept right now or it wasn't // get the Accept right now or it wasn't
// valid, so we shouldn't store this status. // valid, so we shouldn't store this status.
// log.Errorf(ctx, "undereferencable ApprovedByURI: %v", err)
// Do log the error though as it may be return false, nil
// interesting for admins to see.
log.Info(ctx, "rejecting reply with undereferenceable ApprovedByURI: %v", err)
return onFalse()
} }
// Status has been approved. // Status has been approved.
@ -218,15 +213,16 @@ func (d *Dereferencer) isPermittedBoost(
ctx context.Context, ctx context.Context,
requestUser string, requestUser string,
status *gtsmodel.Status, status *gtsmodel.Status,
boostOf *gtsmodel.Status,
onFalse func() (bool, error),
) (bool, error) { ) (bool, error) {
// Extract boost from status.
boostOf := status.BoostOf
if boostOf.BoostOfID != "" { if boostOf.BoostOfID != "" {
// We do not permit boosts of // We do not permit boosts of
// boost wrapper statuses. (this // boost wrapper statuses. (this
// shouldn't be able to happen). // shouldn't be able to happen).
log.Info(ctx, "rejecting boost of boost wrapper status") return false, nil
return onFalse()
} }
// Check visibility of local // Check visibility of local
@ -244,7 +240,7 @@ func (d *Dereferencer) isPermittedBoost(
// Our status is not visible to the // Our status is not visible to the
// account trying to do the boost. // account trying to do the boost.
if !visible { if !visible {
return onFalse() return false, nil
} }
} }
@ -261,7 +257,7 @@ func (d *Dereferencer) isPermittedBoost(
if boostable.Forbidden() { if boostable.Forbidden() {
// Booster is not permitted // Booster is not permitted
// to do this interaction. // to do this interaction.
return onFalse() return false, nil
} }
if boostable.Permitted() && if boostable.Permitted() &&
@ -300,7 +296,7 @@ func (d *Dereferencer) isPermittedBoost(
return true, nil return true, nil
} }
return onFalse() return false, nil
} }
// Boost claims to be approved, check // Boost claims to be approved, check
@ -313,14 +309,12 @@ func (d *Dereferencer) isPermittedBoost(
status.URI, status.URI,
boostOf.AccountURI, boostOf.AccountURI,
); err != nil { ); err != nil {
// Error dereferencing means we couldn't // Error dereferencing means we couldn't
// get the Accept right now or it wasn't // get the Accept right now or it wasn't
// valid, so we shouldn't store this status. // valid, so we shouldn't store this status.
// log.Errorf(ctx, "undereferencable ApprovedByURI: %v", err)
// Do log the error though as it may be return false, nil
// interesting for admins to see.
log.Info(ctx, "rejecting boost with undereferenceable ApprovedByURI: %v", err)
return onFalse()
} }
// Status has been approved. // Status has been approved.
@ -339,8 +333,8 @@ func (d *Dereferencer) validateApprovedBy(
ctx context.Context, ctx context.Context,
requestUser string, requestUser string,
approvedByURIStr string, // Eg., "https://example.org/users/someone/accepts/01J2736AWWJ3411CPR833F6D03" approvedByURIStr string, // Eg., "https://example.org/users/someone/accepts/01J2736AWWJ3411CPR833F6D03"
expectedObject string, // Eg., "https://some.instance.example.org/users/someone_else/statuses/01J27414TWV9F7DC39FN8ABB5R" expectObjectURIStr string, // Eg., "https://some.instance.example.org/users/someone_else/statuses/01J27414TWV9F7DC39FN8ABB5R"
expectedActor string, // Eg., "https://example.org/users/someone" expectActorURIStr string, // Eg., "https://example.org/users/someone"
) error { ) error {
approvedByURI, err := url.Parse(approvedByURIStr) approvedByURI, err := url.Parse(approvedByURIStr)
if err != nil { if err != nil {
@ -354,14 +348,14 @@ func (d *Dereferencer) validateApprovedBy(
return err return err
} }
transport, err := d.transportController.NewTransportForUsername(ctx, requestUser) tsport, err := d.transportController.NewTransportForUsername(ctx, requestUser)
if err != nil { if err != nil {
err := gtserror.Newf("error creating transport: %w", err) err := gtserror.Newf("error creating transport: %w", err)
return err return err
} }
// Make the call to resolve into an Acceptable. // Make the call to resolve into an Acceptable.
rsp, err := transport.Dereference(ctx, approvedByURI) rsp, err := tsport.Dereference(ctx, approvedByURI)
if err != nil { if err != nil {
err := gtserror.Newf("error dereferencing %s: %w", approvedByURIStr, err) err := gtserror.Newf("error dereferencing %s: %w", approvedByURIStr, err)
return err return err
@ -385,82 +379,83 @@ func (d *Dereferencer) validateApprovedBy(
// have changed (i.e. we followed some redirects). // have changed (i.e. we followed some redirects).
rspURL := rsp.Request.URL rspURL := rsp.Request.URL
rspURLStr := rspURL.String() rspURLStr := rspURL.String()
if rspURLStr != approvedByURIStr { switch {
// Final URI was different from approvedByURIStr. case rspURLStr == approvedByURIStr:
// i.e. from here, rspURLStr != approvedByURIStr.
// //
// Make sure it's at least on the same host as // Make sure it's at least on the same host as
// what we expected (ie., we weren't redirected // what we expected (ie., we weren't redirected
// across domains), and make sure it's the same // across domains), and make sure it's the same
// as the ID of the Accept we were returned. // as the ID of the Accept we were returned.
if rspURL.Host != approvedByURI.Host { case rspURL.Host != approvedByURI.Host:
err := gtserror.Newf( return gtserror.Newf(
"final dereference host %s did not match approvedByURI host %s", "final dereference host %s did not match approvedByURI host %s",
rspURL.Host, approvedByURI.Host, rspURL.Host, approvedByURI.Host,
) )
return err case acceptURIStr != rspURLStr:
} return gtserror.Newf(
if acceptURIStr != rspURLStr {
err := gtserror.Newf(
"final dereference uri %s did not match returned Accept ID/URI %s", "final dereference uri %s did not match returned Accept ID/URI %s",
rspURLStr, acceptURIStr, rspURLStr, acceptURIStr,
) )
return err
}
} }
// Ensure the Accept URI has the same host // Extract the actor IRI and string from Accept.
// as the Accept Actor, so we know we're
// not dealing with someone on a different
// domain just pretending to be the Actor.
actorIRIs := ap.GetActorIRIs(acceptable) actorIRIs := ap.GetActorIRIs(acceptable)
if len(actorIRIs) != 1 { actorIRI, actorIRIStr := extractIRI(actorIRIs)
err := gtserror.New("resolved Accept actor(s) length was not 1") switch {
case actorIRIStr == "":
err := gtserror.New("missing Accept actor IRI")
return gtserror.SetMalformed(err) return gtserror.SetMalformed(err)
}
actorIRI := actorIRIs[0]
actorStr := actorIRI.String()
if actorIRI.Host != acceptURI.Host {
err := gtserror.Newf(
"Accept Actor %s was not the same host as Accept %s",
actorStr, acceptURIStr,
)
return err
}
// Ensure the Accept Actor is who we expect // Ensure the Accept Actor is who we expect
// it to be, and not someone else trying to // it to be, and not someone else trying to
// do an Accept for an interaction with a // do an Accept for an interaction with a
// statusable they don't own. // statusable they don't own.
if actorStr != expectedActor { case actorIRI.Host != acceptURI.Host:
err := gtserror.Newf( return gtserror.Newf(
"Accept Actor %s was not the same as expected actor %s", "Accept Actor %s was not the same host as Accept %s",
actorStr, expectedActor, actorIRIStr, acceptURIStr,
)
// Ensure the Accept Actor is who we expect
// it to be, and not someone else trying to
// do an Accept for an interaction with a
// statusable they don't own.
case actorIRIStr != expectActorURIStr:
return gtserror.Newf(
"Accept Actor %s was not the same as expected actor %s",
actorIRIStr, expectActorURIStr,
) )
return err
} }
// Extract the object IRI string from Accept.
objectIRIs := ap.GetObjectIRIs(acceptable)
_, objectIRIStr := extractIRI(objectIRIs)
switch {
case objectIRIStr == "":
err := gtserror.New("missing Accept object IRI")
return gtserror.SetMalformed(err)
// Ensure the Accept Object is what we expect // Ensure the Accept Object is what we expect
// it to be, ie., it's Accepting the interaction // it to be, ie., it's Accepting the interaction
// we need it to Accept, and not something else. // we need it to Accept, and not something else.
objectIRIs := ap.GetObjectIRIs(acceptable) case objectIRIStr != expectObjectURIStr:
if len(objectIRIs) != 1 { return gtserror.Newf(
err := gtserror.New("resolved Accept object(s) length was not 1")
return err
}
objectIRI := objectIRIs[0]
objectStr := objectIRI.String()
if objectStr != expectedObject {
err := gtserror.Newf(
"resolved Accept Object uri %s was not the same as expected object %s", "resolved Accept Object uri %s was not the same as expected object %s",
objectStr, expectedObject, objectIRIStr, expectObjectURIStr,
) )
return err
} }
return nil return nil
} }
// extractIRI is shorthand to extract the first IRI
// url.URL{} object and serialized form from slice.
func extractIRI(iris []*url.URL) (*url.URL, string) {
if len(iris) == 0 {
return nil, ""
}
u := iris[0]
return u, u.String()
}