Files
vibeproxy/internal/api/tokens.go
T
owenandClaude Sonnet 5 ba1f7c4c03 Initial vibeproxy implementation
Self-contained HTTP/HTTPS/TCP/UDP reverse proxy manager written in Go,
with SQLite storage, a Bootstrap 5 admin UI (Go templates, no JS
framework), and a REST API under /api/v1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QTXFrNP1imCW7jtfL5SZrw
2026-08-17 10:28:59 -05:00

78 lines
2.1 KiB
Go

package api
import (
"net/http"
"github.com/owen/vibeproxy/internal/auth"
"github.com/owen/vibeproxy/internal/database"
)
func (a *API) listTokens(w http.ResponseWriter, r *http.Request) {
tokens, err := database.ListAPITokens(a.db)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
// Never expose the stored hash.
type dto struct {
ID int64 `json:"id"`
Name string `json:"name"`
Prefix string `json:"prefix"`
CreatedAt string `json:"created_at"`
LastUsedAt string `json:"last_used_at,omitempty"`
Revoked bool `json:"revoked"`
}
out := make([]dto, 0, len(tokens))
for _, t := range tokens {
d := dto{ID: t.ID, Name: t.Name, Prefix: t.Prefix, CreatedAt: t.CreatedAt.Format("2006-01-02T15:04:05Z"), Revoked: t.RevokedAt != nil}
if t.LastUsedAt != nil {
d.LastUsedAt = t.LastUsedAt.Format("2006-01-02T15:04:05Z")
}
out = append(out, d)
}
writeJSON(w, http.StatusOK, out)
}
func (a *API) createToken(w http.ResponseWriter, r *http.Request) {
var req struct {
Name string `json:"name"`
}
if !decodeJSON(w, r, &req) {
return
}
if req.Name == "" {
writeError(w, http.StatusBadRequest, "name is required")
return
}
plaintext, hash, prefix, err := auth.GenerateAPIToken()
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
id, err := database.CreateAPIToken(a.db, req.Name, hash, prefix)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
audit(a.db, r, "token_created", req.Name, "")
writeJSON(w, http.StatusCreated, map[string]any{
"id": id,
"name": req.Name,
"token": plaintext, // shown once; never retrievable again
})
}
func (a *API) revokeToken(w http.ResponseWriter, r *http.Request) {
id, err := pathID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid id")
return
}
if err := database.RevokeAPIToken(a.db, id); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
audit(a.db, r, "token_revoked", "", "")
w.WriteHeader(http.StatusNoContent)
}