summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorLibravatar f0x52 <f0x@cthu.lu>2023-01-25 18:06:41 +0100
committerLibravatar GitHub <noreply@github.com>2023-01-25 18:06:41 +0100
commit17eecfb6d9f50821d7822d60fa4135d59ea5ca57 (patch)
tree26796a658eb1b05e27c34ec23c2fc8030ffb4458 /internal
parent[feature] Accept incoming federated Flag activity (#1382) (diff)
downloadgotosocial-17eecfb6d9f50821d7822d60fa4135d59ea5ca57.tar.xz
[feature] Public list of suspended domains (#1362)
* basic rendered domain blocklist (unauthenticated!) * style basic domain block list * better formatting for domain blocklist * add opt-in config option for showing suspended domains * format/linter * re-use InstancePeersGet for web-accessible domain blocklist * reword explanation, border styling * always attach blocklist handler, update error message * domain blocklist error message grammar
Diffstat (limited to 'internal')
-rw-r--r--internal/api/client/instance/instancepeersget.go17
-rw-r--r--internal/config/config.go1
-rw-r--r--internal/config/defaults.go1
-rw-r--r--internal/config/flags.go1
-rw-r--r--internal/config/helpers.gen.go25
-rw-r--r--internal/processing/instance.go13
-rw-r--r--internal/processing/processor.go2
-rw-r--r--internal/web/domain-blocklist.go71
-rw-r--r--internal/web/robots.go4
-rw-r--r--internal/web/web.go2
10 files changed, 122 insertions, 15 deletions
diff --git a/internal/api/client/instance/instancepeersget.go b/internal/api/client/instance/instancepeersget.go
index d3880e2cd..9e2ed89e5 100644
--- a/internal/api/client/instance/instancepeersget.go
+++ b/internal/api/client/instance/instancepeersget.go
@@ -24,6 +24,7 @@ import (
"strings"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -105,6 +106,8 @@ func (m *Module) InstancePeersGETHandler(c *gin.Context) {
return
}
+ var isUnauthenticated = authed.Account == nil || authed.User == nil
+
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
@@ -136,7 +139,19 @@ func (m *Module) InstancePeersGETHandler(c *gin.Context) {
flat = true
}
- data, errWithCode := m.processor.InstancePeersGet(c.Request.Context(), authed, includeSuspended, includeOpen, flat)
+ if includeOpen && !config.GetInstanceExposePeers() && isUnauthenticated {
+ err := fmt.Errorf("peers open query requires an authenticated account/user")
+ apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
+ return
+ }
+
+ if includeSuspended && !config.GetInstanceExposeSuspended() && isUnauthenticated {
+ err := fmt.Errorf("peers suspended query requires an authenticated account/user")
+ apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
+ return
+ }
+
+ data, errWithCode := m.processor.InstancePeersGet(c.Request.Context(), includeSuspended, includeOpen, flat)
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
diff --git a/internal/config/config.go b/internal/config/config.go
index c28cfe419..472e7b93d 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -76,6 +76,7 @@ type Configuration struct {
InstanceExposePeers bool `name:"instance-expose-peers" usage:"Allow unauthenticated users to query /api/v1/instance/peers?filter=open"`
InstanceExposeSuspended bool `name:"instance-expose-suspended" usage:"Expose suspended instances via web UI, and allow unauthenticated users to query /api/v1/instance/peers?filter=suspended"`
+ InstanceExposeSuspendedWeb bool `name:"instance-expose-suspended-web" usage:"Expose list of suspended instances as webpage on /about/suspended"`
InstanceExposePublicTimeline bool `name:"instance-expose-public-timeline" usage:"Allow unauthenticated users to query /api/v1/timelines/public"`
InstanceDeliverToSharedInboxes bool `name:"instance-deliver-to-shared-inboxes" usage:"Deliver federated messages to shared inboxes, if they're available."`
diff --git a/internal/config/defaults.go b/internal/config/defaults.go
index 3cd1a3ed3..ecd32be2f 100644
--- a/internal/config/defaults.go
+++ b/internal/config/defaults.go
@@ -58,6 +58,7 @@ var Defaults = Configuration{
InstanceExposePeers: false,
InstanceExposeSuspended: false,
+ InstanceExposeSuspendedWeb: false,
InstanceDeliverToSharedInboxes: true,
AccountsRegistrationOpen: true,
diff --git a/internal/config/flags.go b/internal/config/flags.go
index a0fde3eed..a21f17f53 100644
--- a/internal/config/flags.go
+++ b/internal/config/flags.go
@@ -78,6 +78,7 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) {
// Instance
cmd.Flags().Bool(InstanceExposePeersFlag(), cfg.InstanceExposePeers, fieldtag("InstanceExposePeers", "usage"))
cmd.Flags().Bool(InstanceExposeSuspendedFlag(), cfg.InstanceExposeSuspended, fieldtag("InstanceExposeSuspended", "usage"))
+ cmd.Flags().Bool(InstanceExposeSuspendedWebFlag(), cfg.InstanceExposeSuspendedWeb, fieldtag("InstanceExposeSuspendedWeb", "usage"))
cmd.Flags().Bool(InstanceDeliverToSharedInboxesFlag(), cfg.InstanceDeliverToSharedInboxes, fieldtag("InstanceDeliverToSharedInboxes", "usage"))
// Accounts
diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go
index 1da2ff42c..3560c566a 100644
--- a/internal/config/helpers.gen.go
+++ b/internal/config/helpers.gen.go
@@ -724,6 +724,31 @@ func GetInstanceExposeSuspended() bool { return global.GetInstanceExposeSuspende
// SetInstanceExposeSuspended safely sets the value for global configuration 'InstanceExposeSuspended' field
func SetInstanceExposeSuspended(v bool) { global.SetInstanceExposeSuspended(v) }
+// GetInstanceExposeSuspendedWeb safely fetches the Configuration value for state's 'InstanceExposeSuspendedWeb' field
+func (st *ConfigState) GetInstanceExposeSuspendedWeb() (v bool) {
+ st.mutex.Lock()
+ v = st.config.InstanceExposeSuspendedWeb
+ st.mutex.Unlock()
+ return
+}
+
+// SetInstanceExposeSuspendedWeb safely sets the Configuration value for state's 'InstanceExposeSuspendedWeb' field
+func (st *ConfigState) SetInstanceExposeSuspendedWeb(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.InstanceExposeSuspendedWeb = v
+ st.reloadToViper()
+}
+
+// InstanceExposeSuspendedWebFlag returns the flag name for the 'InstanceExposeSuspendedWeb' field
+func InstanceExposeSuspendedWebFlag() string { return "instance-expose-suspended-web" }
+
+// GetInstanceExposeSuspendedWeb safely fetches the value for global configuration 'InstanceExposeSuspendedWeb' field
+func GetInstanceExposeSuspendedWeb() bool { return global.GetInstanceExposeSuspendedWeb() }
+
+// SetInstanceExposeSuspendedWeb safely sets the value for global configuration 'InstanceExposeSuspendedWeb' field
+func SetInstanceExposeSuspendedWeb(v bool) { global.SetInstanceExposeSuspendedWeb(v) }
+
// GetInstanceExposePublicTimeline safely fetches the Configuration value for state's 'InstanceExposePublicTimeline' field
func (st *ConfigState) GetInstanceExposePublicTimeline() (v bool) {
st.mutex.Lock()
diff --git a/internal/processing/instance.go b/internal/processing/instance.go
index fec636d2a..afa60ad1e 100644
--- a/internal/processing/instance.go
+++ b/internal/processing/instance.go
@@ -28,7 +28,6 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/text"
"github.com/superseriousbusiness/gotosocial/internal/util"
"github.com/superseriousbusiness/gotosocial/internal/validate"
@@ -48,15 +47,10 @@ func (p *processor) InstanceGet(ctx context.Context, domain string) (*apimodel.I
return ai, nil
}
-func (p *processor) InstancePeersGet(ctx context.Context, authed *oauth.Auth, includeSuspended bool, includeOpen bool, flat bool) (interface{}, gtserror.WithCode) {
+func (p *processor) InstancePeersGet(ctx context.Context, includeSuspended bool, includeOpen bool, flat bool) (interface{}, gtserror.WithCode) {
domains := []*apimodel.Domain{}
if includeOpen {
- if !config.GetInstanceExposePeers() && (authed.Account == nil || authed.User == nil) {
- err := fmt.Errorf("peers open query requires an authenticated account/user")
- return nil, gtserror.NewErrorUnauthorized(err, err.Error())
- }
-
instances, err := p.db.GetInstancePeers(ctx, false)
if err != nil && err != db.ErrNoEntries {
err = fmt.Errorf("error selecting instance peers: %s", err)
@@ -70,11 +64,6 @@ func (p *processor) InstancePeersGet(ctx context.Context, authed *oauth.Auth, in
}
if includeSuspended {
- if !config.GetInstanceExposeSuspended() && (authed.Account == nil || authed.User == nil) {
- err := fmt.Errorf("peers suspended query requires an authenticated account/user")
- return nil, gtserror.NewErrorUnauthorized(err, err.Error())
- }
-
domainBlocks := []*gtsmodel.DomainBlock{}
if err := p.db.GetAll(ctx, &domainBlocks); err != nil && err != db.ErrNoEntries {
return nil, gtserror.NewErrorInternalError(err)
diff --git a/internal/processing/processor.go b/internal/processing/processor.go
index 46634aaaa..68a4c5fa4 100644
--- a/internal/processing/processor.go
+++ b/internal/processing/processor.go
@@ -172,7 +172,7 @@ type Processor interface {
// InstanceGet retrieves instance information for serving at api/v1/instance
InstanceGet(ctx context.Context, domain string) (*apimodel.Instance, gtserror.WithCode)
- InstancePeersGet(ctx context.Context, authed *oauth.Auth, includeSuspended bool, includeOpen bool, flat bool) (interface{}, gtserror.WithCode)
+ InstancePeersGet(ctx context.Context, includeSuspended bool, includeOpen bool, flat bool) (interface{}, gtserror.WithCode)
// InstancePatch updates this instance according to the given form.
//
// It should already be ascertained that the requesting account is authenticated and an admin.
diff --git a/internal/web/domain-blocklist.go b/internal/web/domain-blocklist.go
new file mode 100644
index 000000000..b3cd0efe7
--- /dev/null
+++ b/internal/web/domain-blocklist.go
@@ -0,0 +1,71 @@
+/*
+ GoToSocial
+ Copyright (C) 2021-2023 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 web
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/gtserror"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+const (
+ domainBlockListPath = "/about/suspended"
+)
+
+func (m *Module) domainBlockListGETHandler(c *gin.Context) {
+ authed, err := oauth.Authed(c, false, false, false, false)
+ if err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
+ return
+ }
+
+ if !config.GetInstanceExposeSuspendedWeb() && (authed.Account == nil || authed.User == nil) {
+ err := fmt.Errorf("this instance does not expose the list of suspended domains publicly")
+ apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
+ return
+ }
+
+ host := config.GetHost()
+ instance, err := m.processor.InstanceGet(c.Request.Context(), host)
+ if err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
+ return
+ }
+
+ domainBlocks, errWithCode := m.processor.InstancePeersGet(c.Request.Context(), true, false, false)
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
+ return
+ }
+
+ c.HTML(http.StatusOK, "domain-blocklist.tmpl", gin.H{
+ "instance": instance,
+ "ogMeta": ogBase(instance),
+ "blocklist": domainBlocks,
+ "stylesheets": []string{
+ assetsPathPrefix + "/Fork-Awesome/css/fork-awesome.min.css",
+ },
+ "javascript": []string{distPathPrefix + "/frontend.js"},
+ })
+}
diff --git a/internal/web/robots.go b/internal/web/robots.go
index 4b4d6df28..f66438f5d 100644
--- a/internal/web/robots.go
+++ b/internal/web/robots.go
@@ -49,7 +49,9 @@ Disallow: /emoji/
# panels
Disallow: /admin
Disallow: /user
-Disallow: /settings/`
+Disallow: /settings/
+# domain blocklist
+Disallow: /about/suspended`
)
// robotsGETHandler returns a decent robots.txt that prevents crawling
diff --git a/internal/web/web.go b/internal/web/web.go
index 00b6d4102..f4529286a 100644
--- a/internal/web/web.go
+++ b/internal/web/web.go
@@ -100,6 +100,8 @@ func (m *Module) Route(r router.Router, mi ...gin.HandlerFunc) {
r.AttachHandler(http.MethodGet, confirmEmailPath, m.confirmEmailGETHandler)
r.AttachHandler(http.MethodGet, robotsPath, m.robotsGETHandler)
+ r.AttachHandler(http.MethodGet, domainBlockListPath, m.domainBlockListGETHandler)
+
/*
Attach redirects from old endpoints to current ones for backwards compatibility
*/