diff --git a/.golangci.yml b/.golangci.yml index 4e01169dc6..afd91d65e5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -51,8 +51,6 @@ linters: desc: do not use the go-chi cache package, use gitea's cache system - pkg: github.com/pkg/errors desc: use builtin errors package instead - - pkg: github.com/go-ap/errors - desc: use builtin errors package instead nolintlint: allow-unused: false require-explanation: true diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 03fdbcc0b2..30f56e5f87 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -39,11 +39,6 @@ "path": "filippo.io/edwards25519/LICENSE", "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "git.sr.ht/~mariusor/go-xsd-duration", - "path": "git.sr.ht/~mariusor/go-xsd-duration/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2019 Go xsd:duration\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "gitea.com/go-chi/binding", "path": "gitea.com/go-chi/binding/LICENSE", @@ -489,21 +484,6 @@ "path": "github.com/gliderlabs/ssh/LICENSE", "licenseText": "Copyright (c) 2016 Glider Labs. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Glider Labs nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "github.com/go-ap/activitypub", - "path": "github.com/go-ap/activitypub/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2017 Golang ActitvityPub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, - { - "name": "github.com/go-ap/errors", - "path": "github.com/go-ap/errors/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2019 Golang ActitvityPub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, - { - "name": "github.com/go-ap/jsonld", - "path": "github.com/go-ap/jsonld/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2017 Marius Orcsik\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/go-asn1-ber/asn1-ber", "path": "github.com/go-asn1-ber/asn1-ber/LICENSE", @@ -1154,11 +1134,6 @@ "path": "github.com/urfave/cli/v3/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2023 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "github.com/valyala/fastjson", - "path": "github.com/valyala/fastjson/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2018 Aliaksandr Valialkin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" - }, { "name": "github.com/wneessen/go-mail", "path": "github.com/wneessen/go-mail/LICENSE", diff --git a/go.mod b/go.mod index c5486fceb8..f233698b43 100644 --- a/go.mod +++ b/go.mod @@ -46,8 +46,6 @@ require ( github.com/felixge/fgprof v0.9.5 github.com/fsnotify/fsnotify v1.9.0 github.com/gliderlabs/ssh v0.3.8 - github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742 - github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/cors v1.2.2 github.com/go-co-op/gocron v1.37.0 @@ -135,7 +133,6 @@ require ( code.gitea.io/gitea-vet v0.2.3 // indirect dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect - git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -191,7 +188,6 @@ require ( github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect - github.com/go-ap/errors v0.0.0-20250527110557-c8db454e53fd // indirect github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect @@ -263,7 +259,6 @@ require ( github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/tinylib/msgp v1.6.1 // indirect github.com/unknwon/com v1.0.1 // indirect - github.com/valyala/fastjson v1.6.4 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect @@ -297,8 +292,6 @@ replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-202 replace github.com/nektos/act => gitea.com/gitea/act v0.261.8 -replace git.sr.ht/~mariusor/go-xsd-duration => gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 - exclude github.com/gofrs/uuid v3.2.0+incompatible exclude github.com/gofrs/uuid v4.0.0+incompatible diff --git a/go.sum b/go.sum index 883547adad..2d0dd31b41 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,6 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/gitea/act v0.261.8 h1:rUWB5GOZOubfe2VteKb7XP3HRIbcW3UUmfh7bVAgQcA= gitea.com/gitea/act v0.261.8/go.mod h1:lTp4136rwbZiZS3ZVQeHCvd4qRAZ7LYeiRBqOSdMY/4= -gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= -gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso= gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw= gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g= @@ -305,12 +303,6 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742 h1:X+SsQlZSgJO0A4d1+nI7+g4axZ8u3iUKPirYb5nB5ic= -github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742/go.mod h1:0rgUaERG5qjYenwz4oN5OnUjvkdRuHRjb+2c8FRjz+w= -github.com/go-ap/errors v0.0.0-20250527110557-c8db454e53fd h1:fM5mNIWTPoxoOYoTLd6ifkKXSlXa830l5MYXsrt1UmE= -github.com/go-ap/errors v0.0.0-20250527110557-c8db454e53fd/go.mod h1:Vkh+Z3f24K8nMsJKXo1FHn5ebPsXvB/WDH5JRtYqdNo= -github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw= -github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA= github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= @@ -766,8 +758,6 @@ github.com/urfave/cli-docs/v3 v3.0.0-alpha6 h1:w/l/N0xw1rO/aHRIGXJ0lDwwYFOzilup1 github.com/urfave/cli-docs/v3 v3.0.0-alpha6/go.mod h1:p7Z4lg8FSTrPB9GTaNyTrK3ygffHZcK3w0cU2VE+mzU= github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM= github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= -github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= -github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8= github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= diff --git a/models/user/setting_options.go b/models/user/setting_options.go index 6d37ef63d5..587a46e8de 100644 --- a/models/user/setting_options.go +++ b/models/user/setting_options.go @@ -11,10 +11,6 @@ const ( // SettingsKeyShowOutdatedComments is the setting key whether or not to show outdated comments in PRs SettingsKeyShowOutdatedComments = "comment_code.show_outdated" - // UserActivityPubPrivPem is user's private key - UserActivityPubPrivPem = "activitypub.priv_pem" - // UserActivityPubPubPem is user's public key - UserActivityPubPubPem = "activitypub.pub_pem" // SignupIP is the IP address that the user signed up with SignupIP = "signup.ip" // SignupUserAgent is the user agent that the user signed up with diff --git a/modules/activitypub/client.go b/modules/activitypub/client.go deleted file mode 100644 index a9941f9b75..0000000000 --- a/modules/activitypub/client.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activitypub - -import ( - "bytes" - "context" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "fmt" - "net/http" - "strings" - "time" - - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/setting" - - "github.com/42wim/httpsig" -) - -const ( - // ActivityStreamsContentType const - ActivityStreamsContentType = `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` - httpsigExpirationTime = 60 -) - -// Gets the current time as an RFC 2616 formatted string -// RFC 2616 requires RFC 1123 dates but with GMT instead of UTC -func CurrentTime() string { - return strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT") -} - -func containsRequiredHTTPHeaders(method string, headers []string) error { - var hasRequestTarget, hasDate, hasDigest bool - for _, header := range headers { - hasRequestTarget = hasRequestTarget || header == httpsig.RequestTarget - hasDate = hasDate || header == "Date" - hasDigest = hasDigest || header == "Digest" - } - if !hasRequestTarget { - return fmt.Errorf("missing http header for %s: %s", method, httpsig.RequestTarget) - } else if !hasDate { - return fmt.Errorf("missing http header for %s: Date", method) - } else if !hasDigest && method != http.MethodGet { - return fmt.Errorf("missing http header for %s: Digest", method) - } - return nil -} - -// Client struct -type Client struct { - client *http.Client - algs []httpsig.Algorithm - digestAlg httpsig.DigestAlgorithm - getHeaders []string - postHeaders []string - priv *rsa.PrivateKey - pubID string -} - -// NewClient function -func NewClient(ctx context.Context, user *user_model.User, pubID string) (c *Client, err error) { - if err = containsRequiredHTTPHeaders(http.MethodGet, setting.Federation.GetHeaders); err != nil { - return nil, err - } else if err = containsRequiredHTTPHeaders(http.MethodPost, setting.Federation.PostHeaders); err != nil { - return nil, err - } - - priv, err := GetPrivateKey(ctx, user) - if err != nil { - return nil, err - } - privPem, _ := pem.Decode([]byte(priv)) - privParsed, err := x509.ParsePKCS1PrivateKey(privPem.Bytes) - if err != nil { - return nil, err - } - - c = &Client{ - client: &http.Client{ - Transport: &http.Transport{ - Proxy: proxy.Proxy(), - }, - }, - algs: setting.HttpsigAlgs, - digestAlg: httpsig.DigestAlgorithm(setting.Federation.DigestAlgorithm), - getHeaders: setting.Federation.GetHeaders, - postHeaders: setting.Federation.PostHeaders, - priv: privParsed, - pubID: pubID, - } - return c, err -} - -// NewRequest function -func (c *Client) NewRequest(b []byte, to string) (req *http.Request, err error) { - buf := bytes.NewBuffer(b) - req, err = http.NewRequest(http.MethodPost, to, buf) - if err != nil { - return nil, err - } - req.Header.Add("Content-Type", ActivityStreamsContentType) - req.Header.Add("Date", CurrentTime()) - req.Header.Add("User-Agent", "Gitea/"+setting.AppVer) - signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime) - if err != nil { - return nil, err - } - err = signer.SignRequest(c.priv, c.pubID, req, b) - return req, err -} - -// Post function -func (c *Client) Post(b []byte, to string) (resp *http.Response, err error) { - var req *http.Request - if req, err = c.NewRequest(b, to); err != nil { - return nil, err - } - resp, err = c.client.Do(req) - return resp, err -} diff --git a/modules/activitypub/client_test.go b/modules/activitypub/client_test.go deleted file mode 100644 index 361270a800..0000000000 --- a/modules/activitypub/client_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activitypub - -import ( - "fmt" - "io" - "net/http" - "net/http/httptest" - "testing" - - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" - - "github.com/stretchr/testify/assert" -) - -func TestActivityPubSignedPost(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - pubID := "https://example.com/pubID" - c, err := NewClient(t.Context(), user, pubID) - assert.NoError(t, err) - - expected := "BODY" - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Regexp(t, "^"+setting.Federation.DigestAlgorithm, r.Header.Get("Digest")) - assert.Contains(t, r.Header.Get("Signature"), pubID) - assert.Equal(t, ActivityStreamsContentType, r.Header.Get("Content-Type")) - body, err := io.ReadAll(r.Body) - assert.NoError(t, err) - assert.Equal(t, expected, string(body)) - fmt.Fprint(w, expected) - })) - defer srv.Close() - - r, err := c.Post([]byte(expected), srv.URL) - assert.NoError(t, err) - defer r.Body.Close() - body, err := io.ReadAll(r.Body) - assert.NoError(t, err) - assert.Equal(t, expected, string(body)) -} diff --git a/modules/activitypub/main_test.go b/modules/activitypub/main_test.go deleted file mode 100644 index 4591f1fa55..0000000000 --- a/modules/activitypub/main_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activitypub - -import ( - "testing" - - "code.gitea.io/gitea/models/unittest" - - _ "code.gitea.io/gitea/models" - _ "code.gitea.io/gitea/models/actions" - _ "code.gitea.io/gitea/models/activities" -) - -func TestMain(m *testing.M) { - unittest.MainTest(m) -} diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go deleted file mode 100644 index 7f939af352..0000000000 --- a/modules/activitypub/user_settings.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activitypub - -import ( - "context" - - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/util" -) - -const rsaBits = 3072 - -// GetKeyPair function returns a user's private and public keys -func GetKeyPair(ctx context.Context, user *user_model.User) (pub, priv string, err error) { - var settings map[string]*user_model.Setting - settings, err = user_model.GetSettings(ctx, user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) - if err != nil { - return pub, priv, err - } else if len(settings) == 0 { - if priv, pub, err = util.GenerateKeyPair(rsaBits); err != nil { - return pub, priv, err - } - if err = user_model.SetUserSetting(ctx, user.ID, user_model.UserActivityPubPrivPem, priv); err != nil { - return pub, priv, err - } - if err = user_model.SetUserSetting(ctx, user.ID, user_model.UserActivityPubPubPem, pub); err != nil { - return pub, priv, err - } - return pub, priv, err - } - priv = settings[user_model.UserActivityPubPrivPem].SettingValue - pub = settings[user_model.UserActivityPubPubPem].SettingValue - return pub, priv, err -} - -// GetPublicKey function returns a user's public key -func GetPublicKey(ctx context.Context, user *user_model.User) (pub string, err error) { - pub, _, err = GetKeyPair(ctx, user) - return pub, err -} - -// GetPrivateKey function returns a user's private key -func GetPrivateKey(ctx context.Context, user *user_model.User) (priv string, err error) { - _, priv, err = GetKeyPair(ctx, user) - return priv, err -} diff --git a/modules/activitypub/user_settings_test.go b/modules/activitypub/user_settings_test.go deleted file mode 100644 index 105d4aedea..0000000000 --- a/modules/activitypub/user_settings_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activitypub - -import ( - "testing" - - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - - _ "code.gitea.io/gitea/models" // https://forum.gitea.com/t/testfixtures-could-not-clean-table-access-no-such-table-access/4137/4 - - "github.com/stretchr/testify/assert" -) - -func TestUserSettings(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - pub, priv, err := GetKeyPair(t.Context(), user1) - assert.NoError(t, err) - pub1, err := GetPublicKey(t.Context(), user1) - assert.NoError(t, err) - assert.Equal(t, pub, pub1) - priv1, err := GetPrivateKey(t.Context(), user1) - assert.NoError(t, err) - assert.Equal(t, priv, priv1) -} diff --git a/modules/structs/activitypub.go b/modules/structs/activitypub.go deleted file mode 100644 index 39a6c1ac2a..0000000000 --- a/modules/structs/activitypub.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package structs - -// ActivityPub type -type ActivityPub struct { - // Context defines the JSON-LD context for ActivityPub - Context string `json:"@context"` -} diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index f2ba2baf7f..2ee3368a87 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -4,103 +4,11 @@ package activitypub import ( - "fmt" "net/http" - "strings" - "code.gitea.io/gitea/modules/activitypub" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/context" - - ap "github.com/go-ap/activitypub" - "github.com/go-ap/jsonld" ) -// Person function returns the Person actor for a user -func Person(ctx *context.APIContext) { - // swagger:operation GET /activitypub/user-id/{user-id} activitypub activitypubPerson - // --- - // summary: Returns the Person actor for a user - // produces: - // - application/json - // parameters: - // - name: user-id - // in: path - // description: user ID of the user - // type: integer - // required: true - // responses: - // "200": - // "$ref": "#/responses/ActivityPub" - - // TODO: the setting.AppURL during the test doesn't follow the definition: "It always has a '/' suffix" - link := fmt.Sprintf("%s/api/v1/activitypub/user-id/%d", strings.TrimSuffix(setting.AppURL, "/"), ctx.ContextUser.ID) - person := ap.PersonNew(ap.IRI(link)) - - person.Name = ap.NaturalLanguageValuesNew() - err := person.Name.Set("en", ap.Content(ctx.ContextUser.FullName)) - if err != nil { - ctx.APIErrorInternal(err) - return - } - - person.PreferredUsername = ap.NaturalLanguageValuesNew() - err = person.PreferredUsername.Set("en", ap.Content(ctx.ContextUser.Name)) - if err != nil { - ctx.APIErrorInternal(err) - return - } - - person.URL = ap.IRI(ctx.ContextUser.HTMLURL(ctx)) - - person.Icon = ap.Image{ - Type: ap.ImageType, - MediaType: "image/png", - URL: ap.IRI(ctx.ContextUser.AvatarLink(ctx)), - } - - person.Inbox = ap.IRI(link + "/inbox") - person.Outbox = ap.IRI(link + "/outbox") - - person.PublicKey.ID = ap.IRI(link + "#main-key") - person.PublicKey.Owner = ap.IRI(link) - - publicKeyPem, err := activitypub.GetPublicKey(ctx, ctx.ContextUser) - if err != nil { - ctx.APIErrorInternal(err) - return - } - person.PublicKey.PublicKeyPem = publicKeyPem - - binary, err := jsonld.WithContext(jsonld.IRI(ap.ActivityBaseURI), jsonld.IRI(ap.SecurityContextURI)).Marshal(person) - if err != nil { - ctx.APIErrorInternal(err) - return - } - ctx.Resp.Header().Add("Content-Type", activitypub.ActivityStreamsContentType) - ctx.Resp.WriteHeader(http.StatusOK) - if _, err = ctx.Resp.Write(binary); err != nil { - log.Error("write to resp err: %v", err) - } -} - -// PersonInbox function handles the incoming data for a user inbox -func PersonInbox(ctx *context.APIContext) { - // swagger:operation POST /activitypub/user-id/{user-id}/inbox activitypub activitypubPersonInbox - // --- - // summary: Send to the inbox - // produces: - // - application/json - // parameters: - // - name: user-id - // in: path - // description: user ID of the user - // type: integer - // required: true - // responses: - // "204": - // "$ref": "#/responses/empty" - - ctx.Status(http.StatusNoContent) +func NotImplemented(ctx *context.APIContext) { + http.Error(ctx.Resp, "Not implemented", http.StatusNotImplemented) } diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go deleted file mode 100644 index 4eff51782f..0000000000 --- a/routers/api/v1/activitypub/reqsignature.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package activitypub - -import ( - "crypto" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "io" - "net/http" - "net/url" - - "code.gitea.io/gitea/modules/activitypub" - "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/setting" - gitea_context "code.gitea.io/gitea/services/context" - - "github.com/42wim/httpsig" - ap "github.com/go-ap/activitypub" -) - -func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err error) { - person := ap.PersonNew(ap.IRI(keyID.String())) - err = person.UnmarshalJSON(b) - if err != nil { - return nil, fmt.Errorf("ActivityStreams type cannot be converted to one known to have publicKey property: %w", err) - } - pubKey := person.PublicKey - if pubKey.ID.String() != keyID.String() { - return nil, fmt.Errorf("cannot find publicKey with id: %s in %s", keyID, string(b)) - } - pubKeyPem := pubKey.PublicKeyPem - block, _ := pem.Decode([]byte(pubKeyPem)) - if block == nil || block.Type != "PUBLIC KEY" { - return nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type") - } - p, err = x509.ParsePKIXPublicKey(block.Bytes) - return p, err -} - -func fetch(iri *url.URL) (b []byte, err error) { - req := httplib.NewRequest(iri.String(), http.MethodGet) - req.Header("Accept", activitypub.ActivityStreamsContentType) - req.Header("User-Agent", "Gitea/"+setting.AppVer) - resp, err := req.Response() - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status) - } - b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize)) - return b, err -} - -func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, err error) { - r := ctx.Req - - // 1. Figure out what key we need to verify - v, err := httpsig.NewVerifier(r) - if err != nil { - return false, err - } - ID := v.KeyId() - idIRI, err := url.Parse(ID) - if err != nil { - return false, err - } - // 2. Fetch the public key of the other actor - b, err := fetch(idIRI) - if err != nil { - return false, err - } - pubKey, err := getPublicKeyFromResponse(b, idIRI) - if err != nil { - return false, err - } - // 3. Verify the other actor's key - algo := httpsig.Algorithm(setting.Federation.Algorithms[0]) - authenticated = v.Verify(pubKey, algo) == nil - return authenticated, err -} - -// ReqHTTPSignature function -func ReqHTTPSignature() func(ctx *gitea_context.APIContext) { - return func(ctx *gitea_context.APIContext) { - if authenticated, err := verifyHTTPSignatures(ctx); err != nil { - ctx.APIErrorInternal(err) - } else if !authenticated { - ctx.APIError(http.StatusForbidden, "request signature verification failed") - } - } -} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 359d5af4c4..9dc51bc907 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -936,18 +936,8 @@ func Routes() *web.Router { } if setting.Federation.Enabled { - m.Get("/nodeinfo", misc.NodeInfo) - m.Group("/activitypub", func() { - // deprecated, remove in 1.20, use /user-id/{user-id} instead - m.Group("/user/{username}", func() { - m.Get("", activitypub.Person) - m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox) - }, context.UserAssignmentAPI(), checkTokenPublicOnly()) - m.Group("/user-id/{user-id}", func() { - m.Get("", activitypub.Person) - m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox) - }, context.UserIDAssignmentAPI(), checkTokenPublicOnly()) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub)) + m.Get("/nodeinfo", activitypub.NotImplemented) + m.Any("/activitypub/*", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub), activitypub.NotImplemented) } // Misc (public accessible) diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go deleted file mode 100644 index ffe50e9fda..0000000000 --- a/routers/api/v1/misc/nodeinfo.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package misc - -import ( - "net/http" - "time" - - issues_model "code.gitea.io/gitea/models/issues" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/context" -) - -const cacheKeyNodeInfoUsage = "API_NodeInfoUsage" - -// NodeInfo returns the NodeInfo for the Gitea instance to allow for federation -func NodeInfo(ctx *context.APIContext) { - // swagger:operation GET /nodeinfo miscellaneous getNodeInfo - // --- - // summary: Returns the nodeinfo of the Gitea application - // produces: - // - application/json - // responses: - // "200": - // "$ref": "#/responses/NodeInfo" - - nodeInfoUsage := structs.NodeInfoUsage{} - if setting.Federation.ShareUserStatistics { - cached, _ := ctx.Cache.GetJSON(cacheKeyNodeInfoUsage, &nodeInfoUsage) - if !cached { - usersTotal := int(user_model.CountUsers(ctx, nil)) - now := time.Now() - timeOneMonthAgo := now.AddDate(0, -1, 0).Unix() - timeHaveYearAgo := now.AddDate(0, -6, 0).Unix() - usersActiveMonth := int(user_model.CountUsers(ctx, &user_model.CountUserFilter{LastLoginSince: &timeOneMonthAgo})) - usersActiveHalfyear := int(user_model.CountUsers(ctx, &user_model.CountUserFilter{LastLoginSince: &timeHaveYearAgo})) - - allIssues, _ := issues_model.CountIssues(ctx, &issues_model.IssuesOptions{}) - allComments, _ := issues_model.CountComments(ctx, &issues_model.FindCommentsOptions{}) - - nodeInfoUsage = structs.NodeInfoUsage{ - Users: structs.NodeInfoUsageUsers{ - Total: usersTotal, - ActiveMonth: usersActiveMonth, - ActiveHalfyear: usersActiveHalfyear, - }, - LocalPosts: int(allIssues), - LocalComments: int(allComments), - } - - if err := ctx.Cache.PutJSON(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil { - ctx.APIErrorInternal(err) - return - } - } - } - - nodeInfo := &structs.NodeInfo{ - Version: "2.1", - Software: structs.NodeInfoSoftware{ - Name: "gitea", - Version: setting.AppVer, - Repository: "https://github.com/go-gitea/gitea.git", - Homepage: "https://gitea.io/", - }, - Protocols: []string{"activitypub"}, - Services: structs.NodeInfoServices{ - Inbound: []string{}, - Outbound: []string{"rss2.0"}, - }, - OpenRegistrations: setting.Service.ShowRegistrationButton, - Usage: nodeInfoUsage, - } - ctx.JSON(http.StatusOK, nodeInfo) -} diff --git a/routers/api/v1/swagger/activitypub.go b/routers/api/v1/swagger/activitypub.go deleted file mode 100644 index 91341669da..0000000000 --- a/routers/api/v1/swagger/activitypub.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package swagger - -import ( - api "code.gitea.io/gitea/modules/structs" -) - -// ActivityPub -// swagger:response ActivityPub -type swaggerResponseActivityPub struct { - // in:body - Body api.ActivityPub `json:"body"` -} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 212046f8e6..7031f0aab9 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -23,58 +23,6 @@ }, "basePath": "{{.SwaggerAppSubUrl}}/api/v1", "paths": { - "/activitypub/user-id/{user-id}": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "activitypub" - ], - "summary": "Returns the Person actor for a user", - "operationId": "activitypubPerson", - "parameters": [ - { - "type": "integer", - "description": "user ID of the user", - "name": "user-id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/ActivityPub" - } - } - } - }, - "/activitypub/user-id/{user-id}/inbox": { - "post": { - "produces": [ - "application/json" - ], - "tags": [ - "activitypub" - ], - "summary": "Send to the inbox", - "operationId": "activitypubPersonInbox", - "parameters": [ - { - "type": "integer", - "description": "user ID of the user", - "name": "user-id", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "$ref": "#/responses/empty" - } - } - } - }, "/admin/actions/jobs": { "get": { "produces": [ @@ -1526,23 +1474,6 @@ } } }, - "/nodeinfo": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "miscellaneous" - ], - "summary": "Returns the nodeinfo of the Gitea application", - "operationId": "getNodeInfo", - "responses": { - "200": { - "$ref": "#/responses/NodeInfo" - } - } - } - }, "/notifications": { "get": { "consumes": [ @@ -21771,18 +21702,6 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, - "ActivityPub": { - "description": "ActivityPub type", - "type": "object", - "properties": { - "@context": { - "description": "Context defines the JSON-LD context for ActivityPub", - "type": "string", - "x-go-name": "Context" - } - }, - "x-go-package": "code.gitea.io/gitea/modules/structs" - }, "AddCollaboratorOption": { "description": "AddCollaboratorOption options when adding a user as a collaborator of a repository", "type": "object", @@ -29513,12 +29432,6 @@ } } }, - "ActivityPub": { - "description": "ActivityPub", - "schema": { - "$ref": "#/definitions/ActivityPub" - } - }, "AnnotatedTag": { "description": "AnnotatedTag", "schema": { diff --git a/tests/integration/api_activitypub_person_test.go b/tests/integration/api_activitypub_person_test.go deleted file mode 100644 index 3f1bd4823a..0000000000 --- a/tests/integration/api_activitypub_person_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package integration - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" - - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/activitypub" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/routers" - "code.gitea.io/gitea/tests" - - ap "github.com/go-ap/activitypub" - "github.com/stretchr/testify/assert" -) - -func TestActivityPubPerson(t *testing.T) { - defer tests.PrepareTestEnv(t)() - defer test.MockVariableValue(&setting.Federation.Enabled, true)() - defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() - - t.Run("ExistingPerson", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - userID := 2 - username := "user2" - req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/user-id/%v", userID)) - resp := MakeRequest(t, req, http.StatusOK) - body := resp.Body.Bytes() - assert.Contains(t, string(body), "@context") - - var person ap.Person - err := person.UnmarshalJSON(body) - assert.NoError(t, err) - - assert.Equal(t, ap.PersonType, person.Type) - assert.Equal(t, username, person.PreferredUsername.String()) - keyID := person.GetID().String() - assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v$", userID), keyID) - assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/outbox$", userID), person.Outbox.GetID().String()) - assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/inbox$", userID), person.Inbox.GetID().String()) - - pubKey := person.PublicKey - assert.NotNil(t, pubKey) - publicKeyID := keyID + "#main-key" - assert.Equal(t, pubKey.ID.String(), publicKeyID) - - pubKeyPem := pubKey.PublicKeyPem - assert.NotNil(t, pubKeyPem) - assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem) - }) - t.Run("MissingPerson", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "GET", "/api/v1/activitypub/user-id/999999999") - resp := MakeRequest(t, req, http.StatusNotFound) - assert.Contains(t, resp.Body.String(), "user does not exist") - }) - t.Run("MissingPersonInbox", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - srv := httptest.NewServer(testWebRoutes) - defer srv.Close() - defer test.MockVariableValue(&setting.AppURL, srv.URL+"/")() - - username1 := "user1" - ctx := t.Context() - user1, err := user_model.GetUserByName(ctx, username1) - assert.NoError(t, err) - user1url := srv.URL + "/api/v1/activitypub/user-id/1#main-key" - c, err := activitypub.NewClient(t.Context(), user1, user1url) - assert.NoError(t, err) - user2inboxurl := srv.URL + "/api/v1/activitypub/user-id/2/inbox" - - // Signed request succeeds - resp, err := c.Post([]byte{}, user2inboxurl) - defer resp.Body.Close() - assert.NoError(t, err) - assert.Equal(t, http.StatusNoContent, resp.StatusCode) - - // Unsigned request fails - req := NewRequest(t, "POST", user2inboxurl) - MakeRequest(t, req, http.StatusInternalServerError) - }) -} diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go deleted file mode 100644 index 916c2f1723..0000000000 --- a/tests/integration/api_nodeinfo_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package integration - -import ( - "net/http" - "testing" - - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/routers" - "code.gitea.io/gitea/tests" - - "github.com/stretchr/testify/assert" -) - -func TestNodeinfo(t *testing.T) { - defer tests.PrepareTestEnv(t)() - defer test.MockVariableValue(&setting.Federation.Enabled, true)() - defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() - - req := NewRequest(t, "GET", "/api/v1/nodeinfo") - resp := MakeRequest(t, req, http.StatusOK) - VerifyJSONSchema(t, resp, "nodeinfo_2.1.json") - - var nodeinfo api.NodeInfo - DecodeJSON(t, resp, &nodeinfo) - assert.True(t, nodeinfo.OpenRegistrations) - assert.Equal(t, "gitea", nodeinfo.Software.Name) - assert.Equal(t, 29, nodeinfo.Usage.Users.Total) - assert.Equal(t, 22, nodeinfo.Usage.LocalPosts) - assert.Equal(t, 3, nodeinfo.Usage.LocalComments) -} diff --git a/tests/integration/schemas/nodeinfo_2.1.json b/tests/integration/schemas/nodeinfo_2.1.json deleted file mode 100644 index 561e644797..0000000000 --- a/tests/integration/schemas/nodeinfo_2.1.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "http://nodeinfo.diaspora.software/ns/schema/2.1#", - "description": "NodeInfo schema version 2.1.", - "type": "object", - "additionalProperties": false, - "required": [ - "version", - "software", - "protocols", - "services", - "openRegistrations", - "usage", - "metadata" - ], - "properties": { - "version": { - "description": "The schema version, must be 2.1.", - "enum": [ - "2.1" - ] - }, - "software": { - "description": "Metadata about server software in use.", - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "version" - ], - "properties": { - "name": { - "description": "The canonical name of this server software.", - "type": "string", - "pattern": "^[a-z0-9-]+$" - }, - "version": { - "description": "The version of this server software.", - "type": "string" - }, - "repository": { - "description": "The url of the source code repository of this server software.", - "type": "string" - }, - "homepage": { - "description": "The url of the homepage of this server software.", - "type": "string" - } - } - }, - "protocols": { - "description": "The protocols supported on this server.", - "type": "array", - "minItems": 1, - "items": { - "enum": [ - "activitypub", - "buddycloud", - "dfrn", - "diaspora", - "libertree", - "ostatus", - "pumpio", - "tent", - "xmpp", - "zot" - ] - } - }, - "services": { - "description": "The third party sites this server can connect to via their application API.", - "type": "object", - "additionalProperties": false, - "required": [ - "inbound", - "outbound" - ], - "properties": { - "inbound": { - "description": "The third party sites this server can retrieve messages from for combined display with regular traffic.", - "type": "array", - "minItems": 0, - "items": { - "enum": [ - "atom1.0", - "gnusocial", - "imap", - "pnut", - "pop3", - "pumpio", - "rss2.0", - "twitter" - ] - } - }, - "outbound": { - "description": "The third party sites this server can publish messages to on the behalf of a user.", - "type": "array", - "minItems": 0, - "items": { - "enum": [ - "atom1.0", - "blogger", - "buddycloud", - "diaspora", - "dreamwidth", - "drupal", - "facebook", - "friendica", - "gnusocial", - "google", - "insanejournal", - "libertree", - "linkedin", - "livejournal", - "mediagoblin", - "myspace", - "pinterest", - "pnut", - "posterous", - "pumpio", - "redmatrix", - "rss2.0", - "smtp", - "tent", - "tumblr", - "twitter", - "wordpress", - "xmpp" - ] - } - } - } - }, - "openRegistrations": { - "description": "Whether this server allows open self-registration.", - "type": "boolean" - }, - "usage": { - "description": "Usage statistics for this server.", - "type": "object", - "additionalProperties": false, - "required": [ - "users" - ], - "properties": { - "users": { - "description": "statistics about the users of this server.", - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "description": "The total amount of on this server registered users.", - "type": "integer", - "minimum": 0 - }, - "activeHalfyear": { - "description": "The amount of users that signed in at least once in the last 180 days.", - "type": "integer", - "minimum": 0 - }, - "activeMonth": { - "description": "The amount of users that signed in at least once in the last 30 days.", - "type": "integer", - "minimum": 0 - } - } - }, - "localPosts": { - "description": "The amount of posts that were made by users that are registered on this server.", - "type": "integer", - "minimum": 0 - }, - "localComments": { - "description": "The amount of comments that were made by users that are registered on this server.", - "type": "integer", - "minimum": 0 - } - } - }, - "metadata": { - "description": "Free form key value pairs for software specific values. Clients should not rely on any specific key present.", - "type": "object", - "minProperties": 0, - "additionalProperties": true - } - } -} diff --git a/tests/integration/webfinger_test.go b/tests/integration/webfinger_test.go deleted file mode 100644 index 6efc44e603..0000000000 --- a/tests/integration/webfinger_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package integration - -import ( - "fmt" - "net/http" - "net/url" - "strconv" - "testing" - - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/tests" - - "github.com/stretchr/testify/assert" -) - -func TestWebfinger(t *testing.T) { - defer tests.PrepareTestEnv(t)() - defer test.MockVariableValue(&setting.Federation.Enabled, true)() - - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - - appURL, _ := url.Parse(setting.AppURL) - - type webfingerLink struct { - Rel string `json:"rel,omitempty"` - Type string `json:"type,omitempty"` - Href string `json:"href,omitempty"` - Titles map[string]string `json:"titles,omitempty"` - Properties map[string]any `json:"properties,omitempty"` - } - - type webfingerJRD struct { - Subject string `json:"subject,omitempty"` - Aliases []string `json:"aliases,omitempty"` - Properties map[string]any `json:"properties,omitempty"` - Links []*webfingerLink `json:"links,omitempty"` - } - - session := loginUser(t, "user1") - - req := NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", user.LowerName, appURL.Host)) - resp := MakeRequest(t, req, http.StatusOK) - - var jrd webfingerJRD - DecodeJSON(t, resp, &jrd) - assert.Equal(t, "acct:user2@"+appURL.Host, jrd.Subject) - assert.ElementsMatch(t, []string{user.HTMLURL(t.Context()), appURL.String() + "api/v1/activitypub/user-id/" + strconv.FormatInt(user.ID, 10)}, jrd.Aliases) - - req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", user.LowerName, "unknown.host")) - MakeRequest(t, req, http.StatusBadRequest) - - req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", "user31", appURL.Host)) - MakeRequest(t, req, http.StatusNotFound) - - req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", "user31", appURL.Host)) - session.MakeRequest(t, req, http.StatusOK) - - req = NewRequest(t, "GET", "/.well-known/webfinger?resource=mailto:"+user.Email) - MakeRequest(t, req, http.StatusNotFound) -}