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:
+13
-35
@@ -54,6 +54,7 @@ func (h *OPDSHandler) getBaseURLs(c echo.Context) (string, string, error) {
|
|||||||
// GetDeviceCatalog returns the OPDS catalog feed for a device
|
// GetDeviceCatalog returns the OPDS catalog feed for a device
|
||||||
func (h *OPDSHandler) GetDeviceCatalog(c echo.Context) error {
|
func (h *OPDSHandler) GetDeviceCatalog(c echo.Context) error {
|
||||||
deviceID := c.Param("deviceId")
|
deviceID := c.Param("deviceId")
|
||||||
|
|
||||||
page := c.QueryParam("page")
|
page := c.QueryParam("page")
|
||||||
perPage := c.QueryParam("per_page")
|
perPage := c.QueryParam("per_page")
|
||||||
includeFormat := c.QueryParam("include_format")
|
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
|
// SearchDeviceCatalog searches the OPDS catalog for a device
|
||||||
func (h *OPDSHandler) SearchDeviceCatalog(c echo.Context) error {
|
func (h *OPDSHandler) SearchDeviceCatalog(c echo.Context) error {
|
||||||
deviceID := c.Param("deviceId")
|
deviceID := c.Param("deviceId")
|
||||||
|
|
||||||
query := c.QueryParam("q")
|
query := c.QueryParam("q")
|
||||||
|
|
||||||
if query == "" {
|
if query == "" {
|
||||||
@@ -341,16 +343,9 @@ func (h *OPDSHandler) DownloadBook(c echo.Context) error {
|
|||||||
format = "epub"
|
format = "epub"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse IDs
|
// Parse IDs (middleware guarantees valid UUIDs)
|
||||||
deviceUUID, err := uuid.Parse(deviceID)
|
deviceUUID, _ := uuid.Parse(deviceID)
|
||||||
if err != nil {
|
bookUUID, _ := uuid.Parse(bookID)
|
||||||
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"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify device exists
|
// Verify device exists
|
||||||
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
|
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")
|
deviceID := c.Param("deviceId")
|
||||||
bookID := c.Param("bookId")
|
bookID := c.Param("bookId")
|
||||||
|
|
||||||
// Parse IDs
|
// Parse IDs (middleware guarantees valid UUIDs)
|
||||||
deviceUUID, err := uuid.Parse(deviceID)
|
deviceUUID, _ := uuid.Parse(deviceID)
|
||||||
if err != nil {
|
bookUUID, _ := uuid.Parse(bookID)
|
||||||
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"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify device exists
|
// Verify device exists
|
||||||
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
|
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"))
|
return c.XML(http.StatusInternalServerError, opds.NewErrorFeed("Failed to get config"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse device ID
|
// Parse device ID (middleware guarantees valid UUID)
|
||||||
deviceUUID, err := uuid.Parse(deviceID)
|
deviceUUID, _ := uuid.Parse(deviceID)
|
||||||
if err != nil {
|
|
||||||
return c.XML(http.StatusBadRequest, opds.NewErrorFeed("Invalid device ID"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify device exists
|
// Verify device exists
|
||||||
_, err = h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
|
_, 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")
|
deviceID := c.Param("deviceId")
|
||||||
bookID := c.Param("bookId")
|
bookID := c.Param("bookId")
|
||||||
|
|
||||||
// Parse IDs
|
// Parse IDs (middleware guarantees valid UUIDs)
|
||||||
deviceUUID, err := uuid.Parse(deviceID)
|
deviceUUID, _ := uuid.Parse(deviceID)
|
||||||
if err != nil {
|
bookUUID, _ := uuid.Parse(bookID)
|
||||||
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"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify device exists
|
// Verify device exists
|
||||||
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
|
device, err := h.db.GetDevice(c.Request().Context(), pgtype.UUID{Bytes: deviceUUID, Valid: true})
|
||||||
|
|||||||
@@ -42,6 +42,24 @@ func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerF
|
|||||||
var urlToken string
|
var urlToken string
|
||||||
var queryToken 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)
|
// Method 1: Try Bearer token header (KOReader, API clients, OPDS)
|
||||||
authHeader := c.Request().Header.Get("Authorization")
|
authHeader := c.Request().Header.Get("Authorization")
|
||||||
if authHeader != "" {
|
if authHeader != "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user