One moment while we verify your connection...
+ +diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go
index 0845e5ed1..6bc27a7c4 100644
--- a/cmd/gotosocial/action/server/server.go
+++ b/cmd/gotosocial/action/server/server.go
@@ -499,7 +499,6 @@ var Start action.GTSAction = func(ctx context.Context) error {
s2sLimit := middleware.RateLimit(rlLimit, exceptions) // server-to-server (AP)
fsMainLimit := middleware.RateLimit(rlLimit, exceptions) // fileserver / web templates
fsEmojiLimit := middleware.RateLimit(rlLimit*2, exceptions) // fileserver (emojis only, use high limit)
- nollamas := middleware.NoLLaMas(instanceAccount)
// throttling
cpuMultiplier := config.GetAdvancedThrottlingMultiplier()
@@ -545,7 +544,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
nodeInfoModule.Route(route, s2sLimit, s2sThrottle, gzip)
activityPubModule.Route(route, s2sLimit, s2sThrottle, robotsDisallowAll, gzip)
activityPubModule.RoutePublicKey(route, s2sLimit, pkThrottle, robotsDisallowAll, gzip)
- webModule.Route(route, fsMainLimit, fsThrottle, robotsDisallowAIOnly, nollamas, gzip)
+ webModule.Route(route, fsMainLimit, fsThrottle, robotsDisallowAIOnly, gzip)
// Finally start the main http server!
if err := route.Start(); err != nil {
diff --git a/internal/middleware/nollamas.go b/internal/middleware/nollamas.go
index fc7a24716..0ebdf8c15 100644
--- a/internal/middleware/nollamas.go
+++ b/internal/middleware/nollamas.go
@@ -18,6 +18,9 @@
package middleware
import (
+ "context"
+ "crypto/rand"
+ "crypto/rsa"
"crypto/sha256"
"crypto/sha512"
"crypto/subtle"
@@ -29,15 +32,23 @@ import (
"codeberg.org/gruf/go-byteutil"
"github.com/gin-gonic/gin"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+ apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
+ apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
+ "github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
-func NoLLaMas(instanceAcc *gtsmodel.Account) gin.HandlerFunc {
- // Generate seed hash from
- // this instance private key.
- priv := instanceAcc.PrivateKey
- bpriv := x509.MarshalPKCS1PrivateKey(priv)
+func NoLLaMas(
+ getInstance func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode),
+) gin.HandlerFunc {
+ privKey, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ panic(err)
+ }
+
+ // Generate seed hash
+ // from this private key.
+ bpriv := x509.MarshalPKCS1PrivateKey(privKey)
seed := sha512.Sum512(bpriv)
// Configure nollamas.
@@ -45,6 +56,7 @@ func NoLLaMas(instanceAcc *gtsmodel.Account) gin.HandlerFunc {
nollamas.seed = seed[:]
nollamas.ttl = time.Hour
nollamas.diff = 4
+ nollamas.getInstance = getInstance
return nollamas.Serve
}
@@ -57,9 +69,10 @@ const encodedHashLen = 2 * hashLen
func newHash() hash.Hash { return sha256.New() }
type nollamas struct {
- seed []byte // securely hashed instance private key
- ttl time.Duration
- diff uint8
+ seed []byte // securely hashed private key
+ ttl time.Duration
+ diff uint8
+ getInstance func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode)
}
func (m *nollamas) Serve(c *gin.Context) {
@@ -169,10 +182,26 @@ func (m *nollamas) renderChallenge(c *gin.Context, challenge string) {
// our challenge page.
c.Abort()
+ instance, errWithCode := m.getInstance(c.Request.Context())
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.getInstance)
+ return
+ }
+
// Write the templated challenge HTML response to client.
- c.HTML(http.StatusOK, "nollamas.tmpl", map[string]any{
- "challenge": challenge,
- "difficulty": m.diff,
+ apiutil.TemplateWebPage(c, apiutil.WebPage{
+ Template: "nollamas.tmpl",
+ Instance: instance,
+ Extra: map[string]any{
+ "challenge": challenge,
+ "difficulty": m.diff,
+ },
+ Javascript: []apiutil.JavascriptEntry{
+ {
+ Src: "/assets/dist/nollamas.js",
+ Defer: true,
+ },
+ },
})
}
diff --git a/internal/web/web.go b/internal/web/web.go
index 5bccca06d..402a45ae7 100644
--- a/internal/web/web.go
+++ b/internal/web/web.go
@@ -99,12 +99,16 @@ func (m *Module) Route(r *router.Router, mi ...gin.HandlerFunc) {
// Handlers that serve profiles and statuses should use
// the SignatureCheck middleware, so that requests with
- // content-type application/activity+json can be served
+ // content-type application/activity+json can be served,
+ // and (if enabled) the nollamas middleware, to protect
+ // against scraping by shitty LLM bullshit.
profileGroup := r.AttachGroup(profileGroupPath)
profileGroup.Use(mi...)
profileGroup.Use(middleware.SignatureCheck(m.isURIBlocked), middleware.CacheControl(middleware.CacheControlConfig{
Directives: []string{"no-store"},
}))
+ nollamas := middleware.NoLLaMas(m.processor.InstanceGetV1)
+ profileGroup.Use(nollamas)
profileGroup.Handle(http.MethodGet, "", m.profileGETHandler) // use empty path here since it's the base of the group
profileGroup.Handle(http.MethodGet, statusPath, m.threadGETHandler)
diff --git a/web/source/index.js b/web/source/index.js
index d66afe757..e99c27fcd 100644
--- a/web/source/index.js
+++ b/web/source/index.js
@@ -73,6 +73,24 @@ skulk({
["babelify", { global: true }]
],
},
+ nollamas: {
+ entryFile: "nollamas",
+ outputFile: "nollamas.js",
+ preset: ["js"],
+ prodCfg: prodCfg,
+ transform: [
+ ["babelify", { global: true }]
+ ],
+ },
+ nollamasworker: {
+ entryFile: "nollamasworker",
+ outputFile: "nollamasworker.js",
+ preset: ["js"],
+ prodCfg: prodCfg,
+ transform: [
+ ["babelify", { global: true }]
+ ],
+ },
settings: {
entryFile: "settings",
outputFile: "settings.js",
diff --git a/web/source/nollamas/index.js b/web/source/nollamas/index.js
new file mode 100644
index 000000000..c330dcdc1
--- /dev/null
+++ b/web/source/nollamas/index.js
@@ -0,0 +1,52 @@
+/*
+ GoToSocial
+ Copyright (C) GoToSocial Authors admin@gotosocial.org
+ SPDX-License-Identifier: AGPL-3.0-or-later
+
+ 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
One moment while we verify your connection...
- -One moment while we verify your connection...
+ +