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
78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
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
|
|
}
|