You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.9 KiB
185 lines
4.9 KiB
package app |
|
|
|
import ( |
|
"encoding/json" |
|
"net/http" |
|
"strconv" |
|
|
|
lol "lol.mleku.dev" |
|
"lol.mleku.dev/chk" |
|
|
|
"git.mleku.dev/mleku/nostr/httpauth" |
|
"next.orly.dev/pkg/acl" |
|
"next.orly.dev/pkg/logbuffer" |
|
) |
|
|
|
// LogsResponse is the response structure for GET /api/logs |
|
type LogsResponse struct { |
|
Logs []logbuffer.LogEntry `json:"logs"` |
|
Total int `json:"total"` |
|
HasMore bool `json:"has_more"` |
|
} |
|
|
|
// LogLevelResponse is the response structure for GET /api/logs/level |
|
type LogLevelResponse struct { |
|
Level string `json:"level"` |
|
} |
|
|
|
// LogLevelRequest is the request structure for POST /api/logs/level |
|
type LogLevelRequest struct { |
|
Level string `json:"level"` |
|
} |
|
|
|
// handleGetLogs handles GET /api/logs |
|
func (s *Server) handleGetLogs(w http.ResponseWriter, r *http.Request) { |
|
if r.Method != http.MethodGet { |
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) |
|
return |
|
} |
|
|
|
// Validate NIP-98 authentication |
|
valid, pubkey, err := httpauth.CheckAuth(r) |
|
if chk.E(err) || !valid { |
|
errorMsg := "NIP-98 authentication validation failed" |
|
if err != nil { |
|
errorMsg = err.Error() |
|
} |
|
http.Error(w, errorMsg, http.StatusUnauthorized) |
|
return |
|
} |
|
|
|
// Check permissions - require owner level only |
|
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr) |
|
if accessLevel != "owner" { |
|
http.Error(w, "Owner permission required", http.StatusForbidden) |
|
return |
|
} |
|
|
|
// Check if log buffer is available |
|
if logbuffer.GlobalBuffer == nil { |
|
http.Error(w, "Log buffer not enabled", http.StatusServiceUnavailable) |
|
return |
|
} |
|
|
|
// Parse query parameters |
|
offset := 0 |
|
limit := 100 |
|
if offsetStr := r.URL.Query().Get("offset"); offsetStr != "" { |
|
if v, err := strconv.Atoi(offsetStr); err == nil && v >= 0 { |
|
offset = v |
|
} |
|
} |
|
if limitStr := r.URL.Query().Get("limit"); limitStr != "" { |
|
if v, err := strconv.Atoi(limitStr); err == nil && v > 0 && v <= 500 { |
|
limit = v |
|
} |
|
} |
|
|
|
// Get logs from buffer |
|
logs := logbuffer.GlobalBuffer.Get(offset, limit) |
|
total := logbuffer.GlobalBuffer.Count() |
|
hasMore := offset+len(logs) < total |
|
|
|
response := LogsResponse{ |
|
Logs: logs, |
|
Total: total, |
|
HasMore: hasMore, |
|
} |
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
json.NewEncoder(w).Encode(response) |
|
} |
|
|
|
// handleClearLogs handles POST /api/logs/clear |
|
func (s *Server) handleClearLogs(w http.ResponseWriter, r *http.Request) { |
|
if r.Method != http.MethodPost { |
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) |
|
return |
|
} |
|
|
|
// Validate NIP-98 authentication |
|
valid, pubkey, err := httpauth.CheckAuth(r) |
|
if chk.E(err) || !valid { |
|
errorMsg := "NIP-98 authentication validation failed" |
|
if err != nil { |
|
errorMsg = err.Error() |
|
} |
|
http.Error(w, errorMsg, http.StatusUnauthorized) |
|
return |
|
} |
|
|
|
// Check permissions - require owner level only |
|
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr) |
|
if accessLevel != "owner" { |
|
http.Error(w, "Owner permission required", http.StatusForbidden) |
|
return |
|
} |
|
|
|
// Check if log buffer is available |
|
if logbuffer.GlobalBuffer == nil { |
|
http.Error(w, "Log buffer not enabled", http.StatusServiceUnavailable) |
|
return |
|
} |
|
|
|
// Clear the buffer |
|
logbuffer.GlobalBuffer.Clear() |
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) |
|
} |
|
|
|
// handleLogLevel handles GET and POST /api/logs/level |
|
func (s *Server) handleLogLevel(w http.ResponseWriter, r *http.Request) { |
|
switch r.Method { |
|
case http.MethodGet: |
|
s.handleGetLogLevel(w, r) |
|
case http.MethodPost: |
|
s.handleSetLogLevel(w, r) |
|
default: |
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) |
|
} |
|
} |
|
|
|
// handleGetLogLevel handles GET /api/logs/level |
|
func (s *Server) handleGetLogLevel(w http.ResponseWriter, r *http.Request) { |
|
// No auth required for reading log level |
|
level := logbuffer.GetCurrentLevel() |
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
json.NewEncoder(w).Encode(LogLevelResponse{Level: level}) |
|
} |
|
|
|
// handleSetLogLevel handles POST /api/logs/level |
|
func (s *Server) handleSetLogLevel(w http.ResponseWriter, r *http.Request) { |
|
// Validate NIP-98 authentication |
|
valid, pubkey, err := httpauth.CheckAuth(r) |
|
if chk.E(err) || !valid { |
|
errorMsg := "NIP-98 authentication validation failed" |
|
if err != nil { |
|
errorMsg = err.Error() |
|
} |
|
http.Error(w, errorMsg, http.StatusUnauthorized) |
|
return |
|
} |
|
|
|
// Check permissions - require owner level only |
|
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr) |
|
if accessLevel != "owner" { |
|
http.Error(w, "Owner permission required", http.StatusForbidden) |
|
return |
|
} |
|
|
|
// Parse request body |
|
var req LogLevelRequest |
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil { |
|
http.Error(w, "Invalid request body", http.StatusBadRequest) |
|
return |
|
} |
|
|
|
// Validate and set log level |
|
level := logbuffer.SetCurrentLevel(req.Level) |
|
lol.SetLogLevel(level) |
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
json.NewEncoder(w).Encode(LogLevelResponse{Level: level}) |
|
}
|
|
|