fix: validate UUIDs in OPDS middleware before authentication

- Add UUID validation in device_auth middleware for OPDS routes
- Return 400 Bad Request for invalid device/book IDs instead of 401
- Remove redundant UUID validation from OPDS handlers (middleware handles it)
This commit is contained in:
2026-02-14 00:12:15 -05:00
parent 030e8c87e3
commit 02ff078adf
2 changed files with 31 additions and 35 deletions
+13 -35
View File
@@ -54,6 +54,7 @@ func (h *OPDSHandler) getBaseURLs(c echo.Context) (string, string, error) {
// GetDeviceCatalog returns the OPDS catalog feed for a device
func (h *OPDSHandler) GetDeviceCatalog(c echo.Context) error {
deviceID := c.Param("deviceId")
page := c.QueryParam("page")
perPage := c.QueryParam("per_page")
includeFormat := c.QueryParam("include_format")
@@ -217,6 +218,7 @@ func (h *OPDSHandler) GetDeviceCatalog(c echo.Context) error {
// SearchDeviceCatalog searches the OPDS catalog for a device
func (h *OPDSHandler) SearchDeviceCatalog(c echo.Context) error {
deviceID := c.Param("deviceId")
query := c.QueryParam("q")
if query == "" {
@@ -341,16 +343,9 @@ func (h *OPDSHandler) DownloadBook(c echo.Context) error {
format = "epub"
}
// Parse IDs
deviceUUID, err := uuid.Parse(deviceID)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"})
}
bookUUID, err := uuid.Parse(bookID)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book id"})
}
// Parse IDs (middleware guarantees valid UUIDs)
deviceUUID, _ := uuid.Parse(deviceID)
bookUUID, _ := uuid.Parse(bookID)
// Verify device exists
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
@@ -484,16 +479,9 @@ func (h *OPDSHandler) GetCoverImage(c echo.Context) error {
deviceID := c.Param("deviceId")
bookID := c.Param("bookId")
// Parse IDs
deviceUUID, err := uuid.Parse(deviceID)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"})
}
bookUUID, err := uuid.Parse(bookID)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book id"})
}
// Parse IDs (middleware guarantees valid UUIDs)
deviceUUID, _ := uuid.Parse(deviceID)
bookUUID, _ := uuid.Parse(bookID)
// Verify device exists
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
@@ -580,11 +568,8 @@ func (h *OPDSHandler) GetDeviceNavigation(c echo.Context) error {
return c.XML(http.StatusInternalServerError, opds.NewErrorFeed("Failed to get config"))
}
// Parse device ID
deviceUUID, err := uuid.Parse(deviceID)
if err != nil {
return c.XML(http.StatusBadRequest, opds.NewErrorFeed("Invalid device ID"))
}
// Parse device ID (middleware guarantees valid UUID)
deviceUUID, _ := uuid.Parse(deviceID)
// Verify device exists
_, err = h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
@@ -629,16 +614,9 @@ func (h *OPDSHandler) ListFormats(c echo.Context) error {
deviceID := c.Param("deviceId")
bookID := c.Param("bookId")
// Parse IDs
deviceUUID, err := uuid.Parse(deviceID)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device id"})
}
bookUUID, err := uuid.Parse(bookID)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book id"})
}
// Parse IDs (middleware guarantees valid UUIDs)
deviceUUID, _ := uuid.Parse(deviceID)
bookUUID, _ := uuid.Parse(bookID)
// Verify device exists
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
+18
View File
@@ -42,6 +42,24 @@ func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerF
var urlToken string
var queryToken string
// For OPDS routes, validate deviceId is a valid UUID before authentication
// This allows returning 400 Bad Request for invalid UUIDs instead of 401
if strings.HasPrefix(c.Request().URL.Path, "/opds/devices/") {
deviceID := c.Param("deviceId")
if deviceID != "" {
if _, err := uuid.Parse(deviceID); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid device ID"})
}
}
// Also validate bookId for download, cover, and formats endpoints
bookID := c.Param("bookId")
if bookID != "" {
if _, err := uuid.Parse(bookID); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid book ID"})
}
}
}
// Method 1: Try Bearer token header (KOReader, API clients, OPDS)
authHeader := c.Request().Header.Get("Authorization")
if authHeader != "" {