Commit ea3c61d
🪣 fix: Decode S3 Object Keys from URLs (#15426)
* 🔤 fix: Decode percent-encoded S3 keys so non-ASCII filenames are readable
extractKeyFromS3Url returns `URL.pathname` as the S3 object key without
decoding it. The AWS SDK percent-encodes the Key again when it signs the
request, so a file stored under `Ársreikningur.pdf` is fetched as
`%C3%81rsreikningur.pdf` and every read fails with NoSuchKey. ASCII keys are
byte-identical either way, which is why this only appears for non-English
filenames.
Decode keys derived from a URL path in all three branches (path-style
endpoint, bucket-in-path, virtual-hosted). A key passed in raw — not a URL —
still returns untouched, and a malformed escape sequence falls back to the
raw value with a warning rather than throwing.
* 🔗 fix: Percent-encode CloudFront URL keys so both URL forms agree
buildCloudFrontUrl interpolated the raw S3 key into the URL while SDK-generated
S3 URLs carry an encoded one, so the two forms of `file.filepath` disagreed
about what a `%` means. `assertS3FileName` permits `%`, so a key containing the
literal text `report%20final.pdf` produced a CloudFront URL indistinguishable
from one for a key containing a space — and decoding on extraction would then
target the wrong object on read, re-sign, and delete.
Encoding each path segment here (separators stay literal) makes both producers
consistent, which is what lets extractKeyFromS3Url decode unconditionally.
* style: sort imports in cloudfront/crud.ts (pre-existing drift)
The changed-file import-sort gate flags this file; the drift predates this PR
(the untouched upstream version fails the same check). Kept as its own commit
so it does not obscure the fix.
* 🔏 fix: Encode the CloudFront Invalidation Path Like the Viewer URL
`buildCloudFrontUrl` now percent-encodes each key segment, so the cached
viewer path for a key with a literal `%` or a non-ASCII character is the
encoded form. `deleteFileFromCloudFront` still handed the raw key to
`CreateInvalidationCommand`, so the invalidation no longer matched the
cached object and deleted content stayed served until the entry expired.
Both producers now share one `encodeKeyPath` helper.
Also asserts that `getS3FileStream` sends the decoded key to
`GetObjectCommand`, which is the call that actually failed with
`NoSuchKey`, rather than only checking the extractor.
Co-authored-by: dinershtein <228485+dinershtein@users.noreply.github.com>
---------
Co-authored-by: Danny Avila <danny@librechat.ai>
Co-authored-by: dinershtein <228485+dinershtein@users.noreply.github.com>1 parent 1aa86a9 commit ea3c61d
4 files changed
Lines changed: 138 additions & 16 deletions
File tree
- packages/api/src/storage
- cloudfront
- __tests__
- s3
- __tests__
Lines changed: 42 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
95 | 117 | | |
96 | 118 | | |
97 | 119 | | |
| |||
512 | 534 | | |
513 | 535 | | |
514 | 536 | | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
515 | 557 | | |
516 | 558 | | |
517 | 559 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | | - | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
8 | 7 | | |
9 | 8 | | |
10 | 9 | | |
| |||
14 | 13 | | |
15 | 14 | | |
16 | 15 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
| 16 | + | |
21 | 17 | | |
22 | 18 | | |
23 | 19 | | |
| |||
27 | 23 | | |
28 | 24 | | |
29 | 25 | | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
80 | 92 | | |
81 | 93 | | |
82 | 94 | | |
83 | 95 | | |
84 | 96 | | |
85 | 97 | | |
86 | | - | |
87 | | - | |
| 98 | + | |
88 | 99 | | |
89 | 100 | | |
90 | 101 | | |
| |||
235 | 246 | | |
236 | 247 | | |
237 | 248 | | |
238 | | - | |
239 | | - | |
| 249 | + | |
240 | 250 | | |
241 | 251 | | |
242 | 252 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1118 | 1118 | | |
1119 | 1119 | | |
1120 | 1120 | | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
1121 | 1134 | | |
1122 | 1135 | | |
1123 | 1136 | | |
| |||
1463 | 1476 | | |
1464 | 1477 | | |
1465 | 1478 | | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
| 1510 | + | |
| 1511 | + | |
| 1512 | + | |
1466 | 1513 | | |
1467 | 1514 | | |
1468 | 1515 | | |
| |||
1511 | 1558 | | |
1512 | 1559 | | |
1513 | 1560 | | |
1514 | | - | |
| 1561 | + | |
1515 | 1562 | | |
1516 | 1563 | | |
1517 | 1564 | | |
1518 | 1565 | | |
1519 | | - | |
| 1566 | + | |
| 1567 | + | |
1520 | 1568 | | |
1521 | 1569 | | |
1522 | 1570 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
638 | 638 | | |
639 | 639 | | |
640 | 640 | | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
641 | 662 | | |
642 | 663 | | |
643 | 664 | | |
| |||
659 | 680 | | |
660 | 681 | | |
661 | 682 | | |
662 | | - | |
| 683 | + | |
663 | 684 | | |
664 | 685 | | |
665 | 686 | | |
| |||
677 | 698 | | |
678 | 699 | | |
679 | 700 | | |
680 | | - | |
| 701 | + | |
681 | 702 | | |
682 | 703 | | |
683 | 704 | | |
| |||
695 | 716 | | |
696 | 717 | | |
697 | 718 | | |
698 | | - | |
699 | | - | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
700 | 722 | | |
701 | 723 | | |
702 | 724 | | |
| |||
0 commit comments