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,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/app"
|
||||
"github.com/owen/vibeproxy/internal/auth"
|
||||
"github.com/owen/vibeproxy/internal/config"
|
||||
"github.com/owen/vibeproxy/internal/database"
|
||||
)
|
||||
|
||||
func newAdminCmd() *cobra.Command {
|
||||
root := &cobra.Command{Use: "admin", Short: "Administrator account utilities"}
|
||||
root.AddCommand(newAdminResetPasswordCmd())
|
||||
return root
|
||||
}
|
||||
|
||||
func newAdminResetPasswordCmd() *cobra.Command {
|
||||
cfg := config.Default()
|
||||
cmd := &cobra.Command{
|
||||
Use: "reset-password",
|
||||
Short: "Generate a new random password for the admin account",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
a, err := app.Open(cfg, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
|
||||
password, err := auth.GenerateRandomPassword()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash, err := auth.HashPassword(password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := database.UpdateUserPassword(a.DB, "admin", hash, true); err != nil {
|
||||
return err
|
||||
}
|
||||
database.InsertAuditLog(a.DB, "cli", "password_changed", "admin", "password reset via CLI")
|
||||
fmt.Println("New admin password:")
|
||||
fmt.Println(password)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
fs := flag.NewFlagSet("admin-reset-password", flag.ContinueOnError)
|
||||
config.RegisterFlags(fs, &cfg)
|
||||
cmd.Flags().AddGoFlagSet(fs)
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/app"
|
||||
"github.com/owen/vibeproxy/internal/config"
|
||||
)
|
||||
|
||||
func newCertificatesCmd() *cobra.Command {
|
||||
root := &cobra.Command{Use: "certificates", Short: "Certificate utilities"}
|
||||
root.AddCommand(newCertificatesRenewCmd())
|
||||
return root
|
||||
}
|
||||
|
||||
func newCertificatesRenewCmd() *cobra.Command {
|
||||
cfg := config.Default()
|
||||
cmd := &cobra.Command{
|
||||
Use: "renew",
|
||||
Short: "Renew any Let's Encrypt certificates within their renewal window",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
a, err := app.Open(cfg, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
|
||||
settings := a.Store.Current().Settings
|
||||
n, err := a.Certs.RenewDue(context.Background(), settings.ACMERenewalWindowDays, settings.ACMEEmail, settings.ACMEStaging)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("renewed %d certificate(s)\n", n)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
fs := flag.NewFlagSet("certificates-renew", flag.ContinueOnError)
|
||||
config.RegisterFlags(fs, &cfg)
|
||||
cmd.Flags().AddGoFlagSet(fs)
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/app"
|
||||
"github.com/owen/vibeproxy/internal/config"
|
||||
)
|
||||
|
||||
func newConfigCmd() *cobra.Command {
|
||||
root := &cobra.Command{Use: "config", Short: "Configuration utilities"}
|
||||
root.AddCommand(newConfigCheckCmd())
|
||||
return root
|
||||
}
|
||||
|
||||
func newConfigCheckCmd() *cobra.Command {
|
||||
cfg := config.Default()
|
||||
cmd := &cobra.Command{
|
||||
Use: "check",
|
||||
Short: "Validate configuration and database migrations without starting listeners",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
a, err := app.Open(cfg, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("configuration check failed: %w", err)
|
||||
}
|
||||
defer a.Close()
|
||||
fmt.Println("OK: database opens, migrations applied, and initial configuration loaded successfully.")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
fs := flag.NewFlagSet("config-check", flag.ContinueOnError)
|
||||
config.RegisterFlags(fs, &cfg)
|
||||
cmd.Flags().AddGoFlagSet(fs)
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/app"
|
||||
"github.com/owen/vibeproxy/internal/backup"
|
||||
"github.com/owen/vibeproxy/internal/config"
|
||||
)
|
||||
|
||||
func newDatabaseCmd() *cobra.Command {
|
||||
root := &cobra.Command{Use: "database", Short: "Database utilities"}
|
||||
root.AddCommand(newDatabaseBackupCmd(), newDatabaseMigrateCmd())
|
||||
return root
|
||||
}
|
||||
|
||||
func newDatabaseBackupCmd() *cobra.Command {
|
||||
cfg := config.Default()
|
||||
var outDir string
|
||||
cmd := &cobra.Command{
|
||||
Use: "backup",
|
||||
Short: "Create an on-demand SQLite backup",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
a, err := app.Open(cfg, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
if outDir == "" {
|
||||
outDir = cfg.DataDir + "/backups"
|
||||
}
|
||||
path, err := backup.Run(a.DB, outDir, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("backup written to " + path)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
fs := flag.NewFlagSet("database-backup", flag.ContinueOnError)
|
||||
config.RegisterFlags(fs, &cfg)
|
||||
cmd.Flags().AddGoFlagSet(fs)
|
||||
cmd.Flags().StringVar(&outDir, "out", "", "backup output directory (default: <data-dir>/backups)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newDatabaseMigrateCmd() *cobra.Command {
|
||||
cfg := config.Default()
|
||||
cmd := &cobra.Command{
|
||||
Use: "migrate",
|
||||
Short: "Apply any pending database migrations",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
a, err := app.Open(cfg, logger) // Open() runs migrations
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
fmt.Println("database is up to date")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
fs := flag.NewFlagSet("database-migrate", flag.ContinueOnError)
|
||||
config.RegisterFlags(fs, &cfg)
|
||||
cmd.Flags().AddGoFlagSet(fs)
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Command vibeproxy is a self-contained HTTP/HTTPS/TCP/UDP reverse proxy
|
||||
// manager with a Bootstrap 5 web UI, SQLite storage, and a REST API.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var logger = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
||||
|
||||
func main() {
|
||||
root := &cobra.Command{
|
||||
Use: "vibeproxy",
|
||||
Short: "vibeproxy is a self-contained reverse proxy manager",
|
||||
}
|
||||
root.AddCommand(
|
||||
newServeCmd(),
|
||||
newVersionCmd(),
|
||||
newConfigCmd(),
|
||||
newAdminCmd(),
|
||||
newDatabaseCmd(),
|
||||
newCertificatesCmd(),
|
||||
)
|
||||
if err := root.Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/app"
|
||||
"github.com/owen/vibeproxy/internal/config"
|
||||
)
|
||||
|
||||
func newServeCmd() *cobra.Command {
|
||||
cfg := config.Default()
|
||||
cmd := &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "Run vibeproxy: HTTP/HTTPS/TCP/UDP proxying, web UI, and REST API",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
a, err := app.Open(cfg, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Close()
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
logger.Info("vibeproxy starting",
|
||||
"http", cfg.HTTPAddr, "https", cfg.HTTPSAddr, "admin", cfg.AdminAddr)
|
||||
return a.Run(ctx)
|
||||
},
|
||||
}
|
||||
fs := flag.NewFlagSet("serve", flag.ContinueOnError)
|
||||
config.RegisterFlags(fs, &cfg)
|
||||
cmd.Flags().AddGoFlagSet(fs)
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Version is set via -ldflags "-X main.Version=..." at release build time.
|
||||
var Version = "dev"
|
||||
|
||||
func newVersionCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the vibeproxy version",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("vibeproxy " + Version)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user