fix CORS headers and a wasm experiment
Some checks failed
Go / build (push) Has been cancelled
Go / release (push) Has been cancelled

This commit is contained in:
2025-11-14 19:15:50 +00:00
parent 9fb976703d
commit 24eef5b5a8
13 changed files with 691 additions and 35 deletions

View File

@@ -17,6 +17,7 @@ import (
"lol.mleku.dev/chk"
"next.orly.dev/app/config"
"next.orly.dev/pkg/acl"
"next.orly.dev/pkg/blossom"
"next.orly.dev/pkg/database"
"next.orly.dev/pkg/encoders/event"
"next.orly.dev/pkg/encoders/filter"
@@ -29,7 +30,6 @@ import (
"next.orly.dev/pkg/protocol/publish"
"next.orly.dev/pkg/spider"
dsync "next.orly.dev/pkg/sync"
blossom "next.orly.dev/pkg/blossom"
)
type Server struct {
@@ -91,19 +91,9 @@ func (s *Server) isIPBlacklisted(remote string) bool {
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Set comprehensive CORS headers for proxy compatibility
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, "+
"X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host, X-Real-IP, "+
"Upgrade, Connection, Sec-WebSocket-Key, Sec-WebSocket-Version, "+
"Sec-WebSocket-Protocol, Sec-WebSocket-Extensions")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Max-Age", "86400")
// Add proxy-friendly headers
w.Header().Set("Vary", "Origin, Access-Control-Request-Method, Access-Control-Request-Headers")
// CORS headers should be handled by the reverse proxy (Caddy/nginx)
// to avoid duplicate headers. If running without a reverse proxy,
// uncomment the CORS configuration below or configure via environment variable.
// Handle preflight OPTIONS requests
if r.Method == "OPTIONS" {
@@ -245,7 +235,9 @@ func (s *Server) UserInterface() {
s.mux.HandleFunc("/api/sprocket/update", s.handleSprocketUpdate)
s.mux.HandleFunc("/api/sprocket/restart", s.handleSprocketRestart)
s.mux.HandleFunc("/api/sprocket/versions", s.handleSprocketVersions)
s.mux.HandleFunc("/api/sprocket/delete-version", s.handleSprocketDeleteVersion)
s.mux.HandleFunc(
"/api/sprocket/delete-version", s.handleSprocketDeleteVersion,
)
s.mux.HandleFunc("/api/sprocket/config", s.handleSprocketConfig)
// NIP-86 management endpoint
s.mux.HandleFunc("/api/nip86", s.handleNIP86Management)
@@ -343,7 +335,9 @@ func (s *Server) handleAuthChallenge(w http.ResponseWriter, r *http.Request) {
jsonData, err := json.Marshal(response)
if chk.E(err) {
http.Error(w, "Error generating challenge", http.StatusInternalServerError)
http.Error(
w, "Error generating challenge", http.StatusInternalServerError,
)
return
}
@@ -561,7 +555,10 @@ func (s *Server) handleExport(w http.ResponseWriter, r *http.Request) {
// Check permissions - require write, admin, or owner level
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr)
if accessLevel != "write" && accessLevel != "admin" && accessLevel != "owner" {
http.Error(w, "Write, admin, or owner permission required", http.StatusForbidden)
http.Error(
w, "Write, admin, or owner permission required",
http.StatusForbidden,
)
return
}
@@ -610,7 +607,9 @@ func (s *Server) handleExport(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/x-ndjson")
w.Header().Set("Content-Disposition", "attachment; filename=\""+filename+"\"")
w.Header().Set(
"Content-Disposition", "attachment; filename=\""+filename+"\"",
)
// Stream export
s.D.Export(s.Ctx, w, pks...)
@@ -725,7 +724,9 @@ func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) {
// Check permissions - require admin or owner level
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr)
if accessLevel != "admin" && accessLevel != "owner" {
http.Error(w, "Admin or owner permission required", http.StatusForbidden)
http.Error(
w, "Admin or owner permission required", http.StatusForbidden,
)
return
}
@@ -785,7 +786,9 @@ func (s *Server) handleSprocketStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
jsonData, err := json.Marshal(status)
if chk.E(err) {
http.Error(w, "Error generating response", http.StatusInternalServerError)
http.Error(
w, "Error generating response", http.StatusInternalServerError,
)
return
}
@@ -826,7 +829,10 @@ func (s *Server) handleSprocketUpdate(w http.ResponseWriter, r *http.Request) {
// Update the sprocket script
if err := s.sprocketManager.UpdateSprocket(string(body)); chk.E(err) {
http.Error(w, fmt.Sprintf("Failed to update sprocket: %v", err), http.StatusInternalServerError)
http.Error(
w, fmt.Sprintf("Failed to update sprocket: %v", err),
http.StatusInternalServerError,
)
return
}
@@ -861,7 +867,10 @@ func (s *Server) handleSprocketRestart(w http.ResponseWriter, r *http.Request) {
// Restart the sprocket script
if err := s.sprocketManager.RestartSprocket(); chk.E(err) {
http.Error(w, fmt.Sprintf("Failed to restart sprocket: %v", err), http.StatusInternalServerError)
http.Error(
w, fmt.Sprintf("Failed to restart sprocket: %v", err),
http.StatusInternalServerError,
)
return
}
@@ -870,7 +879,9 @@ func (s *Server) handleSprocketRestart(w http.ResponseWriter, r *http.Request) {
}
// handleSprocketVersions returns all sprocket script versions
func (s *Server) handleSprocketVersions(w http.ResponseWriter, r *http.Request) {
func (s *Server) handleSprocketVersions(
w http.ResponseWriter, r *http.Request,
) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
@@ -896,14 +907,19 @@ func (s *Server) handleSprocketVersions(w http.ResponseWriter, r *http.Request)
versions, err := s.sprocketManager.GetSprocketVersions()
if chk.E(err) {
http.Error(w, fmt.Sprintf("Failed to get sprocket versions: %v", err), http.StatusInternalServerError)
http.Error(
w, fmt.Sprintf("Failed to get sprocket versions: %v", err),
http.StatusInternalServerError,
)
return
}
w.Header().Set("Content-Type", "application/json")
jsonData, err := json.Marshal(versions)
if chk.E(err) {
http.Error(w, "Error generating response", http.StatusInternalServerError)
http.Error(
w, "Error generating response", http.StatusInternalServerError,
)
return
}
@@ -911,7 +927,9 @@ func (s *Server) handleSprocketVersions(w http.ResponseWriter, r *http.Request)
}
// handleSprocketDeleteVersion deletes a specific sprocket version
func (s *Server) handleSprocketDeleteVersion(w http.ResponseWriter, r *http.Request) {
func (s *Server) handleSprocketDeleteVersion(
w http.ResponseWriter, r *http.Request,
) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
@@ -957,7 +975,10 @@ func (s *Server) handleSprocketDeleteVersion(w http.ResponseWriter, r *http.Requ
// Delete the sprocket version
if err := s.sprocketManager.DeleteSprocketVersion(request.Filename); chk.E(err) {
http.Error(w, fmt.Sprintf("Failed to delete sprocket version: %v", err), http.StatusInternalServerError)
http.Error(
w, fmt.Sprintf("Failed to delete sprocket version: %v", err),
http.StatusInternalServerError,
)
return
}
@@ -982,7 +1003,9 @@ func (s *Server) handleSprocketConfig(w http.ResponseWriter, r *http.Request) {
jsonData, err := json.Marshal(response)
if chk.E(err) {
http.Error(w, "Error generating response", http.StatusInternalServerError)
http.Error(
w, "Error generating response", http.StatusInternalServerError,
)
return
}
@@ -1006,7 +1029,9 @@ func (s *Server) handleACLMode(w http.ResponseWriter, r *http.Request) {
jsonData, err := json.Marshal(response)
if chk.E(err) {
http.Error(w, "Error generating response", http.StatusInternalServerError)
http.Error(
w, "Error generating response", http.StatusInternalServerError,
)
return
}
@@ -1016,7 +1041,9 @@ func (s *Server) handleACLMode(w http.ResponseWriter, r *http.Request) {
// handleSyncCurrent handles requests for the current serial number
func (s *Server) handleSyncCurrent(w http.ResponseWriter, r *http.Request) {
if s.syncManager == nil {
http.Error(w, "Sync manager not initialized", http.StatusServiceUnavailable)
http.Error(
w, "Sync manager not initialized", http.StatusServiceUnavailable,
)
return
}
@@ -1031,7 +1058,9 @@ func (s *Server) handleSyncCurrent(w http.ResponseWriter, r *http.Request) {
// handleSyncEventIDs handles requests for event IDs with their serial numbers
func (s *Server) handleSyncEventIDs(w http.ResponseWriter, r *http.Request) {
if s.syncManager == nil {
http.Error(w, "Sync manager not initialized", http.StatusServiceUnavailable)
http.Error(
w, "Sync manager not initialized", http.StatusServiceUnavailable,
)
return
}
@@ -1044,12 +1073,16 @@ func (s *Server) handleSyncEventIDs(w http.ResponseWriter, r *http.Request) {
}
// validatePeerRequest validates NIP-98 authentication and checks if the requesting peer is authorized
func (s *Server) validatePeerRequest(w http.ResponseWriter, r *http.Request) bool {
func (s *Server) validatePeerRequest(
w http.ResponseWriter, r *http.Request,
) bool {
// Validate NIP-98 authentication
valid, pubkey, err := httpauth.CheckAuth(r)
if err != nil {
log.Printf("NIP-98 auth validation error: %v", err)
http.Error(w, "Authentication validation failed", http.StatusUnauthorized)
http.Error(
w, "Authentication validation failed", http.StatusUnauthorized,
)
return false
}
if !valid {