check domain blocks way earlier on

This commit is contained in:
tsmethurst 2021-06-30 14:22:46 +02:00
commit 5bf7b46cf4
19 changed files with 255 additions and 77 deletions

View file

@ -19,10 +19,12 @@
package user
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// FollowersGETHandler returns a collection of URIs for followers of the target user, formatted so that other AP servers can understand it.
@ -46,9 +48,14 @@ func (m *Module) FollowersGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)
// make a copy of the context to pass along so we don't break anything
cp := c.Copy()
user, err := m.processor.GetFediFollowers(requestedUsername, cp.Request) // GetFediUser handles auth as well
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
user, err := m.processor.GetFediFollowers(ctx, requestedUsername, c.Request.URL) // GetFediUser handles auth as well
if err != nil {
l.Info(err.Error())
c.JSON(err.Code(), gin.H{"error": err.Safe()})

View file

@ -19,10 +19,12 @@
package user
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// FollowingGETHandler returns a collection of URIs for accounts that the target user follows, formatted so that other AP servers can understand it.
@ -46,9 +48,14 @@ func (m *Module) FollowingGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)
// make a copy of the context to pass along so we don't break anything
cp := c.Copy()
user, err := m.processor.GetFediFollowing(requestedUsername, cp.Request) // handles auth as well
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
user, err := m.processor.GetFediFollowing(ctx, requestedUsername, c.Request.URL) // handles auth as well
if err != nil {
l.Info(err.Error())
c.JSON(err.Code(), gin.H{"error": err.Safe()})

View file

@ -19,11 +19,13 @@
package user
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// InboxPOSTHandler deals with incoming POST requests to an actor's inbox.
@ -40,7 +42,14 @@ func (m *Module) InboxPOSTHandler(c *gin.Context) {
return
}
posted, err := m.processor.InboxPost(c.Request.Context(), c.Writer, c.Request)
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
posted, err := m.processor.InboxPost(ctx, c.Writer, c.Request)
if err != nil {
if withCode, ok := err.(gtserror.WithCode); ok {
l.Debug(withCode.Error())

View file

@ -1,10 +1,12 @@
package user
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// PublicKeyGETHandler should be served at eg https://example.org/users/:username/main-key.
@ -32,9 +34,14 @@ func (m *Module) PublicKeyGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)
// make a copy of the context to pass along so we don't break anything
cp := c.Copy()
user, err := m.processor.GetFediUser(requestedUsername, cp.Request) // GetFediUser handles auth as well
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
user, err := m.processor.GetFediUser(ctx, requestedUsername, c.Request.URL) // GetFediUser handles auth as well
if err != nil {
l.Info(err.Error())
c.JSON(err.Code(), gin.H{"error": err.Safe()})

View file

@ -1,10 +1,12 @@
package user
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// StatusGETHandler serves the target status as an activitystreams NOTE so that other AP servers can parse it.
@ -34,9 +36,14 @@ func (m *Module) StatusGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)
// make a copy of the context to pass along so we don't break anything
cp := c.Copy()
status, err := m.processor.GetFediStatus(requestedUsername, requestedStatusID, cp.Request) // handles auth as well
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
status, err := m.processor.GetFediStatus(ctx, requestedUsername, requestedStatusID, c.Request.URL) // handles auth as well
if err != nil {
l.Info(err.Error())
c.JSON(err.Code(), gin.H{"error": err.Safe()})

View file

@ -19,10 +19,12 @@
package user
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// UsersGETHandler should be served at https://example.org/users/:username.
@ -54,9 +56,14 @@ func (m *Module) UsersGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)
// make a copy of the context to pass along so we don't break anything
cp := c.Copy()
user, err := m.processor.GetFediUser(requestedUsername, cp.Request) // GetFediUser handles auth as well
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
user, err := m.processor.GetFediUser(ctx, requestedUsername, c.Request.URL) // GetFediUser handles auth as well
if err != nil {
l.Info(err.Error())
c.JSON(err.Code(), gin.H{"error": err.Safe()})

View file

@ -19,12 +19,14 @@
package webfinger
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// WebfingerGETRequest handles requests to, for example, https://example.org/.well-known/webfinger?resource=acct:some_user@example.org
@ -68,7 +70,14 @@ func (m *Module) WebfingerGETRequest(c *gin.Context) {
return
}
resp, err := m.processor.GetWebfingerAccount(username, c.Request)
// transfer the signature verifier from the gin context to the request context
ctx := c.Request.Context()
verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, util.APRequestingPublicKeyVerifier, verifier)
}
resp, err := m.processor.GetWebfingerAccount(ctx, username, c.Request.URL)
if err != nil {
l.Debugf("aborting request with an error: %s", err.Error())
c.JSON(err.Code(), gin.H{"error": err.Safe()})

View file

@ -24,6 +24,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
@ -33,18 +34,21 @@ const robotsPath = "/robots.txt"
type Module struct {
config *config.Config
log *logrus.Logger
db db.DB
}
// New returns a new security module
func New(config *config.Config, log *logrus.Logger) api.ClientModule {
func New(config *config.Config, db db.DB, log *logrus.Logger) api.ClientModule {
return &Module{
config: config,
log: log,
db: db,
}
}
// Route attaches security middleware to the given router
func (m *Module) Route(s router.Router) error {
s.AttachMiddleware(m.SignatureCheck)
s.AttachMiddleware(m.FlocBlock)
s.AttachMiddleware(m.ExtraHeaders)
s.AttachMiddleware(m.UserAgentBlock)

View file

@ -0,0 +1,66 @@
package security
import (
"net/http"
"net/url"
"github.com/gin-gonic/gin"
"github.com/go-fed/httpsig"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
func (m *Module) SignatureCheck(c *gin.Context) {
l := m.log.WithField("func", "DomainBlockChecker")
// set this extra field for signature validation
c.Request.Header.Set("host", m.config.Host)
// create the verifier from the request
// if the request is signed, it will have a signature header
verifier, err := httpsig.NewVerifier(c.Request)
if err == nil {
// the request was signed!
// The key ID should be given in the signature so that we know where to fetch it from the remote server.
// This will be something like https://example.org/users/whatever_requesting_user#main-key
requestingPublicKeyID, err := url.Parse(verifier.KeyId())
if err == nil && requestingPublicKeyID != nil {
// we managed to parse the url!
// if the domain is blocked we want to bail as early as possible
blockedDomain, err := m.blockedDomain(requestingPublicKeyID.Host)
if err != nil {
l.Errorf("could not tell if domain %s was blocked or not: %s", requestingPublicKeyID.Host, err)
c.AbortWithStatus(http.StatusInternalServerError)
return
}
if blockedDomain {
l.Infof("domain %s is blocked", requestingPublicKeyID.Host)
c.AbortWithStatus(http.StatusForbidden)
return
}
// set the verifier on the context here to save some work further down the line
c.Set(string(util.APRequestingPublicKeyVerifier), verifier)
}
}
}
func (m *Module) blockedDomain(host string) (bool, error) {
b := &gtsmodel.DomainBlock{}
err := m.db.GetWhere([]db.Where{{Key: "domain", Value: host, CaseInsensitive: true}}, b)
if err == nil {
// block exists
return true, nil
}
if _, ok := err.(db.ErrNoEntries); ok {
// there are no entries so there's no block
return false, nil
}
// there's an actual error
return false, err
}

View file

@ -138,7 +138,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, c *config.Config, log
fileServerModule := fileserver.New(c, processor, log)
adminModule := admin.New(c, processor, log)
statusModule := status.New(c, processor, log)
securityModule := security.New(c, log)
securityModule := security.New(c, dbService, log)
streamingModule := streaming.New(c, processor, log)
apis := []api.ClientModule{

View file

@ -84,7 +84,7 @@ var Start cliactions.GTSAction = func(ctx context.Context, _ *config.Config, log
fileServerModule := fileserver.New(c, processor, log)
adminModule := admin.New(c, processor, log)
statusModule := status.New(c, processor, log)
securityModule := security.New(c, log)
securityModule := security.New(c, dbService, log)
streamingModule := streaming.New(c, processor, log)
apis := []api.ClientModule{

View file

@ -25,7 +25,6 @@ import (
"encoding/pem"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
@ -35,6 +34,7 @@ import (
"github.com/go-fed/httpsig"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
/*
@ -115,35 +115,30 @@ func getPublicKeyFromResponse(c context.Context, b []byte, keyID *url.URL) (voca
//
// Also note that this function *does not* dereference the remote account that the signature key is associated with.
// Other functions should use the returned URL to dereference the remote account, if required.
func (f *federator) AuthenticateFederatedRequest(requestedUsername string, r *http.Request) (*url.URL, bool, error) {
func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedUsername string) (*url.URL, bool, error) {
l := f.log.WithField("func", "AuthenticateFederatedRequest")
var publicKey interface{}
var pkOwnerURI *url.URL
var err error
// set this extra field for signature validation
r.Header.Set("host", f.config.Host)
verifier, err := httpsig.NewVerifier(r)
if err != nil {
return nil, false, fmt.Errorf("could not create http sig verifier: %s", err)
// thanks to signaturecheck.go in the security package, we should already have a signature verifier set on the context
vi := ctx.Value(util.APRequestingPublicKeyVerifier)
if vi == nil {
l.Debug("request wasn't signed")
return nil, false, nil // request wasn't signed
}
verifier, ok := vi.(httpsig.Verifier)
if !ok {
l.Debug("couldn't extract sig verifier")
return nil, false, nil // couldn't extract the verifier
}
// The key ID should be given in the signature so that we know where to fetch it from the remote server.
// This will be something like https://example.org/users/whatever_requesting_user#main-key
requestingPublicKeyID, err := url.Parse(verifier.KeyId())
if err != nil {
return nil, false, fmt.Errorf("could not parse key id into a url: %s", err)
}
// if the domain is blocked we want to make as few calls towards it as possible, so already bail here if that's the case!
blockedDomain, err := f.blockedDomain(requestingPublicKeyID.Host)
if err != nil {
return nil, false, fmt.Errorf("could not tell if domain %s was blocked or not: %s", requestingPublicKeyID.Host, err)
}
if blockedDomain {
f.log.Infof("domain %s is blocked", requestingPublicKeyID.Host)
return nil, false, nil
l.Debug("couldn't parse public key URL")
return nil, false, nil // couldn't parse the public key ID url
}
requestingRemoteAccount := &gtsmodel.Account{}

View file

@ -119,7 +119,7 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr
return nil, false, fmt.Errorf("could not fetch requested account with username %s: %s", username, err)
}
publicKeyOwnerURI, authenticated, err := f.AuthenticateFederatedRequest(requestedAccount.Username, r)
publicKeyOwnerURI, authenticated, err := f.AuthenticateFederatedRequest(ctx, requestedAccount.Username)
if err != nil {
l.Debugf("request not authenticated: %s", err)
return ctx, false, err

View file

@ -19,7 +19,7 @@
package federation
import (
"net/http"
"context"
"net/url"
"sync"
@ -48,7 +48,7 @@ type Federator interface {
// If the request does not pass authentication, or there's a domain block, nil, false, nil will be returned.
//
// If something goes wrong during authentication, nil, false, and an error will be returned.
AuthenticateFederatedRequest(username string, r *http.Request) (*url.URL, bool, error)
AuthenticateFederatedRequest(ctx context.Context, username string) (*url.URL, bool, error)
// FingerRemoteAccount performs a webfinger lookup for a remote account, using the .well-known path. It will return the ActivityPub URI for that
// account, or an error if it doesn't exist or can't be retrieved.
FingerRemoteAccount(requestingUsername string, targetUsername string, targetDomain string) (*url.URL, error)

View file

@ -20,6 +20,7 @@ package processing
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
@ -89,7 +90,7 @@ func (p *processor) dereferenceFediRequest(username string, requestingAccountURI
return requestingAccount, nil
}
func (p *processor) GetFediUser(requestedUsername string, request *http.Request) (interface{}, gtserror.WithCode) {
func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode) {
// get the account the request is referring to
requestedAccount := &gtsmodel.Account{}
if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil {
@ -98,17 +99,17 @@ func (p *processor) GetFediUser(requestedUsername string, request *http.Request)
var requestedPerson vocab.ActivityStreamsPerson
var err error
if util.IsPublicKeyPath(request.URL) {
if util.IsPublicKeyPath(requestURL) {
// if it's a public key path, we don't need to authenticate but we'll only serve the bare minimum user profile needed for the public key
requestedPerson, err = p.tc.AccountToASMinimal(requestedAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
} else if util.IsUserPath(request.URL) {
} else if util.IsUserPath(requestURL) {
// if it's a user path, we want to fully authenticate the request before we serve any data, and then we can serve a more complete profile
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(requestedUsername, request)
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(ctx, requestedUsername)
if err != nil || !authenticated {
return nil, gtserror.NewErrorNotAuthorized(err)
return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized")
}
// if we're already handshaking/dereferencing a remote account, we can skip the dereferencing part
@ -144,7 +145,7 @@ func (p *processor) GetFediUser(requestedUsername string, request *http.Request)
return data, nil
}
func (p *processor) GetFediFollowers(requestedUsername string, request *http.Request) (interface{}, gtserror.WithCode) {
func (p *processor) GetFediFollowers(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode) {
// get the account the request is referring to
requestedAccount := &gtsmodel.Account{}
if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil {
@ -152,9 +153,9 @@ func (p *processor) GetFediFollowers(requestedUsername string, request *http.Req
}
// authenticate the request
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(requestedUsername, request)
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(ctx, requestedUsername)
if err != nil || !authenticated {
return nil, gtserror.NewErrorNotAuthorized(err)
return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized")
}
requestingAccount, err := p.dereferenceFediRequest(requestedUsername, requestingAccountURI)
@ -189,7 +190,7 @@ func (p *processor) GetFediFollowers(requestedUsername string, request *http.Req
return data, nil
}
func (p *processor) GetFediFollowing(requestedUsername string, request *http.Request) (interface{}, gtserror.WithCode) {
func (p *processor) GetFediFollowing(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode) {
// get the account the request is referring to
requestedAccount := &gtsmodel.Account{}
if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil {
@ -197,9 +198,9 @@ func (p *processor) GetFediFollowing(requestedUsername string, request *http.Req
}
// authenticate the request
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(requestedUsername, request)
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(ctx, requestedUsername)
if err != nil || !authenticated {
return nil, gtserror.NewErrorNotAuthorized(err)
return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized")
}
requestingAccount, err := p.dereferenceFediRequest(requestedUsername, requestingAccountURI)
@ -234,7 +235,7 @@ func (p *processor) GetFediFollowing(requestedUsername string, request *http.Req
return data, nil
}
func (p *processor) GetFediStatus(requestedUsername string, requestedStatusID string, request *http.Request) (interface{}, gtserror.WithCode) {
func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string, requestedStatusID string, requestURL *url.URL) (interface{}, gtserror.WithCode) {
// get the account the request is referring to
requestedAccount := &gtsmodel.Account{}
if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil {
@ -242,9 +243,9 @@ func (p *processor) GetFediStatus(requestedUsername string, requestedStatusID st
}
// authenticate the request
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(requestedUsername, request)
requestingAccountURI, authenticated, err := p.federator.AuthenticateFederatedRequest(ctx, requestedUsername)
if err != nil || !authenticated {
return nil, gtserror.NewErrorNotAuthorized(err)
return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized")
}
requestingAccount, err := p.dereferenceFediRequest(requestedUsername, requestingAccountURI)
@ -294,7 +295,7 @@ func (p *processor) GetFediStatus(requestedUsername string, requestedStatusID st
return data, nil
}
func (p *processor) GetWebfingerAccount(requestedUsername string, request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode) {
func (p *processor) GetWebfingerAccount(ctx context.Context, requestedUsername string, requestURL *url.URL) (*apimodel.WellKnownResponse, gtserror.WithCode) {
// get the account the request is referring to
requestedAccount := &gtsmodel.Account{}
if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil {

View file

@ -21,6 +21,7 @@ package processing
import (
"context"
"net/http"
"net/url"
"github.com/sirupsen/logrus"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
@ -158,22 +159,22 @@ type Processor interface {
// GetFediUser handles the getting of a fedi/activitypub representation of a user/account, performing appropriate authentication
// before returning a JSON serializable interface to the caller.
GetFediUser(requestedUsername string, request *http.Request) (interface{}, gtserror.WithCode)
GetFediUser(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode)
// GetFediFollowers handles the getting of a fedi/activitypub representation of a user/account's followers, performing appropriate
// authentication before returning a JSON serializable interface to the caller.
GetFediFollowers(requestedUsername string, request *http.Request) (interface{}, gtserror.WithCode)
GetFediFollowers(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode)
// GetFediFollowing handles the getting of a fedi/activitypub representation of a user/account's following, performing appropriate
// authentication before returning a JSON serializable interface to the caller.
GetFediFollowing(requestedUsername string, request *http.Request) (interface{}, gtserror.WithCode)
GetFediFollowing(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode)
// GetFediStatus handles the getting of a fedi/activitypub representation of a particular status, performing appropriate
// authentication before returning a JSON serializable interface to the caller.
GetFediStatus(requestedUsername string, requestedStatusID string, request *http.Request) (interface{}, gtserror.WithCode)
GetFediStatus(ctx context.Context, requestedUsername string, requestedStatusID string, requestURL *url.URL) (interface{}, gtserror.WithCode)
// GetWebfingerAccount handles the GET for a webfinger resource. Most commonly, it will be used for returning account lookups.
GetWebfingerAccount(requestedUsername string, request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode)
GetWebfingerAccount(ctx context.Context, requestedUsername string, requestURL *url.URL) (*apimodel.WellKnownResponse, gtserror.WithCode)
// GetNodeInfoRel returns a well known response giving the path to node info.
GetNodeInfoRel(request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode)

View file

@ -66,8 +66,8 @@ const (
// APRequestingActorIRI can be used to set and retrieve the actor of an incoming federation request.
// This will usually be the owner of whatever activity is being posted.
APRequestingActorIRI APContextKey = "requestingActorIRI"
// APRequestingPublicKeyID can be used to set and retrieve the public key ID of an incoming federation request.
APRequestingPublicKeyID APContextKey = "requestingPublicKeyID"
// APRequestingPublicKeyVerifier can be used to set and retrieve the public key verifier of an incoming federation request.
APRequestingPublicKeyVerifier APContextKey = "requestingPublicKeyVerifier"
// APFromFederatorChanKey can be used to pass a pointer to the fromFederator channel into the federator for use in callbacks.
APFromFederatorChanKey APContextKey = "fromFederatorChan"
)

View file

@ -2,7 +2,6 @@ package visibility
import (
"errors"
"net/url"
"fmt"
@ -17,21 +16,23 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
"statusID": targetStatus.ID,
})
uri, err := url.Parse(targetStatus.URI)
if err != nil {
return false, fmt.Errorf("StatusVisible: error parsing uri: %s", targetStatus.URI)
}
if blocked, err := f.blockedDomain(uri.Host); blocked || err != nil {
l.Debugf("domain %s is blocked", uri.Host)
return blocked, err
}
aaaaaaaaaa
relevantAccounts, err := f.pullRelevantAccountsFromStatus(targetStatus)
if err != nil {
l.Debugf("error pulling relevant accounts for status %s: %s", targetStatus.ID, err)
return false, fmt.Errorf("error pulling relevant accounts for status %s: %s", targetStatus.ID, err)
}
targetAccount := relevantAccounts.StatusAuthor
domainBlocked, err := f.blockedRelevant(relevantAccounts)
if err != nil {
l.Debugf("error checking domain block: %s", err)
return false, fmt.Errorf("error checking domain block: %s", err)
}
if domainBlocked {
return false, nil
}
targetAccount := relevantAccounts.StatusAuthor
// if target account is suspended then don't show the status
if !targetAccount.SuspendedAt.IsZero() {
l.Trace("target account suspended at is not zero")

View file

@ -81,6 +81,7 @@ type relevantAccounts struct {
MentionedAccounts []*gtsmodel.Account
}
// blockedDomain checks whether the given domain is blocked by us or not
func (f *filter) blockedDomain(host string) (bool, error) {
b := &gtsmodel.DomainBlock{}
err := f.db.GetWhere([]db.Where{{Key: "domain", Value: host, CaseInsensitive: true}}, b)
@ -97,3 +98,59 @@ func (f *filter) blockedDomain(host string) (bool, error) {
// there's an actual error
return false, err
}
// blockedRelevant checks through all relevant accounts attached to a status
// to make sure none of them are domain blocked by this instance.
func (f *filter) blockedRelevant(r *relevantAccounts) (bool, error) {
if r.StatusAuthor != nil {
b, err := f.blockedDomain(r.StatusAuthor.Domain)
if err != nil {
return false, err
}
if b {
return true, nil
}
}
if r.ReplyToAccount != nil {
b, err := f.blockedDomain(r.ReplyToAccount.Domain)
if err != nil {
return false, err
}
if b {
return true, nil
}
}
if r.BoostedAccount != nil {
b, err := f.blockedDomain(r.BoostedAccount.Domain)
if err != nil {
return false, err
}
if b {
return true, nil
}
}
if r.BoostedReplyToAccount != nil {
b, err := f.blockedDomain(r.BoostedReplyToAccount.Domain)
if err != nil {
return false, err
}
if b {
return true, nil
}
}
for _, a := range r.MentionedAccounts {
b, err := f.blockedDomain(a.Domain)
if err != nil {
return false, err
}
if b {
return true, nil
}
}
return false, nil
}