Simplified the database layer by removing custom interface wrappers and using standard library *sql.DB and *sql.Tx types directly. Changes: - Removed DBConnection and DBTransaction interfaces from database.go - Removed NewDBConnection() wrapper function - Updated TokenGenerator to use *sql.DB instead of DBConnection - Updated all validation and revocation methods to accept *sql.Tx - Updated TableManager to work with *sql.DB directly - Updated all tests to use db.Begin() instead of custom wrappers - Fixed GeneratorConfig.DB field (was DBConn) - Updated documentation in doc.go with correct API usage Benefits: - Simpler API with fewer abstractions - Works directly with database/sql standard library - Compatible with GORM (via gormDB.DB()) and Bun (share same *sql.DB) - Easier to understand and maintain - No unnecessary wrapper layers Breaking changes: - GeneratorConfig.DBConn renamed to GeneratorConfig.DB - Removed NewDBConnection() function - pass *sql.DB directly - ValidateAccess/ValidateRefresh now accept *sql.Tx instead of DBTransaction - Token.Revoke/CheckNotRevoked now accept *sql.Tx instead of DBTransaction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
214 lines
5.7 KiB
Go
214 lines
5.7 KiB
Go
package hws_test
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.haelnorr.com/h/golib/hws"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func Test_SafeFileServer(t *testing.T) {
|
|
t.Run("Nil filesystem returns error", func(t *testing.T) {
|
|
handler, err := hws.SafeFileServer(nil)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, handler)
|
|
assert.Contains(t, err.Error(), "No file system provided")
|
|
})
|
|
|
|
t.Run("Valid filesystem returns handler", func(t *testing.T) {
|
|
fs := http.Dir(".")
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, handler)
|
|
})
|
|
|
|
t.Run("Directory listing is blocked", func(t *testing.T) {
|
|
// Create a temporary directory
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create some test files
|
|
testFile := filepath.Join(tmpDir, "test.txt")
|
|
err := os.WriteFile(testFile, []byte("test content"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
// Try to access the directory
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
// Should return 404 for directory listing
|
|
assert.Equal(t, http.StatusNotFound, rr.Code)
|
|
})
|
|
|
|
t.Run("Individual files are accessible", func(t *testing.T) {
|
|
// Create a temporary directory
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a test file
|
|
testFile := filepath.Join(tmpDir, "test.txt")
|
|
testContent := []byte("test content")
|
|
err := os.WriteFile(testFile, testContent, 0644)
|
|
require.NoError(t, err)
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
// Try to access the file
|
|
req := httptest.NewRequest("GET", "/test.txt", nil)
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
// Should return 200 for file access
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
assert.Equal(t, string(testContent), rr.Body.String())
|
|
})
|
|
|
|
t.Run("Non-existent file returns 404", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
req := httptest.NewRequest("GET", "/nonexistent.txt", nil)
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
assert.Equal(t, http.StatusNotFound, rr.Code)
|
|
})
|
|
|
|
t.Run("Subdirectory listing is blocked", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a subdirectory
|
|
subDir := filepath.Join(tmpDir, "subdir")
|
|
err := os.Mkdir(subDir, 0755)
|
|
require.NoError(t, err)
|
|
|
|
// Create a file in the subdirectory
|
|
testFile := filepath.Join(subDir, "test.txt")
|
|
err = os.WriteFile(testFile, []byte("content"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
// Try to list the subdirectory
|
|
req := httptest.NewRequest("GET", "/subdir/", nil)
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
// Should return 404 for subdirectory listing
|
|
assert.Equal(t, http.StatusNotFound, rr.Code)
|
|
})
|
|
|
|
t.Run("Files in subdirectories are accessible", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a subdirectory
|
|
subDir := filepath.Join(tmpDir, "subdir")
|
|
err := os.Mkdir(subDir, 0755)
|
|
require.NoError(t, err)
|
|
|
|
// Create a file in the subdirectory
|
|
testFile := filepath.Join(subDir, "test.txt")
|
|
testContent := []byte("subdirectory content")
|
|
err = os.WriteFile(testFile, testContent, 0644)
|
|
require.NoError(t, err)
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
// Try to access the file in the subdirectory
|
|
req := httptest.NewRequest("GET", "/subdir/test.txt", nil)
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
assert.Equal(t, string(testContent), rr.Body.String())
|
|
})
|
|
|
|
t.Run("Hidden files are accessible", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a hidden file (starting with .)
|
|
testFile := filepath.Join(tmpDir, ".hidden")
|
|
testContent := []byte("hidden content")
|
|
err := os.WriteFile(testFile, testContent, 0644)
|
|
require.NoError(t, err)
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
req := httptest.NewRequest("GET", "/.hidden", nil)
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
// Hidden files should still be accessible
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
assert.Equal(t, string(testContent), rr.Body.String())
|
|
})
|
|
}
|
|
|
|
func Test_SafeFileServer_Integration(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create test files
|
|
indexFile := filepath.Join(tmpDir, "index.html")
|
|
err := os.WriteFile(indexFile, []byte("<html>Test</html>"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
cssFile := filepath.Join(tmpDir, "style.css")
|
|
err = os.WriteFile(cssFile, []byte("body { color: red; }"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
// Create server with SafeFileServer
|
|
server := createTestServer(t, &buf)
|
|
|
|
fs := http.Dir(tmpDir)
|
|
httpFS := http.FileSystem(fs)
|
|
handler, err := hws.SafeFileServer(&httpFS)
|
|
require.NoError(t, err)
|
|
|
|
err = server.AddRoutes(hws.Route{
|
|
Path: "/static/",
|
|
Method: hws.MethodGET,
|
|
Handler: http.StripPrefix("/static", handler),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = server.Start(t.Context())
|
|
require.NoError(t, err)
|
|
defer server.Shutdown(t.Context())
|
|
|
|
<-server.Ready()
|
|
|
|
t.Run("Can serve static files through server", func(t *testing.T) {
|
|
// This would need actual HTTP requests to the running server
|
|
// Simplified for now
|
|
})
|
|
}
|