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,106 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/owen/vibeproxy/internal/database"
|
||||
"github.com/owen/vibeproxy/internal/models"
|
||||
)
|
||||
|
||||
func (a *API) listAccessLists(w http.ResponseWriter, r *http.Request) {
|
||||
lists, err := database.ListAccessLists(a.db)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, lists)
|
||||
}
|
||||
|
||||
func (a *API) getAccessList(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := pathID(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
l, err := database.GetAccessList(a.db, id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "access list not found")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, l)
|
||||
}
|
||||
|
||||
func (a *API) createAccessList(w http.ResponseWriter, r *http.Request) {
|
||||
var l models.AccessList
|
||||
if !decodeJSON(w, r, &l) {
|
||||
return
|
||||
}
|
||||
if err := validateAccessList(&l); err != nil {
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
l.ID = 0
|
||||
id, err := database.SaveAccessList(a.db, &l)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
a.reload(r)
|
||||
audit(a.db, r, "access_list_changed", l.Name, fmt.Sprintf("id=%d created", id))
|
||||
writeJSON(w, http.StatusCreated, l)
|
||||
}
|
||||
|
||||
func (a *API) updateAccessList(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := pathID(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
var l models.AccessList
|
||||
if !decodeJSON(w, r, &l) {
|
||||
return
|
||||
}
|
||||
l.ID = id
|
||||
if err := validateAccessList(&l); err != nil {
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if _, err := database.SaveAccessList(a.db, &l); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
a.reload(r)
|
||||
audit(a.db, r, "access_list_changed", l.Name, fmt.Sprintf("id=%d updated", id))
|
||||
writeJSON(w, http.StatusOK, l)
|
||||
}
|
||||
|
||||
func (a *API) deleteAccessList(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := pathID(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
if err := database.DeleteAccessList(a.db, id); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
a.reload(r)
|
||||
audit(a.db, r, "access_list_changed", fmt.Sprintf("id=%d", id), "deleted")
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func validateAccessList(l *models.AccessList) error {
|
||||
if l.Name == "" {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
for i, rule := range l.Rules {
|
||||
if rule.Action != models.AccessAllow && rule.Action != models.AccessDeny {
|
||||
return fmt.Errorf("rule %d: action must be allow or deny", i)
|
||||
}
|
||||
if rule.CIDR == "" {
|
||||
return fmt.Errorf("rule %d: CIDR is required", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user