start work on admin domain blocking

This commit is contained in:
tsmethurst 2021-06-28 15:20:13 +02:00
commit c7192c0431
4 changed files with 112 additions and 12 deletions

View file

@ -29,10 +29,12 @@ import (
)
const (
// BasePath is the base API path for this module
// BasePath is the base API path for this module.
BasePath = "/api/v1/admin"
// EmojiPath is used for posting/deleting custom emojis
// EmojiPath is used for posting/deleting custom emojis.
EmojiPath = BasePath + "/custom_emojis"
// DomainBlocksPath is used for posting domain blocks.
DomainBlocksPath = BasePath + "/domain_blocks"
)
// Module implements the ClientAPIModule interface for admin-related actions (reports, emojis, etc)
@ -54,5 +56,6 @@ func New(config *config.Config, processor processing.Processor, log *logrus.Logg
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodPost, EmojiPath, m.emojiCreatePOSTHandler)
r.AttachHandler(http.MethodPost, DomainBlocksPath, m.DomainBlocksPOSTHandler)
return nil
}

View file

@ -0,0 +1,59 @@
package admin
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) {
l := m.log.WithFields(logrus.Fields{
"func": "DomainBlocksPOSTHandler",
"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
}
// extract the media create form from the request context
l.Tracef("parsing request form: %+v", c.Request.Form)
form := &model.DomainBlockCreateRequest{}
if err := c.ShouldBind(form); err != nil {
l.Debugf("error parsing form %+v: %s", c.Request.Form, err)
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("could not parse form: %s", err)})
return
}
// Give the fields on the request form a first pass to make sure the request is superficially valid.
l.Tracef("validating form %+v", form)
if err := validateCreateDomainBlock(form); err != nil {
l.Debugf("error validating form: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
domainBlock, err := m.processor.AdminDomainBlockCreate(authed, form)
if err != nil {
l.Debugf("error creating domain block: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, domainBlock)
}

View file

@ -0,0 +1,42 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
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 model
// DomainBlock represents a block on one domain
type DomainBlock struct {
Domain string `json:"domain"`
Obfuscate bool `json:"obfuscate"`
PrivateComment string `json:"private_comment"`
PublicComment string `json:"public_comment"`
SubscriptionID string `json:"subscription_id"`
CreatedBy string `json:"created_by"`
CreatedAt string `json:"created_at"`
}
// DomainBlockCreateRequest is the form submitted as a POST to /api/v1/admin/domain_blocks to create a new block.
type DomainBlockCreateRequest struct {
// hostname/domain to block
Domain string `form:"domain" json:"domain" xml:"domain" validation:"required"`
// whether the domain should be obfuscated when being displayed publicly
Obfuscate bool `form:"obfuscate" json:"obfuscate" xml:"obfuscate"`
// private comment for other admins on why the domain was blocked
PrivateComment string `form:"private_comment" json:"private_comment" xml:"private_comment"`
// public comment on the reason for the domain block
PublicComment string `form:"public_comment" json:"public_comment" xml:"public_comment"`
}

View file

@ -20,13 +20,11 @@ package gtsmodel
import "time"
// DomainBlock represents a federation block against a particular domain, of varying severity.
// DomainBlock represents a federation block against a particular domain
type DomainBlock struct {
// ID of this block in the database
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// Domain to block. If ANY PART of the candidate domain contains this string, it will be blocked.
// For example: 'example.org' also blocks 'gts.example.org'. '.com' blocks *any* '.com' domains.
// TODO: implement wildcards here
// blocked domain
Domain string `pg:",notnull"`
// When was this block created
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
@ -34,14 +32,12 @@ type DomainBlock struct {
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Account ID of the creator of this block
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
// TODO: define this
Severity int
// Reject media from this domain?
RejectMedia bool
// Reject reports from this domain?
RejectReports bool
// Private comment on this block, viewable to admins
PrivateComment string
// Public comment on this block, viewable (optionally) by everyone
PublicComment string
// whether the domain name should appear obfuscated when displaying it publicly
Obfuscate bool
// if this block was created through a subscription, what's the subscription ID?
SubscriptionID string `pg:"type:CHAR(26)"`
}