gitea源码

reqsignature.go 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package activitypub
  4. import (
  5. "crypto"
  6. "crypto/x509"
  7. "encoding/pem"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "net/http"
  12. "net/url"
  13. "code.gitea.io/gitea/modules/activitypub"
  14. "code.gitea.io/gitea/modules/httplib"
  15. "code.gitea.io/gitea/modules/setting"
  16. gitea_context "code.gitea.io/gitea/services/context"
  17. "github.com/42wim/httpsig"
  18. ap "github.com/go-ap/activitypub"
  19. )
  20. func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err error) {
  21. person := ap.PersonNew(ap.IRI(keyID.String()))
  22. err = person.UnmarshalJSON(b)
  23. if err != nil {
  24. return nil, fmt.Errorf("ActivityStreams type cannot be converted to one known to have publicKey property: %w", err)
  25. }
  26. pubKey := person.PublicKey
  27. if pubKey.ID.String() != keyID.String() {
  28. return nil, fmt.Errorf("cannot find publicKey with id: %s in %s", keyID, string(b))
  29. }
  30. pubKeyPem := pubKey.PublicKeyPem
  31. block, _ := pem.Decode([]byte(pubKeyPem))
  32. if block == nil || block.Type != "PUBLIC KEY" {
  33. return nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type")
  34. }
  35. p, err = x509.ParsePKIXPublicKey(block.Bytes)
  36. return p, err
  37. }
  38. func fetch(iri *url.URL) (b []byte, err error) {
  39. req := httplib.NewRequest(iri.String(), http.MethodGet)
  40. req.Header("Accept", activitypub.ActivityStreamsContentType)
  41. req.Header("User-Agent", "Gitea/"+setting.AppVer)
  42. resp, err := req.Response()
  43. if err != nil {
  44. return nil, err
  45. }
  46. defer resp.Body.Close()
  47. if resp.StatusCode != http.StatusOK {
  48. return nil, fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
  49. }
  50. b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize))
  51. return b, err
  52. }
  53. func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, err error) {
  54. r := ctx.Req
  55. // 1. Figure out what key we need to verify
  56. v, err := httpsig.NewVerifier(r)
  57. if err != nil {
  58. return false, err
  59. }
  60. ID := v.KeyId()
  61. idIRI, err := url.Parse(ID)
  62. if err != nil {
  63. return false, err
  64. }
  65. // 2. Fetch the public key of the other actor
  66. b, err := fetch(idIRI)
  67. if err != nil {
  68. return false, err
  69. }
  70. pubKey, err := getPublicKeyFromResponse(b, idIRI)
  71. if err != nil {
  72. return false, err
  73. }
  74. // 3. Verify the other actor's key
  75. algo := httpsig.Algorithm(setting.Federation.Algorithms[0])
  76. authenticated = v.Verify(pubKey, algo) == nil
  77. return authenticated, err
  78. }
  79. // ReqHTTPSignature function
  80. func ReqHTTPSignature() func(ctx *gitea_context.APIContext) {
  81. return func(ctx *gitea_context.APIContext) {
  82. if authenticated, err := verifyHTTPSignatures(ctx); err != nil {
  83. ctx.APIErrorInternal(err)
  84. } else if !authenticated {
  85. ctx.APIError(http.StatusForbidden, "request signature verification failed")
  86. }
  87. }
  88. }