diff --git a/cmd/mgmt/acmeroutes.go b/cmd/mgmt/acmeroutes.go index 4e1e959..bda5e02 100644 --- a/cmd/mgmt/acmeroutes.go +++ b/cmd/mgmt/acmeroutes.go @@ -39,7 +39,7 @@ func handleDNSRoutes(r chi.Router) { ctx := r.Context() claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims) if !ok || !strings.HasPrefix(domain+".", claims.Slug) { - msg := `{ "error": "invalid domain" }` + msg := `{ "error": "invalid domain", "code":"E_BAD_REQUEST"}` http.Error(w, msg+"\n", http.StatusUnprocessableEntity) return } @@ -50,7 +50,7 @@ func handleDNSRoutes(r chi.Router) { decoder := json.NewDecoder(r.Body) err := decoder.Decode(&ch) if nil != err || "" == ch.Token || "" == ch.KeyAuth { - msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}"}` + msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}", "code":"E_BAD_REQUEST"}` http.Error(w, msg, http.StatusUnprocessableEntity) return } @@ -65,7 +65,7 @@ func handleDNSRoutes(r chi.Router) { err = <-ch.error if nil != err || "" == ch.Token || "" == ch.KeyAuth { fmt.Println("presenter err", err, ch.Token, ch.KeyAuth) - msg := `{"error":"ACME dns-01 error"}` + msg := `{"error":"ACME dns-01 error", "code":"E_SERVER"}` http.Error(w, msg, http.StatusUnprocessableEntity) return } @@ -88,7 +88,7 @@ func handleDNSRoutes(r chi.Router) { cleanups <- &ch err := <-ch.error if nil != err || "" == ch.Token || "" == ch.KeyAuth { - msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}"}` + msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}", "code":"E_BAD_REQUEST"}` http.Error(w, msg, http.StatusUnprocessableEntity) return } diff --git a/cmd/mgmt/devices.go b/cmd/mgmt/devices.go index d67819e..36b3bab 100644 --- a/cmd/mgmt/devices.go +++ b/cmd/mgmt/devices.go @@ -22,7 +22,7 @@ func handleDeviceRoutes(r chi.Router) { ctx := r.Context() claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims) if !ok || "*" != claims.Slug { - msg := `{"error":"missing or invalid authorization token"}` + msg := `{"error":"missing or invalid authorization token", "code":"E_TOKEN"}` http.Error(w, msg+"\n", http.StatusUnprocessableEntity) return } @@ -58,7 +58,7 @@ func handleDeviceRoutes(r chi.Router) { auth.SharedKey = base64.RawURLEncoding.EncodeToString(rnd) } if len(auth.SharedKey) < 20 { - msg := `{"error":"shared_key must be >= 16 bytes"}` + msg := `{"error":"shared_key must be >= 16 bytes", "code":"E_BAD_REQUEST"}` http.Error(w, string(msg), http.StatusUnprocessableEntity) return } @@ -71,16 +71,16 @@ func handleDeviceRoutes(r chi.Router) { auth.PublicKey = auth.PublicKey[:24] } if pub != auth.PublicKey { - msg := `{"error":"public_key must be the first 24 bytes of the base64-encoded hash of the shared_key"}` + msg := `{"error":"public_key must be the first 24 bytes of the base64-encoded hash of the shared_key", "code":"E_BAD_REQUEST"}` http.Error(w, msg+"\n", http.StatusUnprocessableEntity) return } err = store.Add(auth) if nil != err { - msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)"}` + msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_BAD_SERVER"}` if authstore.ErrExists == err { - msg = fmt.Sprintf(`{ "error": "%s" }`, err.Error()) + msg = fmt.Sprintf(`{ "error": "%s", "code":"E_EXIST"}`, err.Error()) } log.Printf("/api/devices/\n") log.Println(err) @@ -101,7 +101,7 @@ func handleDeviceRoutes(r chi.Router) { things, err = store.Active() } if nil != err { - msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)"}` + msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_SERVER"}` log.Printf("/api/devices/\n") log.Println(err) http.Error(w, msg, http.StatusInternalServerError) @@ -130,7 +130,12 @@ func handleDeviceRoutes(r chi.Router) { // TODO store should be concurrency-safe auth, err := store.Get(slug) if nil != err { - msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)"}` + var msg string + if err == authstore.ErrNotFound { + msg = `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_NOT_FOUND"}` + } else { + msg = `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_SERVER"}` + } log.Printf("/api/devices/%s\n", slug) log.Println(err) http.Error(w, msg, http.StatusInternalServerError) @@ -152,14 +157,19 @@ func handleDeviceRoutes(r chi.Router) { slug := chi.URLParam(r, "slug") auth, err := store.Get(slug) if nil == auth { - msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)"}` + var msg string + if err == authstore.ErrNotFound { + msg = `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_NOT_FOUND"}` + } else { + msg = `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_SERVER"}` + } log.Printf("/api/devices/%s\n", slug) log.Println(err) http.Error(w, msg, http.StatusInternalServerError) return } if err := store.Delete(auth); nil != err { - msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)"}` + msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_SERVER"}` log.Printf("/api/devices/%s\n", slug) log.Println(err) http.Error(w, msg, http.StatusInternalServerError) diff --git a/cmd/mgmt/route.go b/cmd/mgmt/route.go index 447ab65..11a67d8 100644 --- a/cmd/mgmt/route.go +++ b/cmd/mgmt/route.go @@ -6,9 +6,11 @@ import ( "fmt" "log" "net/http" + "os" "strings" "time" + "git.rootprojects.org/root/telebit/dbg" "git.rootprojects.org/root/telebit/mgmt/authstore" "github.com/dgrijalva/jwt-go" "github.com/go-chi/chi" @@ -65,7 +67,9 @@ func routeAll() chi.Router { tokenString, &MgmtClaims{}, func(token *jwt.Token) (interface{}, error) { - fmt.Println("parsed jwt", token) + if dbg.Debug { + fmt.Println("parsed jwt", token) + } kid, ok := token.Header["kid"].(string) if !ok { return nil, fmt.Errorf("missing jwt header 'kid' (key id)") @@ -115,20 +119,21 @@ func routeAll() chi.Router { ) ctx := r.Context() - if nil != err { - fmt.Println("auth err", err) - ctx = context.WithValue(ctx, MWKey("error"), err) - } if nil != tok { - fmt.Println("any auth?", tok) if tok.Valid { ctx = context.WithValue(ctx, MWKey("token"), tok) ctx = context.WithValue(ctx, MWKey("claims"), tok.Claims) ctx = context.WithValue(ctx, MWKey("valid"), true) + fmt.Println("[auth] Token is fully valid:") + fmt.Println(ctx.Value(MWKey("claims"))) + } else { + fmt.Println("[auth] Token was parsed, but NOT valid:", tok) } } - fmt.Println("Good Auth?") - fmt.Println(ctx.Value(MWKey("claims"))) + if nil != err { + fmt.Println("[auth] Token is NOT valid due to error:", err) + ctx = context.WithValue(ctx, MWKey("error"), err) + } next.ServeHTTP(w, r.WithContext(ctx)) }) @@ -141,7 +146,7 @@ func routeAll() chi.Router { ctx := r.Context() claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims) if !ok { - msg := `{"error":"failure to ping: 3"}` + msg := `{"error":"failure to ping: 3", "code":"E_TOKEN"}` fmt.Println("touch no claims", claims) http.Error(w, msg+"\n", http.StatusBadRequest) return @@ -163,17 +168,17 @@ func routeAll() chi.Router { sharedKey := chi.URLParam(r, "otp") original, err := store.Get(sharedKey) if nil != err { - msg := `{"error":"not found"}` + msg := `{"error":"not found", "code":"E_NOT_FOUND"}` log.Printf("/api/register-device/\n") log.Println(err) http.Error(w, msg, http.StatusNotFound) return } if "" != original.MachinePPID { - msg := `{"error":"the presented key has already been used"}` + msg := `{"error":"the presented key has already been used", "code":"E_EXIST"}` log.Printf("/api/register-device/\n") log.Println(err) - http.Error(w, msg, http.StatusInternalServerError) + http.Error(w, msg, http.StatusUnprocessableEntity) return } @@ -210,7 +215,7 @@ func routeAll() chi.Router { original.MachinePPID = auth.MachinePPID err = store.Set(original) if nil != err { - msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)"}` + msg := `{"error":"not really sure what happened, but it didn't go well (check the logs)", "code":"E_SERVER"}` log.Printf("/api/register-device/\n") log.Println(err) http.Error(w, msg, http.StatusInternalServerError) @@ -226,8 +231,7 @@ func routeAll() chi.Router { ctx := r.Context() claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims) if !ok { - msg := `{"error":"failure to ping: 1"}` - fmt.Println("touch no claims", claims) + msg := `{"error":"failure to ping: 1", "code":"E_TOKEN"}` http.Error(w, msg+"\n", http.StatusBadRequest) return } @@ -235,8 +239,14 @@ func routeAll() chi.Router { fmt.Println("ping pong??", claims) err := store.Touch(claims.Slug) if nil != err { - msg := `{"error":"failure to ping: 2"}` - fmt.Println("touch err", err) + fmt.Fprintf(os.Stderr, "touch err %s\n", err) + var msg string + if err == authstore.ErrNotFound { + // if the token is valid, touch should ALWAYS work + msg = `{"error":"failure to ping: inconsistent database data", "code":"E_SERVER"}` + } else { + msg = `{"error":"failure to ping: 2", "code":"E_SERVER"}` + } http.Error(w, msg+"\n", http.StatusBadRequest) return } diff --git a/mgmt/authstore/authstore.go b/mgmt/authstore/authstore.go index d4a3080..4cee403 100644 --- a/mgmt/authstore/authstore.go +++ b/mgmt/authstore/authstore.go @@ -14,6 +14,7 @@ import ( ) var ErrExists = errors.New("token already exists") +var ErrNotFound = errors.New("record not found") type Authorization struct { ID string `db:"id,omitempty" json:"-"` diff --git a/mgmt/authstore/postgresql.go b/mgmt/authstore/postgresql.go index 57b9912..243dbf1 100644 --- a/mgmt/authstore/postgresql.go +++ b/mgmt/authstore/postgresql.go @@ -153,9 +153,9 @@ func (s *PGStore) Touch(pub string) error { if nil != err { return err } - // PostgreSQL does support RowsAffected() + // PostgreSQL is one of the databases for which RowsAffected() IS supported if count, _ := row.RowsAffected(); count != 1 { - return fmt.Errorf("record was not updated") + return ErrNotFound } return nil }