mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-16 15:23:00 -06:00
check domain blocks way earlier on
This commit is contained in:
parent
99eb3bf564
commit
5bf7b46cf4
19 changed files with 255 additions and 77 deletions
|
|
@ -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()})
|
||||
|
|
|
|||
|
|
@ -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()})
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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()})
|
||||
|
|
|
|||
|
|
@ -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()})
|
||||
|
|
|
|||
|
|
@ -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()})
|
||||
|
|
|
|||
|
|
@ -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()})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
66
internal/api/security/signaturecheck.go
Normal file
66
internal/api/security/signaturecheck.go
Normal 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 := >smodel.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
|
||||
}
|
||||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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 := >smodel.Account{}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 := >smodel.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 := >smodel.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 := >smodel.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 := >smodel.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 := >smodel.Account{}
|
||||
if err := p.db.GetLocalAccountByUsername(requestedUsername, requestedAccount); err != nil {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 := >smodel.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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue