From 8597ae7147f96c76ad4199a619a39629fc66d0be Mon Sep 17 00:00:00 2001 From: doesnm Date: Thu, 16 May 2024 22:31:02 +0300 Subject: [PATCH] feature,fix: add request validation and fix attachment --- actor.go | 11 +++-------- http.go | 24 ++++++++++++++++++++++-- remoteActor.go | 45 +++++++++++++++++---------------------------- 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/actor.go b/actor.go index 114523b..31d84f9 100644 --- a/actor.go +++ b/actor.go @@ -28,12 +28,7 @@ import ( // Actor represents a local actor we can act on // behalf of. -//type Attachment struct { -// Type string -// Name string -// Href string -// Rel string -//} + type Actor struct { Name, summary, actorType, iri string @@ -70,7 +65,7 @@ func MakeActor(name, summary, actorType string) (Actor, error) { following := make(map[string]interface{}) rejected := make(map[string]interface{}) requested := make(map[string]interface{}) - var attachment []interface{} + attachment := make([]interface{},0) followersIRI := baseURL + name + "/followers" publicKeyID := baseURL + name + "#main-key" iri := baseURL + name @@ -358,7 +353,7 @@ func (a *Actor) CreateNote(content, inReplyTo string,attachment []interface{}) { if inReplyTo != "" { note["inReplyTo"] = inReplyTo } - if inReplyTo != nil { + if attachment != nil { note["attachment"] = attachment } note["id"] = id diff --git a/http.go b/http.go index be750c8..2d265c1 100644 --- a/http.go +++ b/http.go @@ -10,7 +10,7 @@ import ( "github.com/gologme/log" "github.com/gorilla/mux" "github.com/writefreely/go-nodeinfo" - + "github.com/go-fed/httpsig" "encoding/json" ) @@ -190,7 +190,27 @@ func Serve(actors map[string]Actor) { return } // TODO check if it's actually an activity - + verifier, err := httpsig.NewVerifier(r) + if err != nil { + log.Error("Error then creating verifier") + w.WriteHeader(http.StatusUnauthorized) + return + } + pubKeyId := verifier.KeyId() + algo := httpsig.RSA_SHA256 + ra,err := NewRemoteActor(pubKeyId) + if err != nil { + log.Error("Can't fetch remote actor") + w.WriteHeader(http.StatusUnauthorized) + return + } + verified := verifier.Verify(ra.publicKey, algo) + log.Info(verified) + if verified != nil { + log.Error("Signature mismatch") + w.WriteHeader(http.StatusUnauthorized) + return + } // check if case is going to be an issue switch activity["type"] { case "Follow": diff --git a/remoteActor.go b/remoteActor.go index 86e99a2..83ca88b 100644 --- a/remoteActor.go +++ b/remoteActor.go @@ -1,35 +1,38 @@ package activityserve import ( - "bytes" "encoding/json" - "fmt" - "io/ioutil" - "net/http" - + "encoding/pem" "github.com/gologme/log" + "crypto/x509" + "crypto/rsa" ) // RemoteActor is a type that holds an actor -// that we want to interact with + // that we want to interact with type RemoteActor struct { iri, outbox, inbox, sharedInbox string url string info map[string]interface{} + publicKey *rsa.PublicKey } // NewRemoteActor returns a remoteActor which holds // all the info required for an actor we want to // interact with (not essentially sitting in our instance) func NewRemoteActor(iri string) (RemoteActor, error) { - info, err := get(iri) if err != nil { log.Info("Couldn't get remote actor information") log.Info(err) return RemoteActor{}, err } - + publicKeyBlock := info["publicKey"].(map[string]interface {}) + publicKeyPem := publicKeyBlock["publicKeyPem"].(string) + spkiBlock, _ := pem.Decode([]byte(publicKeyPem)) + var spkiKey *rsa.PublicKey + pubInterface, _ := x509.ParsePKIXPublicKey(spkiBlock.Bytes) + spkiKey = pubInterface.(*rsa.PublicKey) outbox, _ := info["outbox"].(string) inbox, _ := info["inbox"].(string) url, _ := info["url"].(string) @@ -48,6 +51,7 @@ func NewRemoteActor(iri string) (RemoteActor, error) { inbox: inbox, sharedInbox: sharedInbox, url: url, + publicKey: spkiKey, }, err } @@ -57,35 +61,20 @@ func (ra RemoteActor) getLatestPosts(number int) (map[string]interface{}, error) func get(iri string) (info map[string]interface{}, err error) { - buf := new(bytes.Buffer) - - req, err := http.NewRequest("GET", iri, buf) + sactor,err := GetActor("server","Internal service actor","Service") if err != nil { + log.Info("Failed to get service actor") log.Info(err) return } - req.Header.Add("Accept", "application/activity+json") - req.Header.Add("User-Agent", userAgent+" "+version) - req.Header.Add("Accept-Charset", "utf-8") - - resp, err := client.Do(req) - + responseData,err := sactor.signedHTTPGet(iri) if err != nil { - log.Info("Cannot perform the request") + log.Info("Failed to make signed http get request") log.Info(err) return } - - responseData, _ := ioutil.ReadAll(resp.Body) - - if !isSuccess(resp.StatusCode) { - err = fmt.Errorf("GET request to %s failed (%d): %s\nResponse: %s \nHeaders: %s", iri, resp.StatusCode, resp.Status, FormatJSON(responseData), FormatHeaders(req.Header)) - log.Info(err) - return - } - var e interface{} - err = json.Unmarshal(responseData, &e) + err = json.Unmarshal([]byte(responseData), &e) if err != nil { log.Info("something went wrong when unmarshalling the json")