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
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/models"
|
||||
)
|
||||
|
||||
func CreateAPIToken(db *sql.DB, name, tokenHash, prefix string) (int64, error) {
|
||||
res, err := db.Exec(`INSERT INTO api_tokens (name, token_hash, prefix) VALUES (?, ?, ?)`, name, tokenHash, prefix)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
func ListAPITokens(db *sql.DB) ([]models.APIToken, error) {
|
||||
rows, err := db.Query(`SELECT id, name, token_hash, prefix, created_at, last_used_at, revoked_at FROM api_tokens ORDER BY id DESC`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []models.APIToken
|
||||
for rows.Next() {
|
||||
var t models.APIToken
|
||||
var created string
|
||||
var lastUsed, revoked sql.NullString
|
||||
if err := rows.Scan(&t.ID, &t.Name, &t.TokenHash, &t.Prefix, &created, &lastUsed, &revoked); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.CreatedAt = parseTime(created)
|
||||
if lastUsed.Valid {
|
||||
tt := parseTime(lastUsed.String)
|
||||
t.LastUsedAt = &tt
|
||||
}
|
||||
if revoked.Valid {
|
||||
tt := parseTime(revoked.String)
|
||||
t.RevokedAt = &tt
|
||||
}
|
||||
out = append(out, t)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func GetAPITokenByHash(db *sql.DB, hash string) (*models.APIToken, error) {
|
||||
row := db.QueryRow(`SELECT id, name, token_hash, prefix, created_at, last_used_at, revoked_at FROM api_tokens WHERE token_hash = ?`, hash)
|
||||
var t models.APIToken
|
||||
var created string
|
||||
var lastUsed, revoked sql.NullString
|
||||
if err := row.Scan(&t.ID, &t.Name, &t.TokenHash, &t.Prefix, &created, &lastUsed, &revoked); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
t.CreatedAt = parseTime(created)
|
||||
if lastUsed.Valid {
|
||||
tt := parseTime(lastUsed.String)
|
||||
t.LastUsedAt = &tt
|
||||
}
|
||||
if revoked.Valid {
|
||||
tt := parseTime(revoked.String)
|
||||
t.RevokedAt = &tt
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func TouchAPIToken(db *sql.DB, id int64) error {
|
||||
_, err := db.Exec(`UPDATE api_tokens SET last_used_at = strftime('%Y-%m-%dT%H:%M:%fZ','now') WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func RevokeAPIToken(db *sql.DB, id int64) error {
|
||||
_, err := db.Exec(`UPDATE api_tokens SET revoked_at = strftime('%Y-%m-%dT%H:%M:%fZ','now') WHERE id = ? AND revoked_at IS NULL`, id)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user