mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-02 16:20:57 +02:00
fix(security): bound cover download memory usage
This commit is contained in:
+8
-1
@@ -36,6 +36,7 @@ func downloadCoverToMemory(coverURL string) ([]byte, error) {
|
||||
|
||||
const (
|
||||
embeddedCoverJPEGQuality = 88
|
||||
maxCoverDownloadBytes = 24 * 1024 * 1024
|
||||
// Decoding arbitrary provider artwork allocates roughly four bytes per
|
||||
// pixel. Refuse pathological images before Decode so a malicious extension
|
||||
// cannot force an unbounded mobile allocation. Normal artwork through
|
||||
@@ -298,11 +299,17 @@ func fetchCoverBytes(downloadURL string) ([]byte, error) {
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("cover download failed: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
if resp.ContentLength > maxCoverDownloadBytes {
|
||||
return nil, fmt.Errorf("cover download exceeds %d MiB limit", maxCoverDownloadBytes/(1024*1024))
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
data, err := io.ReadAll(io.LimitReader(resp.Body, maxCoverDownloadBytes+1))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read cover data: %w", err)
|
||||
}
|
||||
if len(data) > maxCoverDownloadBytes {
|
||||
return nil, fmt.Errorf("cover download exceeds %d MiB limit", maxCoverDownloadBytes/(1024*1024))
|
||||
}
|
||||
|
||||
width, height := coverDimensions(data)
|
||||
GoLog("[Cover] Downloaded %d KB (%dx%d)", len(data)/1024, width, height)
|
||||
|
||||
@@ -2,10 +2,14 @@ package gobackend
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -151,6 +155,20 @@ func TestDownloadCoverUsesProviderURLUnchanged(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchCoverBytesRejectsOversizedResponse(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
|
||||
writer.Header().Set("Content-Length", fmt.Sprintf("%d", maxCoverDownloadBytes+1))
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer server.Close()
|
||||
SetAllowPrivateNetwork(true)
|
||||
defer SetAllowPrivateNetwork(false)
|
||||
|
||||
if _, err := fetchCoverBytes(server.URL); err == nil || !strings.Contains(err.Error(), "exceeds") {
|
||||
t.Fatalf("expected oversized cover rejection, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResizeCoverForEmbeddingPreservesAspectRatio(t *testing.T) {
|
||||
original := encodedTestCover(t, 1200, 600, "jpeg")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user