+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
"crypto/hmac"
5
"crypto/sha256"
6
"encoding/hex"
7
"log"
8
"net/http"
9
-
"net/url"
10
"time"
11
12
"github.com/go-chi/chi/v5"
···
83
84
// check if domain is valid url, and strip extra bits down to just host
85
domain := r.FormValue("domain")
86
-
url, err := url.Parse(domain)
87
if domain == "" || err != nil {
88
http.Error(w, "Invalid form", http.StatusBadRequest)
89
return
90
}
91
92
-
key, err := s.Db.GenerateRegistrationKey(url.Host, did)
93
94
if err != nil {
95
log.Println(err)
···
112
return
113
}
114
115
secret, err := s.Db.GetRegistrationKey(domain)
116
if err != nil {
117
log.Printf("no key found for domain %s: %s\n", domain, err)
118
return
119
}
120
-
121
-
hmac := hmac.New(sha256.New, []byte(secret))
122
-
signature := hex.EncodeToString(hmac.Sum(nil))
123
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)
128
if err != nil {
129
-
log.Println("failed to create ping request for ", url.String())
130
return
131
}
132
-
pingRequest.Header.Set("X-Signature", signature)
133
134
client := &http.Client{
135
Timeout: 5 * time.Second,
···
142
}
143
144
if resp.StatusCode != http.StatusOK {
145
-
log.Println("status nok")
146
w.Write([]byte("no dice"))
147
return
148
}
149
w.Write([]byte("check success"))
150
151
// mark as registered
152
s.Db.Register(domain)
153
154
return
155
}
156
157
func (s *State) Router() http.Handler {
···
4
"crypto/hmac"
5
"crypto/sha256"
6
"encoding/hex"
7
+
"fmt"
8
"log"
9
"net/http"
10
"time"
11
12
"github.com/go-chi/chi/v5"
···
83
84
// check if domain is valid url, and strip extra bits down to just host
85
domain := r.FormValue("domain")
86
if domain == "" || err != nil {
87
+
log.Println(err)
88
http.Error(w, "Invalid form", http.StatusBadRequest)
89
return
90
}
91
92
+
key, err := s.Db.GenerateRegistrationKey(domain, did)
93
94
if err != nil {
95
log.Println(err)
···
112
return
113
}
114
115
+
log.Println("checking ", domain)
116
+
117
secret, err := s.Db.GetRegistrationKey(domain)
118
if err != nil {
119
log.Printf("no key found for domain %s: %s\n", domain, err)
120
return
121
}
122
+
log.Println("has secret ", secret)
123
124
// make a request do the knotserver with an empty body and above signature
125
+
url := fmt.Sprintf("http://%s/internal/health", domain)
126
+
127
+
pingRequest, err := buildPingRequest(url, secret)
128
if err != nil {
129
+
log.Println("failed to build ping request", err)
130
return
131
}
132
133
client := &http.Client{
134
Timeout: 5 * time.Second,
···
141
}
142
143
if resp.StatusCode != http.StatusOK {
144
+
log.Println("status nok", resp.StatusCode)
145
w.Write([]byte("no dice"))
146
return
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
+
164
w.Write([]byte("check success"))
165
166
// mark as registered
167
s.Db.Register(domain)
168
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
188
}
189
190
func (s *State) Router() http.Handler {
+3
-4
cmd/knotserver/main.go
+3
-4
cmd/knotserver/main.go
···
7
"log/slog"
8
"net/http"
9
"os"
10
-
"os/signal"
11
-
"syscall"
12
13
"github.com/icyphox/bild/knotserver"
14
"github.com/icyphox/bild/knotserver/config"
15
)
16
17
func main() {
18
-
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
19
-
defer stop()
20
21
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
22
···
7
"log/slog"
8
"net/http"
9
"os"
10
11
"github.com/icyphox/bild/knotserver"
12
"github.com/icyphox/bild/knotserver/config"
13
)
14
15
func main() {
16
+
ctx := context.Background()
17
+
// ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
18
+
// defer stop()
19
20
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
21
+2
knotserver/middleware.go
+2
knotserver/middleware.go
···
4
"crypto/hmac"
5
"crypto/sha256"
6
"encoding/hex"
7
"net/http"
8
"time"
9
)
···
11
func (h *Handle) VerifySignature(next http.Handler) http.Handler {
12
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13
signature := r.Header.Get("X-Signature")
14
if signature == "" || !h.verifyHMAC(signature, r) {
15
writeError(w, "signature verification failed", http.StatusForbidden)
16
return
···
4
"crypto/hmac"
5
"crypto/sha256"
6
"encoding/hex"
7
+
"log"
8
"net/http"
9
"time"
10
)
···
12
func (h *Handle) VerifySignature(next http.Handler) http.Handler {
13
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14
signature := r.Header.Get("X-Signature")
15
+
log.Println(signature)
16
if signature == "" || !h.verifyHMAC(signature, r) {
17
writeError(w, "signature verification failed", http.StatusForbidden)
18
return
+8
knotserver/routes.go
+8
knotserver/routes.go
···
2
3
import (
4
"compress/gzip"
5
+
"crypto/hmac"
6
+
"crypto/sha256"
7
+
"encoding/hex"
8
"encoding/json"
9
"errors"
10
"fmt"
···
407
// }
408
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
+
415
w.Write([]byte("ok"))
416
}