This commit is contained in:
David Schroeder
2026-07-25 15:18:21 -05:00
parent 6594aece09
commit 1dcfc56844
11 changed files with 369 additions and 164 deletions
+79 -14
View File
@@ -11,6 +11,10 @@ import (
)
func (s *Server) handlePortal(w http.ResponseWriter, r *http.Request) {
if hasAuditQuery(r) {
http.Redirect(w, r, "/portal/audit?"+r.URL.RawQuery, http.StatusSeeOther)
return
}
tech, err := s.currentTechnician(r)
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
@@ -31,13 +35,7 @@ func (s *Server) handlePortal(w http.ResponseWriter, r *http.Request) {
http.Error(w, "unable to list installer actions", http.StatusInternalServerError)
return
}
auditFilter := auditFiltersFromRequest(r)
auditEventTypes, err := s.listAuditEventTypes(r)
if err != nil {
http.Error(w, "unable to list audit event types", http.StatusInternalServerError)
return
}
auditEvents, err := s.listAuditEvents(r, auditFilter)
auditEvents, err := s.listAuditEvents(r, auditFilters{TimeRange: "all"}, 15)
if err != nil {
http.Error(w, "unable to list audit events", http.StatusInternalServerError)
return
@@ -48,14 +46,80 @@ func (s *Server) handlePortal(w http.ResponseWriter, r *http.Request) {
CSRFToken: tech.CSRFToken,
Authorizations: authorizations,
AuditEvents: auditEvents,
AuditFilters: auditFilter,
AuditEventTypes: auditEventTypes,
Packages: packages,
Actions: actions,
NewCode: r.URL.Query().Get("code"),
DefaultHostLimit: s.cfg.DefaultHostLimit,
DefaultDuration: strconv.Itoa(int(s.cfg.DefaultDuration.Hours())),
Notice: r.URL.Query().Get("notice"),
CurrentView: "codes",
})
}
func hasAuditQuery(r *http.Request) bool {
query := r.URL.Query()
for _, field := range []string{
"audit_range",
"audit_event",
"audit_actor",
"audit_hostname",
"audit_package",
"audit_ip",
"audit_details",
} {
if query.Has(field) {
return true
}
}
return false
}
func (s *Server) handlePackagesPortal(w http.ResponseWriter, r *http.Request) {
tech, err := s.currentTechnician(r)
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
packages, err := s.listPackages(r)
if err != nil {
http.Error(w, "unable to list packages", http.StatusInternalServerError)
return
}
s.render(w, "packages.html", pageData{
Title: "Protected Packages",
Technician: tech,
CSRFToken: tech.CSRFToken,
Packages: packages,
Notice: r.URL.Query().Get("notice"),
CurrentView: "packages",
})
}
func (s *Server) handleAuditPortal(w http.ResponseWriter, r *http.Request) {
tech, err := s.currentTechnician(r)
if err != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
auditFilter := auditFiltersFromRequest(r)
auditEventTypes, err := s.listAuditEventTypes(r)
if err != nil {
http.Error(w, "unable to list audit event types", http.StatusInternalServerError)
return
}
auditEvents, err := s.listAuditEvents(r, auditFilter, 250)
if err != nil {
http.Error(w, "unable to list audit events", http.StatusInternalServerError)
return
}
s.render(w, "audit.html", pageData{
Title: "Audit Trail",
Technician: tech,
CSRFToken: tech.CSRFToken,
AuditEvents: auditEvents,
AuditFilters: auditFilter,
AuditEventTypes: auditEventTypes,
CurrentView: "audit",
})
}
@@ -133,7 +197,7 @@ func (s *Server) listAuditEventTypes(r *http.Request) ([]string, error) {
return eventTypes, rows.Err()
}
func auditQuery(filters auditFilters) (string, []any) {
func auditQuery(filters auditFilters, limit int) (string, []any) {
query := `SELECT event_type, actor, hostname, package_slug, source_ip, details, created_at
FROM audit_events
WHERE 1 = 1`
@@ -168,12 +232,13 @@ func auditQuery(filters auditFilters) (string, []any) {
query += " AND LOCATE(?, " + filter.column + ") > 0"
arguments = append(arguments, filter.value)
}
query += " ORDER BY created_at DESC LIMIT 250"
query += " ORDER BY created_at DESC LIMIT ?"
arguments = append(arguments, limit)
return query, arguments
}
func (s *Server) listAuditEvents(r *http.Request, filters auditFilters) ([]auditRecord, error) {
query, arguments := auditQuery(filters)
func (s *Server) listAuditEvents(r *http.Request, filters auditFilters, limit int) ([]auditRecord, error) {
query, arguments := auditQuery(filters, limit)
rows, err := s.db.QueryContext(
r.Context(),
query,
@@ -469,7 +534,7 @@ func (s *Server) handleUpsertPackage(w http.ResponseWriter, r *http.Request) {
}
_ = s.audit(r.Context(), "package_saved", tech.Login, nil, "", values["slug"], s.clientIP(r),
fmt.Sprintf("version=%s enabled=%t", values["package_version"], enabled))
http.Redirect(w, r, "/portal?notice=Package+saved", http.StatusSeeOther)
http.Redirect(w, r, "/portal/packages?notice=Package+saved", http.StatusSeeOther)
}
func (s *Server) savePackage(