fix(im): validate Content-Range for resource download chunks#1178
fix(im): validate Content-Range for resource download chunks#1178xu91102 wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThis PR hardens HTTP range-request validation for IM resource downloads by introducing a ChangesRange Request Validation for IM Downloads
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes The changes introduce a new validation contract for Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
shortcuts/im/helpers_test.go (1)
562-569:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCover the new Windows-rooted path branch here.
This table exercises
/tmp/out.bin, but it never hits the newstrings.HasPrefix(outputPath, "\\")rejection path. Adding a\tmp\out.bincase would lock in the regression this PR is trying to prevent on Windows.Suggested test case
{name: "absolute path", fileKey: "file_123", outputPath: "/tmp/out.bin", wantErr: "absolute paths are not allowed"}, + {name: "windows rooted path", fileKey: "file_123", outputPath: `\tmp\out.bin`, wantErr: "absolute paths are not allowed"}, {name: "parent escape", fileKey: "file_123", outputPath: "../out.bin", wantErr: "path cannot escape the current working directory"},🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@shortcuts/im/helpers_test.go` around lines 562 - 569, Add a test row to the table in shortcuts/im/helpers_test.go that exercises the Windows-rooted path branch by using outputPath set to `\tmp\out.bin` (e.g., {name: "Windows-rooted path", fileKey: "file_123", outputPath: "\\tmp\\out.bin", wantErr: "absolute paths are not allowed"}) so the strings.HasPrefix(outputPath, "\\") rejection branch is covered; place it alongside the other cases that assert errors for absolute/escaped paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@shortcuts/im/im_messages_resources_download.go`:
- Around line 244-251: The code currently only validates the Content-Range
header via validateContentRange (using r.nextOffset, end, r.totalSize) but does
not verify the actual response body length, allowing corrupted writes; update
the download handling around the validateContentRange/resp.Body logic (the block
that calls validateContentRange and the similar logic at lines ~253-254) to
compute expectedLen = end - start + 1 (from the contentRange you validated),
read exactly expectedLen bytes from resp.Body (e.g., via io.ReadFull or io.CopyN
into the destination) and fail with an error (close resp.Body and return
output.ErrNetwork(...)) if fewer or more bytes are read (EOF/mismatch), and only
advance r.nextOffset after a successful exact-length write; apply the same
exact-length check to the initial probe body path as well.
---
Outside diff comments:
In `@shortcuts/im/helpers_test.go`:
- Around line 562-569: Add a test row to the table in
shortcuts/im/helpers_test.go that exercises the Windows-rooted path branch by
using outputPath set to `\tmp\out.bin` (e.g., {name: "Windows-rooted path",
fileKey: "file_123", outputPath: "\\tmp\\out.bin", wantErr: "absolute paths are
not allowed"}) so the strings.HasPrefix(outputPath, "\\") rejection branch is
covered; place it alongside the other cases that assert errors for
absolute/escaped paths.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7d40b66d-6137-48a2-b13a-d82f8e397d5c
📒 Files selected for processing (3)
shortcuts/im/helpers_network_test.goshortcuts/im/helpers_test.goshortcuts/im/im_messages_resources_download.go
| if err := validateContentRange(resp.Header.Get("Content-Range"), contentRange{ | ||
| start: r.nextOffset, | ||
| end: end, | ||
| total: r.totalSize, | ||
| }); err != nil { | ||
| resp.Body.Close() | ||
| return 0, output.ErrNetwork("invalid Content-Range header on range response: %s", err) | ||
| } |
There was a problem hiding this comment.
Validate the chunk body length, not just the header.
This still accepts a 206 body whose actual byte count differs from end-start+1. Because nextOffset advances from the header immediately, an oversized chunk followed by a later undersized chunk can still land on the expected final totalSize while writing corrupted bytes to disk. Please track the advertised length for each response and fail on EOF when the body length does not match it; the initial probe body needs the same check.
Also applies to: 253-254
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@shortcuts/im/im_messages_resources_download.go` around lines 244 - 251, The
code currently only validates the Content-Range header via validateContentRange
(using r.nextOffset, end, r.totalSize) but does not verify the actual response
body length, allowing corrupted writes; update the download handling around the
validateContentRange/resp.Body logic (the block that calls validateContentRange
and the similar logic at lines ~253-254) to compute expectedLen = end - start +
1 (from the contentRange you validated), read exactly expectedLen bytes from
resp.Body (e.g., via io.ReadFull or io.CopyN into the destination) and fail with
an error (close resp.Body and return output.ErrNetwork(...)) if fewer or more
bytes are read (EOF/mismatch), and only advance r.nextOffset after a successful
exact-length write; apply the same exact-length check to the initial probe body
path as well.
Summary
Fixes an integrity gap in
im +messages-resources-downloadrange downloads where later206 Partial Contentresponses could return the wrong byte range while still matching the final byte count. The downloader now parses and validatesContent-Rangefor the initial and subsequent chunks.Changes
Content-Rangeparser that validates byte start, end, and total values.200 OKsingle-stream downloads unchanged./tmp/out.binare rejected on Windows too.Test Plan
go test ./shortcuts/im -run TestParseContentRange|TestDownloadIMResourceRangeChunksValidateContentRange|TestDownloadIMResourceToPathInitialRangeMustMatchRequest|TestDownloadIMResourceToPathHTTPClientError|TestNormalizeDownloadOutputPath|TestParseContentDispositionFilename|TestResolveIMResourceDownloadPath|TestDownloadIMResourceToPathRangeDownload|TestDownloadIMResourceToPathInvalidContentRange|TestDownloadIMResourceToPathRangeChunkFailureCleansOutput|TestDownloadIMResourceToPathRangeOverflowCleansOutput|TestDownloadIMResourceToPathRangeShortChunkSizeMismatchgofmt -l shortcuts/im/im_messages_resources_download.go shortcuts/im/helpers_test.go shortcuts/im/helpers_network_test.goproduced no outputgit diff --checkgo test ./shortcuts/imwas run on Windows but hit existing platform issues unrelated to this change: temp media files remained locked during cleanup, andTestValidateMediaFlagPath/absolute_path_rejecteduses/etc/passwd, which is not absolute on Windows.lark-cli im +messages-resources-downloadflow works as expected: not run; change is covered by focused HTTP stream unit tests.Related Issues
Summary by CodeRabbit
Bug Fixes
Tests