| author | |
| committer | |
| log | 3e99019af85e67cdbc5be0ef95b71662ebe683e7 |
| tree | 1a97e439e8df9fa4c03b4ee52c8322089d96968f |
| parent | 7d4b02689ebcb9dbe56e283f0ec3a17f45c8816b |
- Read attachment route paths without URI decoding before normalization
- Align test fixture paths with encoded thread/message/file names2 files changed, 4 insertions(+), 11 deletions(-)
apps/server/src/wsServer.test.ts+3-3| ... | ... | @@ -492,9 +492,9 @@ describe("WebSocket Server", () => { |
| 492 | 492 | const attachmentPath = path.join( |
| 493 | 493 | stateDir, |
| 494 | 494 | "attachments", |
| 495 | "thread folder", | |
| 496 | "message folder", | |
| 497 | "file name.png", | |
| 495 | "thread%20folder", | |
| 496 | "message%20folder", | |
| 497 | "file%20name.png", | |
| 498 | 498 | ); |
| 499 | 499 | fs.mkdirSync(path.dirname(attachmentPath), { recursive: true }); |
| 500 | 500 | fs.writeFileSync(attachmentPath, Buffer.from("hello-encoded-attachment")); |
apps/server/src/wsServer.ts+1-8| ... | ... | @@ -251,14 +251,7 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< |
| 251 | 251 | |
| 252 | 252 | if (url.pathname.startsWith(ATTACHMENTS_ROUTE_PREFIX)) { |
| 253 | 253 | const attachmentsRoot = path.resolve(path.join(serverConfig.stateDir, "attachments")); |
| 254 | const encodedRelativePath = url.pathname.slice(ATTACHMENTS_ROUTE_PREFIX.length); | |
| 255 | let rawRelativePath: string; | |
| 256 | try { | |
| 257 | rawRelativePath = decodeURIComponent(encodedRelativePath); | |
| 258 | } catch { | |
| 259 | respond(400, { "Content-Type": "text/plain" }, "Invalid attachment path"); | |
| 260 | return; | |
| 261 | } | |
| 254 | const rawRelativePath = url.pathname.slice(ATTACHMENTS_ROUTE_PREFIX.length); | |
| 262 | 255 | const normalizedRelativePath = path.normalize(rawRelativePath).replace(/^[/\\]+/, ""); |
| 263 | 256 | |
| 264 | 257 | if ( |