diff --git a/internal/api/client/admin/admin.go b/internal/api/client/admin/admin.go index b20dd2add..b8b94be76 100644 --- a/internal/api/client/admin/admin.go +++ b/internal/api/client/admin/admin.go @@ -35,9 +35,13 @@ const ( EmojiPath = BasePath + "/custom_emojis" // DomainBlocksPath is used for posting domain blocks. DomainBlocksPath = BasePath + "/domain_blocks" + // DomainBlockPath is used for interacting with a single domain block. + DomainBlockPath = DomainBlocksPath + "/:" + IDKey - // ExportQueryKey is the key to use when requesting a public export of some data. + // ExportQueryKey is for requesting a public export of some data. ExportQueryKey = "export" + // IDKey specifies the ID of a single item being interacted with. + IDKey = "id" ) // Module implements the ClientAPIModule interface for admin-related actions (reports, emojis, etc) @@ -61,5 +65,7 @@ func (m *Module) Route(r router.Router) error { r.AttachHandler(http.MethodPost, EmojiPath, m.emojiCreatePOSTHandler) r.AttachHandler(http.MethodPost, DomainBlocksPath, m.DomainBlocksPOSTHandler) r.AttachHandler(http.MethodGet, DomainBlocksPath, m.DomainBlocksGETHandler) + r.AttachHandler(http.MethodGet, DomainBlockPath, m.DomainBlockGETHandler) + r.AttachHandler(http.MethodDelete, DomainBlockPath, m.DomainBlockDELETEHandler) return nil } diff --git a/internal/api/client/admin/domainblockcreate.go b/internal/api/client/admin/domainblockcreate.go index e1ff84d82..5d3df58de 100644 --- a/internal/api/client/admin/domainblockcreate.go +++ b/internal/api/client/admin/domainblockcreate.go @@ -11,6 +11,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) +// DomainBlocksPOSTHandler deals with the creation of a new domain block. func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "DomainBlocksPOSTHandler", @@ -67,5 +68,3 @@ func validateCreateDomainBlock(form *model.DomainBlockCreateRequest) error { return nil } - - diff --git a/internal/api/client/admin/domainblockdelete.go b/internal/api/client/admin/domainblockdelete.go new file mode 100644 index 000000000..d8f4586f9 --- /dev/null +++ b/internal/api/client/admin/domainblockdelete.go @@ -0,0 +1,47 @@ +package admin + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// DomainBlockDELETEHandler deals with the delete of an existing domain block. +func (m *Module) DomainBlockDELETEHandler(c *gin.Context) { + l := m.log.WithFields(logrus.Fields{ + "func": "DomainBlockDELETEHandler", + "request_uri": c.Request.RequestURI, + "user_agent": c.Request.UserAgent(), + "origin_ip": c.ClientIP(), + }) + + // make sure we're authed with an admin account + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + l.Debugf("couldn't auth: %s", err) + c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) + return + } + if !authed.User.Admin { + l.Debugf("user %s not an admin", authed.User.ID) + c.JSON(http.StatusForbidden, gin.H{"error": "not an admin"}) + return + } + + domainBlockID := c.Param(IDKey) + if domainBlockID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "no domain block id provided"}) + return + } + + domainBlock, errWithCode := m.processor.AdminDomainBlockDelete(authed, domainBlockID) + if errWithCode != nil { + l.Debugf("error deleting domain block: %s", errWithCode.Error()) + c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()}) + return + } + + c.JSON(http.StatusOK, domainBlock) +} diff --git a/internal/api/client/admin/domainblockget.go b/internal/api/client/admin/domainblockget.go index 4b7844d62..009794f8a 100644 --- a/internal/api/client/admin/domainblockget.go +++ b/internal/api/client/admin/domainblockget.go @@ -9,9 +9,10 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (m *Module) DomainBlocksGETHandler(c *gin.Context) { +// DomainBlockGETHandler returns one existing domain block, identified by its id. +func (m *Module) DomainBlockGETHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ - "func": "DomainBlocksPOSTHandler", + "func": "DomainBlockGETHandler", "request_uri": c.Request.RequestURI, "user_agent": c.Request.UserAgent(), "origin_ip": c.ClientIP(), @@ -30,6 +31,12 @@ func (m *Module) DomainBlocksGETHandler(c *gin.Context) { return } + domainBlockID := c.Param(IDKey) + if domainBlockID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "no domain block id provided"}) + return + } + export := false exportString := c.Query(ExportQueryKey) if exportString != "" { @@ -42,12 +49,12 @@ func (m *Module) DomainBlocksGETHandler(c *gin.Context) { export = i } - domainBlocks, err := m.processor.AdminDomainBlocksGet(authed, export) + domainBlock, err := m.processor.AdminDomainBlockGet(authed, domainBlockID, export) if err != nil { - l.Debugf("error getting domain blocks: %s", err) + l.Debugf("error getting domain block: %s", err) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - c.JSON(http.StatusOK, domainBlocks) + c.JSON(http.StatusOK, domainBlock) } diff --git a/internal/api/client/admin/domainblocksget.go b/internal/api/client/admin/domainblocksget.go new file mode 100644 index 000000000..1e873a302 --- /dev/null +++ b/internal/api/client/admin/domainblocksget.go @@ -0,0 +1,54 @@ +package admin + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// DomainBlocksGETHandler returns a list of all existing domain blocks. +func (m *Module) DomainBlocksGETHandler(c *gin.Context) { + l := m.log.WithFields(logrus.Fields{ + "func": "DomainBlocksGETHandler", + "request_uri": c.Request.RequestURI, + "user_agent": c.Request.UserAgent(), + "origin_ip": c.ClientIP(), + }) + + // make sure we're authed with an admin account + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + l.Debugf("couldn't auth: %s", err) + c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) + return + } + if !authed.User.Admin { + l.Debugf("user %s not an admin", authed.User.ID) + c.JSON(http.StatusForbidden, gin.H{"error": "not an admin"}) + return + } + + export := false + exportString := c.Query(ExportQueryKey) + if exportString != "" { + i, err := strconv.ParseBool(exportString) + if err != nil { + l.Debugf("error parsing export string: %s", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse export query param"}) + return + } + export = i + } + + domainBlocks, err := m.processor.AdminDomainBlocksGet(authed, export) + if err != nil { + l.Debugf("error getting domain blocks: %s", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, domainBlocks) +} diff --git a/internal/api/client/instance/instancepatch.go b/internal/api/client/instance/instancepatch.go index ace7674c0..250e836be 100644 --- a/internal/api/client/instance/instancepatch.go +++ b/internal/api/client/instance/instancepatch.go @@ -8,6 +8,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) +// InstanceUpdatePATCHHandler allows an admin to update the instance information served at /api/v1/instance func (m *Module) InstanceUpdatePATCHHandler(c *gin.Context) { l := m.log.WithField("func", "InstanceUpdatePATCHHandler") authed, err := oauth.Authed(c, true, true, true, true) diff --git a/internal/api/security/signaturecheck.go b/internal/api/security/signaturecheck.go index fdc2625a0..b852c92ab 100644 --- a/internal/api/security/signaturecheck.go +++ b/internal/api/security/signaturecheck.go @@ -11,6 +11,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) +// SignatureCheck checks whether an incoming http request has been signed. If so, it will check if the domain +// that signed the request is permitted to access the server. If it is permitted, the handler will set the key +// verifier in the gin context for use down the line. func (m *Module) SignatureCheck(c *gin.Context) { l := m.log.WithField("func", "DomainBlockChecker") diff --git a/internal/federation/federatingprotocol.go b/internal/federation/federatingprotocol.go index 429539e37..c0943a328 100644 --- a/internal/federation/federatingprotocol.go +++ b/internal/federation/federatingprotocol.go @@ -235,7 +235,7 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er } for _, uri := range actorIRIs { - blockedDomain, err := f.blockedDomain(uri.Host); + blockedDomain, err := f.blockedDomain(uri.Host) if err != nil { return false, fmt.Errorf("error checking domain block: %s", err) } diff --git a/internal/oauth/util.go b/internal/oauth/util.go index 2f2e2e182..2520fc784 100644 --- a/internal/oauth/util.go +++ b/internal/oauth/util.go @@ -95,6 +95,6 @@ func Authed(c *gin.Context, requireToken bool, requireApp bool, requireUser bool return nil, errors.New("account suspended") } } - + return a, nil } diff --git a/internal/processing/admin.go b/internal/processing/admin.go index 0ffef5a47..73ac32c7a 100644 --- a/internal/processing/admin.go +++ b/internal/processing/admin.go @@ -33,5 +33,13 @@ func (p *processor) AdminDomainBlockCreate(authed *oauth.Auth, form *apimodel.Do } func (p *processor) AdminDomainBlocksGet(authed *oauth.Auth, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) { - return p.adminProcessor.DomainBlocksGet(authed.Account, export) + return p.adminProcessor.DomainBlocksGet(authed.Account, export) +} + +func (p *processor) AdminDomainBlockGet(authed *oauth.Auth, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlockGet(authed.Account, id, export) +} + +func (p *processor) AdminDomainBlockDelete(authed *oauth.Auth, id string) (*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlockDelete(authed.Account, id) } diff --git a/internal/processing/admin/admin.go b/internal/processing/admin/admin.go index af1f8dca1..8cb1d7f78 100644 --- a/internal/processing/admin/admin.go +++ b/internal/processing/admin/admin.go @@ -33,6 +33,8 @@ import ( type Processor interface { DomainBlockCreate(account *gtsmodel.Account, form *apimodel.DomainBlockCreateRequest) (*apimodel.DomainBlock, gtserror.WithCode) DomainBlocksGet(account *gtsmodel.Account, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) + DomainBlockGet(account *gtsmodel.Account, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) + DomainBlockDelete(account *gtsmodel.Account, id string) (*apimodel.DomainBlock, gtserror.WithCode) EmojiCreate(account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) } diff --git a/internal/processing/admin/deletedomainblock.go b/internal/processing/admin/deletedomainblock.go new file mode 100644 index 000000000..973344dc2 --- /dev/null +++ b/internal/processing/admin/deletedomainblock.go @@ -0,0 +1,36 @@ +package admin + +import ( + "fmt" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func (p *processor) DomainBlockDelete(account *gtsmodel.Account, id string) (*apimodel.DomainBlock, gtserror.WithCode) { + domainBlock := >smodel.DomainBlock{} + + if err := p.db.GetByID(id, domainBlock); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + // something has gone really wrong + return nil, gtserror.NewErrorInternalError(err) + } + // there are no entries for this ID + return nil, gtserror.NewErrorNotFound(fmt.Errorf("no entry for ID %s", id)) + } + + // prepare the domain block to return + mastoDomainBlock, err := p.tc.DomainBlockToMasto(domainBlock, false) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + + // delete the domain block + if err := p.db.DeleteByID(id, domainBlock); err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + + return mastoDomainBlock, nil +} diff --git a/internal/processing/admin/getdomainblock.go b/internal/processing/admin/getdomainblock.go new file mode 100644 index 000000000..170d82e0b --- /dev/null +++ b/internal/processing/admin/getdomainblock.go @@ -0,0 +1,30 @@ +package admin + +import ( + "fmt" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func (p *processor) DomainBlockGet(account *gtsmodel.Account, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) { + domainBlock := >smodel.DomainBlock{} + + if err := p.db.GetByID(id, domainBlock); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + // something has gone really wrong + return nil, gtserror.NewErrorInternalError(err) + } + // there are no entries for this ID + return nil, gtserror.NewErrorNotFound(fmt.Errorf("no entry for ID %s", id)) + } + + mastoDomainBlock, err := p.tc.DomainBlockToMasto(domainBlock, export) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + + return mastoDomainBlock, nil +} diff --git a/internal/processing/media/getfile.go b/internal/processing/media/getfile.go index f64d79a26..1664306b8 100644 --- a/internal/processing/media/getfile.go +++ b/internal/processing/media/getfile.go @@ -22,10 +22,10 @@ import ( "fmt" "strings" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/media" - apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" ) func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) { diff --git a/internal/processing/media/update.go b/internal/processing/media/update.go index e27960371..aa3583054 100644 --- a/internal/processing/media/update.go +++ b/internal/processing/media/update.go @@ -22,10 +22,10 @@ import ( "errors" "fmt" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" - apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" ) func (p *processor) Update(account *gtsmodel.Account, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) { diff --git a/internal/processing/processor.go b/internal/processing/processor.go index 9ecf14911..d24897f61 100644 --- a/internal/processing/processor.go +++ b/internal/processing/processor.go @@ -89,6 +89,10 @@ type Processor interface { AdminDomainBlockCreate(authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) (*apimodel.DomainBlock, gtserror.WithCode) // AdminDomainBlocksGet returns a list of currently blocked domains. AdminDomainBlocksGet(authed *oauth.Auth, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) + // AdminDomainBlockGet returns one domain block, specified by ID. + AdminDomainBlockGet(authed *oauth.Auth, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) + // AdminDomainBlockDelete deletes one domain block, specified by ID, returning the deleted domain block. + AdminDomainBlockDelete(authed *oauth.Auth, id string) (*apimodel.DomainBlock, gtserror.WithCode) // AppCreate processes the creation of a new API application AppCreate(authed *oauth.Auth, form *apimodel.ApplicationCreateRequest) (*apimodel.Application, error) diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go index d8849a037..61c11b8ef 100644 --- a/internal/typeutils/internaltofrontend.go +++ b/internal/typeutils/internaltofrontend.go @@ -648,8 +648,8 @@ func (c *converter) NotificationToMasto(n *gtsmodel.Notification) (*model.Notifi func (c *converter) DomainBlockToMasto(b *gtsmodel.DomainBlock, export bool) (*model.DomainBlock, error) { domainBlock := &model.DomainBlock{ - Domain: b.Domain, - PublicComment: b.PublicComment, + Domain: b.Domain, + PublicComment: b.PublicComment, } // if we're exporting a domain block, return it with minimal information attached diff --git a/internal/visibility/util.go b/internal/visibility/util.go index ca5334122..a12dd555f 100644 --- a/internal/visibility/util.go +++ b/internal/visibility/util.go @@ -9,7 +9,7 @@ import ( func (f *filter) pullRelevantAccountsFromStatus(targetStatus *gtsmodel.Status) (*relevantAccounts, error) { accounts := &relevantAccounts{ - MentionedAccounts: []*gtsmodel.Account{}, + MentionedAccounts: []*gtsmodel.Account{}, BoostedMentionedAccounts: []*gtsmodel.Account{}, }