aboutsummaryrefslogtreecommitdiff
path: root/cmd/furl/main.go
blob: cdfef09f73614735501452a45ae2bf5a2913b891 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main

import (
	"bufio"
	"bytes"
	"context"
	"crypto/ed25519"
	"encoding/json"
	"encoding/pem"
	"flag"
	"fmt"
	"net/url"
	"os"

	"github.com/matrix-org/gomatrixserverlib"
	"github.com/matrix-org/gomatrixserverlib/fclient"
	"github.com/matrix-org/gomatrixserverlib/spec"
)

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 := os.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")
	}

	serverName := spec.ServerName(*requestFrom)
	client := fclient.NewFederationClient(
		[]*fclient.SigningIdentity{
			{
				ServerName: serverName,
				KeyID:      gomatrixserverlib.KeyID(keyBlock.Headers["Key-ID"]),
				PrivateKey: privateKey,
			},
		},
	)

	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 := fclient.NewFederationRequest(
		method,
		serverName,
		spec.ServerName(u.Host),
		u.RequestURI(),
	)

	if *requestPost {
		if err = req.SetContent(bodyObj); err != nil {
			panic(err)
		}
	}

	if err = req.Sign(
		spec.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))
}