···
"github.com/go-chi/chi/v5"
"github.com/icyphox/bild/appview"
···
64
-
func (s *State) GenerateRegistrationKey(w http.ResponseWriter, r *http.Request) {
65
-
session, err := s.Auth.Store.Get(r, appview.SESSION_NAME)
66
-
if err != nil || session.IsNew {
67
-
log.Println("unauthorized attempt to generate registration key")
68
-
http.Error(w, "Forbidden", http.StatusUnauthorized)
68
+
func (s *State) Key(w http.ResponseWriter, r *http.Request) {
70
+
case http.MethodGet:
71
+
// list open registrations under this did
74
+
case http.MethodPost:
75
+
session, err := s.Auth.Store.Get(r, appview.SESSION_NAME)
76
+
if err != nil || session.IsNew {
77
+
log.Println("unauthorized attempt to generate registration key")
78
+
http.Error(w, "Forbidden", http.StatusUnauthorized)
82
+
did := session.Values[appview.SESSION_DID].(string)
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)
92
+
key, err := s.Db.GenerateRegistrationKey(url.Host, did)
96
+
http.Error(w, "unable to register this domain", http.StatusNotAcceptable)
100
+
w.Write([]byte(key))
72
-
did := session.Values[appview.SESSION_DID].(string)
105
+
// create a signed request and check if a node responds to that
107
+
// we should also rate limit these checks to avoid ddosing knotservers
108
+
func (s *State) Check(w http.ResponseWriter, r *http.Request) {
domain := r.FormValue("domain")
http.Error(w, "Invalid form", http.StatusBadRequest)
79
-
key, err := s.Db.GenerateRegistrationKey(domain, did)
115
+
secret, err := s.Db.GetRegistrationKey(domain)
83
-
http.Error(w, "unable to register this domain", http.StatusNotAcceptable)
117
+
log.Printf("no key found for domain %s: %s\n", domain, err)
87
-
w.Write([]byte(key))
121
+
hmac := hmac.New(sha256.New, []byte(secret))
122
+
signature := hex.EncodeToString(hmac.Sum(nil))
91
-
type RegisterRequest struct {
92
-
Domain string `json:"domain"`
93
-
Secret string `json:"secret"`
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)
129
+
log.Println("failed to create ping request for ", url.String())
132
+
pingRequest.Header.Set("X-Signature", signature)
96
-
func (s *State) Register(w http.ResponseWriter, r *http.Request) {
98
-
case http.MethodGet:
99
-
log.Println("unimplemented")
134
+
client := &http.Client{
135
+
Timeout: 5 * time.Second,
137
+
resp, err := client.Do(pingRequest)
139
+
w.Write([]byte("no dice"))
140
+
log.Println("domain was unreachable after 5 seconds")
101
-
case http.MethodPost:
102
-
var req RegisterRequest
103
-
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
104
-
http.Error(w, "invalid request body", http.StatusBadRequest)
108
-
domain := req.Domain
109
-
secret := req.Secret
144
+
if resp.StatusCode != http.StatusOK {
145
+
log.Println("status nok")
146
+
w.Write([]byte("no dice"))
149
+
w.Write([]byte("check success"))
111
-
err := s.Db.Register(domain, secret)
113
-
log.Println("failed to register domain", err)
151
+
// mark as registered
152
+
s.Db.Register(domain)
117
-
log.Printf("Registered domain: %s with secret: %s", domain, secret)
func (s *State) Router() http.Handler {
r.Post("/login", s.Login)
125
-
r.Post("/node/register", s.Register)
126
-
r.Group(func(r chi.Router) {
127
-
r.Use(AuthMiddleware(s))
128
-
r.Post("/node/generate-key", s.GenerateRegistrationKey)
162
+
r.Route("/node", func(r chi.Router) {
163
+
r.Post("/check", s.Check)
165
+
r.Group(func(r chi.Router) {
166
+
r.Use(AuthMiddleware(s))
167
+
r.Post("/key", s.Key)