fix versions and turn off challenges port by default
This commit is contained in:
parent
6810c6f86d
commit
b2d6bb7a08
|
@ -68,8 +68,8 @@ func main() {
|
||||||
"port to listen to (default localhost 3000)")
|
"port to listen to (default localhost 3000)")
|
||||||
flag.StringVar(&lnAddr, "listen", "",
|
flag.StringVar(&lnAddr, "listen", "",
|
||||||
"IPv4 or IPv6 bind address + port (instead of --port)")
|
"IPv4 or IPv6 bind address + port (instead of --port)")
|
||||||
flag.StringVar(&challengesPort, "challenges-port", "80",
|
flag.StringVar(&challengesPort, "challenges-port", "",
|
||||||
"port to use to respond to .well-known/acme-challenge tokens")
|
"port to use to respond to .well-known/acme-challenge tokens (should be 80, if used)")
|
||||||
flag.StringVar(&dbURL, "db-url", "postgres://postgres:postgres@localhost:5432/postgres",
|
flag.StringVar(&dbURL, "db-url", "postgres://postgres:postgres@localhost:5432/postgres",
|
||||||
"database (postgres) connection url")
|
"database (postgres) connection url")
|
||||||
flag.StringVar(&secret, "secret", "",
|
flag.StringVar(&secret, "secret", "",
|
||||||
|
@ -161,23 +161,33 @@ func main() {
|
||||||
|
|
||||||
mgmt.Init(store, provider)
|
mgmt.Init(store, provider)
|
||||||
|
|
||||||
go func() {
|
if len(challengesPort) > 0 {
|
||||||
fmt.Println("Listening for ACME challenges on :" + challengesPort)
|
go func() {
|
||||||
r := chi.NewRouter()
|
fmt.Println("Listening for ACME challenges on :" + challengesPort)
|
||||||
r.Get("/version", func(w http.ResponseWriter, r *http.Request) {
|
r := chi.NewRouter()
|
||||||
w.Write([]byte(ver() + "\n"))
|
r.Get("/version", func(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
w.Write([]byte(ver() + "\n"))
|
||||||
r.Get("/api/version", func(w http.ResponseWriter, r *http.Request) {
|
})
|
||||||
w.Write([]byte("TODO (json): " + ver() + "\n"))
|
r.Get("/api/version", func(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
w.Write([]byte("TODO (json): " + ver() + "\n"))
|
||||||
if err := http.ListenAndServe(":"+challengesPort, mgmt.RouteStatic(r)); nil != err {
|
})
|
||||||
log.Fatal(err)
|
if err := http.ListenAndServe(":"+challengesPort, mgmt.RouteStatic(r)); nil != err {
|
||||||
os.Exit(1)
|
log.Fatal(err)
|
||||||
}
|
os.Exit(1)
|
||||||
}()
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Listening on", lnAddr)
|
fmt.Println("Listening on", lnAddr)
|
||||||
fmt.Fprintf(os.Stderr, "failed: %s", http.ListenAndServe(lnAddr, mgmt.RouteAll()))
|
r := chi.NewRouter()
|
||||||
|
r.Get("/version", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte(ver() + "\n"))
|
||||||
|
})
|
||||||
|
r.Get("/api/version", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("TODO (json): " + ver() + "\n"))
|
||||||
|
})
|
||||||
|
mgmt.RouteAll(r)
|
||||||
|
fmt.Fprintf(os.Stderr, "failed: %s", http.ListenAndServe(lnAddr, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
// newNameDotComDNSProvider is for the sake of demoing the tunnel
|
// newNameDotComDNSProvider is for the sake of demoing the tunnel
|
||||||
|
|
|
@ -53,7 +53,7 @@ func getACMEChallenges(w http.ResponseWriter, r *http.Request) {
|
||||||
fsrv.ServeHTTP(w, r)
|
fsrv.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RouteAll() chi.Router {
|
func RouteAll(r chi.Router) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -74,220 +74,219 @@ func RouteAll() chi.Router {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r.Route("/", func(r chi.Router) {
|
||||||
r.Use(middleware.Logger)
|
r.Use(middleware.Logger)
|
||||||
r.Use(middleware.Timeout(15 * time.Second))
|
r.Use(middleware.Timeout(15 * time.Second))
|
||||||
r.Use(middleware.Recoverer)
|
r.Use(middleware.Recoverer)
|
||||||
|
|
||||||
r.Get("/.well-known/acme-challenge/{token}", getACMEChallenges)
|
r.Get("/.well-known/acme-challenge/{token}", getACMEChallenges)
|
||||||
|
|
||||||
r.Route("/api", func(r chi.Router) {
|
r.Route("/api", func(r chi.Router) {
|
||||||
r.Use(func(next http.Handler) http.Handler {
|
r.Use(func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
var tokenString string
|
var tokenString string
|
||||||
if auth := strings.Split(r.Header.Get("Authorization"), " "); len(auth) > 1 {
|
if auth := strings.Split(r.Header.Get("Authorization"), " "); len(auth) > 1 {
|
||||||
// TODO handle Basic auth tokens as well
|
// TODO handle Basic auth tokens as well
|
||||||
tokenString = auth[1]
|
tokenString = auth[1]
|
||||||
}
|
|
||||||
|
|
||||||
//var err2 error = nil
|
|
||||||
tok, err := jwt.ParseWithClaims(
|
|
||||||
tokenString,
|
|
||||||
&MgmtClaims{},
|
|
||||||
func(token *jwt.Token) (interface{}, error) {
|
|
||||||
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)")
|
|
||||||
}
|
|
||||||
auth, err := store.Get(kid)
|
|
||||||
if nil != err {
|
|
||||||
return nil, fmt.Errorf("invalid jwt header 'kid' (key id)")
|
|
||||||
}
|
|
||||||
|
|
||||||
claims := token.Claims.(*MgmtClaims)
|
|
||||||
jti := claims.Id
|
|
||||||
if "" == jti {
|
|
||||||
return nil, fmt.Errorf("missing jwt payload 'jti' (jwt id / nonce)")
|
|
||||||
}
|
|
||||||
iat := claims.IssuedAt
|
|
||||||
if 0 == iat {
|
|
||||||
return nil, fmt.Errorf("missing jwt payload 'iat' (issued at)")
|
|
||||||
}
|
|
||||||
exp := claims.ExpiresAt
|
|
||||||
if 0 == exp {
|
|
||||||
return nil, fmt.Errorf("missing jwt payload 'exp' (expires at)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if "" != claims.Slug {
|
|
||||||
return nil, fmt.Errorf("extra jwt payload 'slug' (unknown)")
|
|
||||||
}
|
|
||||||
claims.Slug = auth.Slug
|
|
||||||
if "" != claims.Subject && auth.Slug != claims.Subject {
|
|
||||||
return nil, fmt.Errorf("invalid jwt payload 'sub' (mismatch)")
|
|
||||||
}
|
|
||||||
claims.Subject = claims.Slug
|
|
||||||
claims.Issuer = DeviceDomain
|
|
||||||
claims.Audience = fmt.Sprintf("wss://%s/ws", RelayDomain)
|
|
||||||
|
|
||||||
/*
|
|
||||||
// a little misdirection there
|
|
||||||
mac := hmac.New(sha256.New, auth.MachinePPID)
|
|
||||||
_ = mac.Write([]byte(auth.SharedKey))
|
|
||||||
_ = mac.Write([]byte(fmt.Sprintf("%d", exp)))
|
|
||||||
return []byte(auth.SharedKey), nil
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fmt.Println("ppid:", auth.MachinePPID)
|
|
||||||
|
|
||||||
return []byte(auth.MachinePPID), nil
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx := r.Context()
|
|
||||||
if nil != 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)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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))
|
//var err2 error = nil
|
||||||
|
tok, err := jwt.ParseWithClaims(
|
||||||
|
tokenString,
|
||||||
|
&MgmtClaims{},
|
||||||
|
func(token *jwt.Token) (interface{}, error) {
|
||||||
|
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)")
|
||||||
|
}
|
||||||
|
auth, err := store.Get(kid)
|
||||||
|
if nil != err {
|
||||||
|
return nil, fmt.Errorf("invalid jwt header 'kid' (key id)")
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := token.Claims.(*MgmtClaims)
|
||||||
|
jti := claims.Id
|
||||||
|
if "" == jti {
|
||||||
|
return nil, fmt.Errorf("missing jwt payload 'jti' (jwt id / nonce)")
|
||||||
|
}
|
||||||
|
iat := claims.IssuedAt
|
||||||
|
if 0 == iat {
|
||||||
|
return nil, fmt.Errorf("missing jwt payload 'iat' (issued at)")
|
||||||
|
}
|
||||||
|
exp := claims.ExpiresAt
|
||||||
|
if 0 == exp {
|
||||||
|
return nil, fmt.Errorf("missing jwt payload 'exp' (expires at)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if "" != claims.Slug {
|
||||||
|
return nil, fmt.Errorf("extra jwt payload 'slug' (unknown)")
|
||||||
|
}
|
||||||
|
claims.Slug = auth.Slug
|
||||||
|
if "" != claims.Subject && auth.Slug != claims.Subject {
|
||||||
|
return nil, fmt.Errorf("invalid jwt payload 'sub' (mismatch)")
|
||||||
|
}
|
||||||
|
claims.Subject = claims.Slug
|
||||||
|
claims.Issuer = DeviceDomain
|
||||||
|
claims.Audience = fmt.Sprintf("wss://%s/ws", RelayDomain)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// a little misdirection there
|
||||||
|
mac := hmac.New(sha256.New, auth.MachinePPID)
|
||||||
|
_ = mac.Write([]byte(auth.SharedKey))
|
||||||
|
_ = mac.Write([]byte(fmt.Sprintf("%d", exp)))
|
||||||
|
return []byte(auth.SharedKey), nil
|
||||||
|
*/
|
||||||
|
|
||||||
|
//fmt.Println("ppid:", auth.MachinePPID)
|
||||||
|
|
||||||
|
return []byte(auth.MachinePPID), nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
if nil != 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
handleDNSRoutes(r)
|
handleDNSRoutes(r)
|
||||||
handleDeviceRoutes(r)
|
handleDeviceRoutes(r)
|
||||||
|
|
||||||
r.Get("/inspect", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/inspect", func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims)
|
claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims)
|
||||||
if !ok {
|
if !ok {
|
||||||
msg := `{"error":"failure to ping: 3", "code":"E_TOKEN"}`
|
msg := `{"error":"failure to ping: 3", "code":"E_TOKEN"}`
|
||||||
fmt.Println("touch no claims", claims)
|
fmt.Println("touch no claims", claims)
|
||||||
http.Error(w, msg+"\n", http.StatusBadRequest)
|
http.Error(w, msg+"\n", http.StatusBadRequest)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte(fmt.Sprintf(
|
|
||||||
`{ "sub": "%s", "aud": "%s", "domains": [ "%s.%s" ], "ports": [] }`+"\n",
|
|
||||||
claims.Subject,
|
|
||||||
claims.Audience,
|
|
||||||
claims.Slug,
|
|
||||||
DeviceDomain,
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
|
|
||||||
r.Route("/register-device", func(r chi.Router) {
|
|
||||||
// r.Use() // must NOT have slug '*'
|
|
||||||
|
|
||||||
r.Post("/{otp}", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
sharedKey := chi.URLParam(r, "otp")
|
|
||||||
original, err := store.Get(sharedKey)
|
|
||||||
if nil != err {
|
|
||||||
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 len(original.MachinePPID) > 0 {
|
|
||||||
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.StatusUnprocessableEntity)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := &authstore.Authorization{}
|
w.Write([]byte(fmt.Sprintf(
|
||||||
decoder := json.NewDecoder(r.Body)
|
`{ "sub": "%s", "aud": "%s", "domains": [ "%s.%s" ], "ports": [] }`+"\n",
|
||||||
err = decoder.Decode(&auth)
|
claims.Subject,
|
||||||
// MachinePPID and PublicKey are required. ID must NOT be set. Slug is ignored.
|
claims.Audience,
|
||||||
epoch := time.Time{}
|
claims.Slug,
|
||||||
auth.SharedKey = sharedKey
|
DeviceDomain,
|
||||||
if nil != err || "" != auth.ID || "" == auth.MachinePPID ||
|
)))
|
||||||
"" == auth.PublicKey || "" == auth.SharedKey ||
|
|
||||||
epoch != auth.CreatedAt || epoch != auth.UpdatedAt || epoch != auth.DeletedAt {
|
|
||||||
msg, _ := json.Marshal(&struct {
|
|
||||||
Error string `json:"error"`
|
|
||||||
}{
|
|
||||||
Error: "expected JSON in the format {\"machine_ppid\":\"\",\"public_key\":\"\"}",
|
|
||||||
})
|
|
||||||
http.Error(w, string(msg), http.StatusUnprocessableEntity)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO hash the PPID and check against the Public Key?
|
|
||||||
pub := authstore.ToPublicKeyString(auth.MachinePPID)
|
|
||||||
if pub != auth.PublicKey {
|
|
||||||
msg, _ := json.Marshal(&struct {
|
|
||||||
Error string `json:"error"`
|
|
||||||
}{
|
|
||||||
Error: "expected `public_key` to be the first 24 bytes of the hash of the `machine_ppid`",
|
|
||||||
})
|
|
||||||
http.Error(w, string(msg), http.StatusUnprocessableEntity)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
original.PublicKey = auth.PublicKey
|
|
||||||
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)", "code":"E_SERVER"}`
|
|
||||||
log.Printf("/api/register-device/\n")
|
|
||||||
log.Println(err)
|
|
||||||
http.Error(w, msg, http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result, _ := json.Marshal(auth)
|
|
||||||
w.Write(result)
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
r.Post("/ping", func(w http.ResponseWriter, r *http.Request) {
|
r.Route("/register-device", func(r chi.Router) {
|
||||||
ctx := r.Context()
|
// r.Use() // must NOT have slug '*'
|
||||||
claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims)
|
|
||||||
if !ok {
|
|
||||||
msg := `{"error":"failure to ping: 1", "code":"E_TOKEN"}`
|
|
||||||
http.Error(w, msg+"\n", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("ping pong??", claims)
|
r.Post("/{otp}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
err := store.Touch(claims.Slug)
|
sharedKey := chi.URLParam(r, "otp")
|
||||||
if nil != err {
|
original, err := store.Get(sharedKey)
|
||||||
fmt.Fprintf(os.Stderr, "touch err %s\n", err)
|
if nil != err {
|
||||||
var msg string
|
msg := `{"error":"not found", "code":"E_NOT_FOUND"}`
|
||||||
if err == authstore.ErrNotFound {
|
log.Printf("/api/register-device/\n")
|
||||||
// if the token is valid, touch should ALWAYS work
|
log.Println(err)
|
||||||
msg = `{"error":"failure to ping: inconsistent database data", "code":"E_SERVER"}`
|
http.Error(w, msg, http.StatusNotFound)
|
||||||
} else {
|
return
|
||||||
msg = `{"error":"failure to ping: 2", "code":"E_SERVER"}`
|
}
|
||||||
|
if len(original.MachinePPID) > 0 {
|
||||||
|
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.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auth := &authstore.Authorization{}
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
err = decoder.Decode(&auth)
|
||||||
|
// MachinePPID and PublicKey are required. ID must NOT be set. Slug is ignored.
|
||||||
|
epoch := time.Time{}
|
||||||
|
auth.SharedKey = sharedKey
|
||||||
|
if nil != err || "" != auth.ID || "" == auth.MachinePPID ||
|
||||||
|
"" == auth.PublicKey || "" == auth.SharedKey ||
|
||||||
|
epoch != auth.CreatedAt || epoch != auth.UpdatedAt || epoch != auth.DeletedAt {
|
||||||
|
msg, _ := json.Marshal(&struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}{
|
||||||
|
Error: "expected JSON in the format {\"machine_ppid\":\"\",\"public_key\":\"\"}",
|
||||||
|
})
|
||||||
|
http.Error(w, string(msg), http.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO hash the PPID and check against the Public Key?
|
||||||
|
pub := authstore.ToPublicKeyString(auth.MachinePPID)
|
||||||
|
if pub != auth.PublicKey {
|
||||||
|
msg, _ := json.Marshal(&struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}{
|
||||||
|
Error: "expected `public_key` to be the first 24 bytes of the hash of the `machine_ppid`",
|
||||||
|
})
|
||||||
|
http.Error(w, string(msg), http.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
original.PublicKey = auth.PublicKey
|
||||||
|
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)", "code":"E_SERVER"}`
|
||||||
|
log.Printf("/api/register-device/\n")
|
||||||
|
log.Println(err)
|
||||||
|
http.Error(w, msg, http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _ := json.Marshal(auth)
|
||||||
|
w.Write(result)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Post("/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims)
|
||||||
|
if !ok {
|
||||||
|
msg := `{"error":"failure to ping: 1", "code":"E_TOKEN"}`
|
||||||
|
http.Error(w, msg+"\n", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
http.Error(w, msg+"\n", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte(`{ "success": true }` + "\n"))
|
fmt.Println("ping pong??", claims)
|
||||||
})
|
err := store.Touch(claims.Slug)
|
||||||
|
if nil != 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
|
||||||
|
}
|
||||||
|
|
||||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
w.Write([]byte(`{ "success": true }` + "\n"))
|
||||||
w.Write([]byte("Hello\n"))
|
})
|
||||||
|
|
||||||
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("Hello\n"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue