diff --git a/cmd/furl/main.go b/cmd/furl/main.go new file mode 100644 index 00000000..efaaa4b8 --- /dev/null +++ b/cmd/furl/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "bufio" + "bytes" + "context" + "crypto/ed25519" + "encoding/json" + "encoding/pem" + "flag" + "fmt" + "io/ioutil" + "net/url" + "os" + + "github.com/matrix-org/gomatrixserverlib" +) + +var requestFrom = flag.String("from", "", "the server name that the request should originate from") +var requestKey = flag.String("key", "matrix_key.pem", "the private key to use when signing the request") +var requestPost = flag.Bool("post", false, "send a POST request instead of GET (pipe input into stdin or type followed by Ctrl-D)") + +func main() { + flag.Parse() + + if requestFrom == nil || *requestFrom == "" { + fmt.Println("expecting: furl -from origin.com [-key matrix_key.pem] https://path/to/url") + fmt.Println("supported flags:") + flag.PrintDefaults() + os.Exit(1) + } + + data, err := ioutil.ReadFile(*requestKey) + if err != nil { + panic(err) + } + + var privateKey ed25519.PrivateKey + keyBlock, _ := pem.Decode(data) + if keyBlock == nil { + panic("keyBlock is nil") + } + if keyBlock.Type == "MATRIX PRIVATE KEY" { + _, privateKey, err = ed25519.GenerateKey(bytes.NewReader(keyBlock.Bytes)) + if err != nil { + panic(err) + } + } else { + panic("unexpected key block") + } + + client := gomatrixserverlib.NewFederationClient( + gomatrixserverlib.ServerName(*requestFrom), + gomatrixserverlib.KeyID(keyBlock.Headers["Key-ID"]), + privateKey, + false, + ) + + u, err := url.Parse(flag.Arg(0)) + if err != nil { + panic(err) + } + + var bodyObj interface{} + var bodyBytes []byte + method := "GET" + if *requestPost { + method = "POST" + fmt.Println("Waiting for JSON input. Press Enter followed by Ctrl-D when done...") + + scan := bufio.NewScanner(os.Stdin) + for scan.Scan() { + bytes := scan.Bytes() + bodyBytes = append(bodyBytes, bytes...) + } + fmt.Println("Done!") + if err = json.Unmarshal(bodyBytes, &bodyObj); err != nil { + panic(err) + } + } + + req := gomatrixserverlib.NewFederationRequest( + method, + gomatrixserverlib.ServerName(u.Host), + u.RequestURI(), + ) + + if *requestPost { + if err = req.SetContent(bodyObj); err != nil { + panic(err) + } + } + + if err = req.Sign( + gomatrixserverlib.ServerName(*requestFrom), + gomatrixserverlib.KeyID(keyBlock.Headers["Key-ID"]), + privateKey, + ); err != nil { + panic(err) + } + + httpReq, err := req.HTTPRequest() + if err != nil { + panic(err) + } + + var res interface{} + err = client.DoRequestAndParseResponse( + context.TODO(), + httpReq, + &res, + ) + if err != nil { + panic(err) + } + + j, err := json.MarshalIndent(res, "", " ") + if err != nil { + panic(err) + } + + fmt.Println(string(j)) +}