+4
-2
appview/db/db.go
+4
-2
appview/db/db.go
+45
-12
appview/state/state.go
+45
-12
appview/state/state.go
···
4
4
"crypto/hmac"
5
5
"crypto/sha256"
6
6
"encoding/hex"
7
+
"fmt"
7
8
"log"
8
9
"net/http"
9
-
"net/url"
10
10
"time"
11
11
12
12
"github.com/go-chi/chi/v5"
···
83
83
84
84
// check if domain is valid url, and strip extra bits down to just host
85
85
domain := r.FormValue("domain")
86
-
url, err := url.Parse(domain)
87
86
if domain == "" || err != nil {
87
+
log.Println(err)
88
88
http.Error(w, "Invalid form", http.StatusBadRequest)
89
89
return
90
90
}
91
91
92
-
key, err := s.Db.GenerateRegistrationKey(url.Host, did)
92
+
key, err := s.Db.GenerateRegistrationKey(domain, did)
93
93
94
94
if err != nil {
95
95
log.Println(err)
···
112
112
return
113
113
}
114
114
115
+
log.Println("checking ", domain)
116
+
115
117
secret, err := s.Db.GetRegistrationKey(domain)
116
118
if err != nil {
117
119
log.Printf("no key found for domain %s: %s\n", domain, err)
118
120
return
119
121
}
120
-
121
-
hmac := hmac.New(sha256.New, []byte(secret))
122
-
signature := hex.EncodeToString(hmac.Sum(nil))
122
+
log.Println("has secret ", secret)
123
123
124
124
// make a request do the knotserver with an empty body and above signature
125
-
url, _ := url.Parse(domain)
126
-
url = url.JoinPath("check")
127
-
pingRequest, err := http.NewRequest("GET", url.String(), nil)
125
+
url := fmt.Sprintf("http://%s/internal/health", domain)
126
+
127
+
pingRequest, err := buildPingRequest(url, secret)
128
128
if err != nil {
129
-
log.Println("failed to create ping request for ", url.String())
129
+
log.Println("failed to build ping request", err)
130
130
return
131
131
}
132
-
pingRequest.Header.Set("X-Signature", signature)
133
132
134
133
client := &http.Client{
135
134
Timeout: 5 * time.Second,
···
142
141
}
143
142
144
143
if resp.StatusCode != http.StatusOK {
145
-
log.Println("status nok")
144
+
log.Println("status nok", resp.StatusCode)
146
145
w.Write([]byte("no dice"))
147
146
return
148
147
}
148
+
149
+
// verify response mac
150
+
signature := resp.Header.Get("X-Signature")
151
+
signatureBytes, err := hex.DecodeString(signature)
152
+
if err != nil {
153
+
return
154
+
}
155
+
156
+
expectedMac := hmac.New(sha256.New, []byte(secret))
157
+
expectedMac.Write([]byte("ok"))
158
+
159
+
if !hmac.Equal(expectedMac.Sum(nil), signatureBytes) {
160
+
log.Printf("response body signature mismatch: %x\n", signatureBytes)
161
+
return
162
+
}
163
+
149
164
w.Write([]byte("check success"))
150
165
151
166
// mark as registered
152
167
s.Db.Register(domain)
153
168
154
169
return
170
+
}
171
+
172
+
func buildPingRequest(url, secret string) (*http.Request, error) {
173
+
pingRequest, err := http.NewRequest("GET", url, nil)
174
+
if err != nil {
175
+
return nil, err
176
+
}
177
+
178
+
timestamp := time.Now().Format(time.RFC3339)
179
+
mac := hmac.New(sha256.New, []byte(secret))
180
+
message := pingRequest.Method + pingRequest.URL.Path + timestamp
181
+
mac.Write([]byte(message))
182
+
signature := hex.EncodeToString(mac.Sum(nil))
183
+
184
+
pingRequest.Header.Set("X-Signature", signature)
185
+
pingRequest.Header.Set("X-Timestamp", timestamp)
186
+
187
+
return pingRequest, nil
155
188
}
156
189
157
190
func (s *State) Router() http.Handler {
+3
-4
cmd/knotserver/main.go
+3
-4
cmd/knotserver/main.go
···
7
7
"log/slog"
8
8
"net/http"
9
9
"os"
10
-
"os/signal"
11
-
"syscall"
12
10
13
11
"github.com/icyphox/bild/knotserver"
14
12
"github.com/icyphox/bild/knotserver/config"
15
13
)
16
14
17
15
func main() {
18
-
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
19
-
defer stop()
16
+
ctx := context.Background()
17
+
// ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
18
+
// defer stop()
20
19
21
20
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
22
21
+2
knotserver/middleware.go
+2
knotserver/middleware.go
···
4
4
"crypto/hmac"
5
5
"crypto/sha256"
6
6
"encoding/hex"
7
+
"log"
7
8
"net/http"
8
9
"time"
9
10
)
···
11
12
func (h *Handle) VerifySignature(next http.Handler) http.Handler {
12
13
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13
14
signature := r.Header.Get("X-Signature")
15
+
log.Println(signature)
14
16
if signature == "" || !h.verifyHMAC(signature, r) {
15
17
writeError(w, "signature verification failed", http.StatusForbidden)
16
18
return
+8
knotserver/routes.go
+8
knotserver/routes.go
···
2
2
3
3
import (
4
4
"compress/gzip"
5
+
"crypto/hmac"
6
+
"crypto/sha256"
7
+
"encoding/hex"
5
8
"encoding/json"
6
9
"errors"
7
10
"fmt"
···
404
407
// }
405
408
406
409
func (h *Handle) Health(w http.ResponseWriter, r *http.Request) {
410
+
log.Println("got health check")
411
+
mac := hmac.New(sha256.New, []byte(h.c.Secret))
412
+
mac.Write([]byte("ok"))
413
+
w.Header().Add("X-Signature", hex.EncodeToString(mac.Sum(nil)))
414
+
407
415
w.Write([]byte("ok"))
408
416
}