Add test files and enhance logging in various components

- Introduced test files for the blossom and database packages to improve test coverage and ensure functionality.
- Updated logging practices by suppressing unnecessary log outputs during tests to enhance clarity and focus on relevant information.
- Refactored error handling in the `handle-message` and `handle-req` functions to avoid logging expected context cancellation errors during shutdown.
- Bumped version to v0.25.2 to reflect these updates.
This commit is contained in:
2025-11-05 08:15:02 +00:00
parent 1d12099f1c
commit 9d13811f6b
25 changed files with 430 additions and 106 deletions

View File

@@ -139,7 +139,9 @@ func ValidateAuthEvent(
}
eventVerb := string(tTags[0].Value())
if eventVerb != verb {
// If verb is non-empty, verify it matches the event verb
// Empty verb means "don't check the verb" (used by GetPubkeyFromRequest)
if verb != "" && eventVerb != verb {
err = errorf.E(
"authorization event verb '%s' does not match required verb '%s'",
eventVerb, verb,

View File

@@ -163,15 +163,10 @@ func (s *Server) handleHeadBlob(w http.ResponseWriter, r *http.Request) {
// handleUpload handles PUT /upload requests (BUD-02)
func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
// Check ACL
// Get initial pubkey from request (may be updated by auth validation)
pubkey, _ := GetPubkeyFromRequest(r)
remoteAddr := s.getRemoteAddr(r)
if !s.checkACL(pubkey, remoteAddr, "write") {
s.setErrorResponse(w, http.StatusForbidden, "insufficient permissions")
return
}
// Read request body
body, err := io.ReadAll(io.LimitReader(r.Body, s.maxBlobSize+1))
if err != nil {
@@ -189,15 +184,7 @@ func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
sha256Hash := CalculateSHA256(body)
sha256Hex := hex.Enc(sha256Hash)
// Check if blob already exists
exists, err := s.storage.HasBlob(sha256Hash)
if err != nil {
log.E.F("error checking blob existence: %v", err)
s.setErrorResponse(w, http.StatusInternalServerError, "internal server error")
return
}
// Optional authorization validation
// Optional authorization validation (do this BEFORE ACL check)
if r.Header.Get(AuthorizationHeader) != "" {
authEv, err := ValidateAuthEvent(r, "upload", sha256Hash)
if err != nil {
@@ -209,6 +196,20 @@ func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
}
}
// Check ACL (do this AFTER getting pubkey from auth)
if !s.checkACL(pubkey, remoteAddr, "write") {
s.setErrorResponse(w, http.StatusForbidden, "insufficient permissions")
return
}
// Check if blob already exists
exists, err := s.storage.HasBlob(sha256Hash)
if err != nil {
log.E.F("error checking blob existence: %v", err)
s.setErrorResponse(w, http.StatusInternalServerError, "internal server error")
return
}
if len(pubkey) == 0 {
s.setErrorResponse(w, http.StatusUnauthorized, "authorization required")
return
@@ -533,15 +534,10 @@ func (s *Server) handleDeleteBlob(w http.ResponseWriter, r *http.Request) {
// handleMirror handles PUT /mirror requests (BUD-04)
func (s *Server) handleMirror(w http.ResponseWriter, r *http.Request) {
// Check ACL
// Get initial pubkey from request (may be updated by auth validation)
pubkey, _ := GetPubkeyFromRequest(r)
remoteAddr := s.getRemoteAddr(r)
if !s.checkACL(pubkey, remoteAddr, "write") {
s.setErrorResponse(w, http.StatusForbidden, "insufficient permissions")
return
}
// Read request body (JSON with URL)
var req struct {
URL string `json:"url"`
@@ -596,7 +592,7 @@ func (s *Server) handleMirror(w http.ResponseWriter, r *http.Request) {
sha256Hash := CalculateSHA256(body)
sha256Hex := hex.Enc(sha256Hash)
// Optional authorization validation
// Optional authorization validation (do this BEFORE ACL check)
if r.Header.Get(AuthorizationHeader) != "" {
authEv, err := ValidateAuthEvent(r, "upload", sha256Hash)
if err != nil {
@@ -608,6 +604,12 @@ func (s *Server) handleMirror(w http.ResponseWriter, r *http.Request) {
}
}
// Check ACL (do this AFTER getting pubkey from auth)
if !s.checkACL(pubkey, remoteAddr, "write") {
s.setErrorResponse(w, http.StatusForbidden, "insufficient permissions")
return
}
if len(pubkey) == 0 {
s.setErrorResponse(w, http.StatusUnauthorized, "authorization required")
return
@@ -654,15 +656,10 @@ func (s *Server) handleMirror(w http.ResponseWriter, r *http.Request) {
// handleMediaUpload handles PUT /media requests (BUD-05)
func (s *Server) handleMediaUpload(w http.ResponseWriter, r *http.Request) {
// Check ACL
// Get initial pubkey from request (may be updated by auth validation)
pubkey, _ := GetPubkeyFromRequest(r)
remoteAddr := s.getRemoteAddr(r)
if !s.checkACL(pubkey, remoteAddr, "write") {
s.setErrorResponse(w, http.StatusForbidden, "insufficient permissions")
return
}
// Read request body
body, err := io.ReadAll(io.LimitReader(r.Body, s.maxBlobSize+1))
if err != nil {
@@ -679,7 +676,7 @@ func (s *Server) handleMediaUpload(w http.ResponseWriter, r *http.Request) {
// Calculate SHA256 for authorization validation
sha256Hash := CalculateSHA256(body)
// Optional authorization validation
// Optional authorization validation (do this BEFORE ACL check)
if r.Header.Get(AuthorizationHeader) != "" {
authEv, err := ValidateAuthEvent(r, "media", sha256Hash)
if err != nil {
@@ -691,6 +688,12 @@ func (s *Server) handleMediaUpload(w http.ResponseWriter, r *http.Request) {
}
}
// Check ACL (do this AFTER getting pubkey from auth)
if !s.checkACL(pubkey, remoteAddr, "write") {
s.setErrorResponse(w, http.StatusForbidden, "insufficient permissions")
return
}
if len(pubkey) == 0 {
s.setErrorResponse(w, http.StatusUnauthorized, "authorization required")
return

View File

@@ -0,0 +1,31 @@
package blossom
import (
"io"
"os"
"testing"
"lol.mleku.dev"
"lol.mleku.dev/log"
)
func TestMain(m *testing.M) {
// Disable all logging during tests unless explicitly enabled
if os.Getenv("TEST_LOG") == "" {
// Set log level to Off to suppress all logs
lol.SetLogLevel("off")
// Also redirect output to discard
lol.Writer = io.Discard
// Disable all log printers
log.T = lol.GetNullPrinter()
log.D = lol.GetNullPrinter()
log.I = lol.GetNullPrinter()
log.W = lol.GetNullPrinter()
log.E = lol.GetNullPrinter()
log.F = lol.GetNullPrinter()
}
// Run tests
os.Exit(m.Run())
}

View File

@@ -36,15 +36,16 @@ func testSetup(t *testing.T) (*Server, func()) {
t.Fatalf("Failed to create database: %v", err)
}
// Create ACL registry
// Create ACL registry and set to "none" mode for tests
aclRegistry := acl.Registry
aclRegistry.Active.Store("none") // Allow all access for tests
// Create server
cfg := &Config{
BaseURL: "http://localhost:8080",
MaxBlobSize: 100 * 1024 * 1024, // 100MB
BaseURL: "http://localhost:8080",
MaxBlobSize: 100 * 1024 * 1024, // 100MB
AllowedMimeTypes: nil,
RequireAuth: false,
RequireAuth: false,
}
server := NewServer(db, aclRegistry, cfg)