-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Release 8.1.1 #38768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Release 8.1.1 #38768
Changes from all commits
ed92d69
5acf342
9f16399
2c4a6bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@rocket.chat/meteor': patch | ||
| --- | ||
|
|
||
| Bump @rocket.chat/meteor version. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@rocket.chat/meteor': patch | ||
| --- | ||
|
|
||
| Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { expect } from 'chai'; | ||
| import { describe, it } from 'mocha'; | ||
|
|
||
| import { sanitizeFileName } from './sanitizeFileName'; | ||
|
|
||
| describe('sanitizeFileName', () => { | ||
| describe('valid filenames', () => { | ||
| it('should allow simple filenames', () => { | ||
| const result = sanitizeFileName('sound.mp3'); | ||
| expect(result).to.equal('sound.mp3'); | ||
| }); | ||
|
|
||
| it('should allow filenames with dashes, underscores and dots', () => { | ||
| const result = sanitizeFileName('alert_test-01.wav'); | ||
| expect(result).to.equal('alert_test-01.wav'); | ||
| }); | ||
|
|
||
| it('should allow filenames without extension', () => { | ||
| const result = sanitizeFileName('beep'); | ||
| expect(result).to.equal('beep'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('invalid paths', () => { | ||
| it('should reject path traversal using ../', () => { | ||
| expect(() => sanitizeFileName('../etc/passwd')).to.throw(); | ||
| }); | ||
|
|
||
| it('should reject path traversal using ./', () => { | ||
| expect(() => sanitizeFileName('./folder/sounds')).to.throw(); | ||
| }); | ||
|
|
||
| it('should reject nested paths', () => { | ||
| expect(() => sanitizeFileName('sounds/alert.mp3')).to.throw(); | ||
| }); | ||
|
|
||
| it('should reject absolute paths', () => { | ||
| expect(() => sanitizeFileName('/etc/passwd')).to.throw(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('invalid characters', () => { | ||
| it('should reject filenames with spaces', () => { | ||
| expect(() => sanitizeFileName('my sound.mp3')).to.throw(); | ||
| }); | ||
|
|
||
| it('should reject filenames with special characters', () => { | ||
| expect(() => sanitizeFileName('sound$.mp3')).to.throw(); | ||
| }); | ||
|
|
||
| it('should reject filenames with backslashes', () => { | ||
| expect(() => sanitizeFileName('..\\passwd')).to.throw(); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import path from 'path'; | ||
|
|
||
| export function sanitizeFileName(fileName: string) { | ||
| const base = path.basename(fileName); | ||
|
|
||
| if (base !== fileName) { | ||
| throw new Error('error-invalid-file-name'); | ||
| } | ||
|
|
||
| if (base === '.' || base.startsWith('..')) { | ||
| throw new Error('error-invalid-file-name'); | ||
| } | ||
|
|
||
| if (!/^[a-zA-Z0-9._-]+$/.test(base)) { | ||
| throw new Error('error-invalid-characters-in-file-name'); | ||
| } | ||
|
Comment on lines
+14
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Find all callers that instantiate FileSystem or invoke its IO methods
# 1. Where is RocketChatFile.FileSystem used and what is passed as fileName?
echo "=== RocketChatFile.FileSystem usage ==="
rg -n --type=ts -C 4 'RocketChatFile\.FileSystem\b' --glob '!*.spec.ts' | head -100
# 2. Where are createWriteStream / createReadStream called on FileSystem instances?
echo -e "\n=== FileSystem method calls in apps/meteor/app/file/ ==="
rg -n --type=ts -C 3 'createWriteStream|createReadStream|\.remove\b|\.deleteFile\b' apps/meteor/app/file/ --glob '!*.spec.ts' | head -150Repository: RocketChat/Rocket.Chat Length of output: 4907 🏁 Script executed: #!/bin/bash
# Find who calls createWriteStream and createReadStream on fileStore instances
echo "=== Callers of createWriteStream ==="
rg -n --type=ts 'fileStore\s*\.\s*createWriteStream\(' --glob '!*.spec.ts' -A 2 -B 2 | head -80
echo -e "\n=== Callers of createReadStream ==="
rg -n --type=ts 'fileStore\s*\.\s*createReadStream\(' --glob '!*.spec.ts' -A 2 -B 2 | head -80
echo -e "\n=== Callers of getFileWithReadStream ==="
rg -n --type=ts '\.getFileWithReadStream\(' --glob '!*.spec.ts' -A 2 -B 2 | head -80Repository: RocketChat/Rocket.Chat Length of output: 1522 🏁 Script executed: #!/bin/bash
# Find all usages of createWriteStream across the codebase
echo "=== All createWriteStream callers ==="
rg -n --type=ts 'createWriteStream' apps/meteor --glob '!*.spec.ts' -B 3 -A 1 | head -150
# Find encodeURIComponent usage with file operations
echo -e "\n=== encodeURIComponent with file operations ==="
rg -n --type=ts 'encodeURIComponent.*\.' apps/meteor --glob '!*.spec.ts' -B 2 -A 2
# Check the emoji custom file store usage more broadly
echo -e "\n=== RocketChatFileEmojiCustomInstance usage ==="
rg -n --type=ts 'RocketChatFileEmojiCustomInstance' apps/meteor --glob '!*.spec.ts' -B 2 -A 3Repository: RocketChat/Rocket.Chat Length of output: 29005 🏁 Script executed: #!/bin/bash
# Check what the asset filenames look like and understand the actual impact
echo "=== Asset filenames usage ==="
rg -n --type=ts 'RocketChatAssetsInstance\.' apps/meteor/app/assets/server -B 3 -A 3 | head -100
echo -e "\n=== Importer filenames ==="
rg -n --type=ts 'RocketChatImportFileInstance\.' apps/meteor/app/importer/server -B 2 -A 2 | head -100
# Check if there are any database records of emoji or other files that might have encoded names
echo -e "\n=== Check emoji-custom startup/init ==="
cat apps/meteor/app/emoji-custom/server/startup/emoji-custom.ts 2>/dev/null | head -50Repository: RocketChat/Rocket.Chat Length of output: 3404 🏁 Script executed: #!/bin/bash
# Check what asset keys are used
echo "=== Asset keys/names ==="
rg -n --type=ts 'Assets_' apps/meteor/app/assets/server/assets.ts | head -20
# Check what newFileName is in importer
echo -e "\n=== Importer newFileName source ==="
rg -n --type=ts 'newFileName.*=' apps/meteor/app/importer/server/methods/ -B 3 -A 1 | head -80
# Check emoji-custom initialization
echo -e "\n=== RocketChatFileEmojiCustomInstance type ==="
rg -n --type=ts 'RocketChatFileEmojiCustomInstance\s*=' apps/meteor/app/emoji-custom/ -A 5 | head -30Repository: RocketChat/Rocket.Chat Length of output: 1631 🏁 Script executed: #!/bin/bash
# Verify the actual emoji-custom instance and understand the real scope
echo "=== Emoji custom FileStore type ==="
rg -n --type=ts 'new RocketChatFile' apps/meteor/app/emoji-custom/server/startup/ -B 5 -A 5
# Understand what happens with existing emoji in database
echo -e "\n=== Check emoji-custom schema/model ==="
fd -t f 'emoji.*\.ts' apps/meteor/app/emoji-custom/server/ --type f -exec head -30 {} \;
# Check if sanitizeFileName is called before encodeURIComponent anywhere
echo -e "\n=== Check sanitizeFileName calls ==="
rg -n --type=ts 'sanitizeFileName\(' apps/meteor --glob '!*.spec.ts' -B 2 -A 2 | head -100Repository: RocketChat/Rocket.Chat Length of output: 2238 🏁 Script executed: #!/bin/bash
# Find what RocketChatFileEmojiCustomInstance actually is
echo "=== Find emoji-custom instance definition ==="
rg -n --type=ts 'RocketChatFileEmojiCustomInstance' apps/meteor/app/emoji-custom/server/startup/emoji-custom.ts -A 10 -B 5
# Check all FileSystem instances to understand the storage backends
echo -e "\n=== FileSystem instances ==="
rg -n --type=ts 'new RocketChatFileSystem\|new RocketChatFileMongoDB' apps/meteor/app/file/server/ -B 3 -A 5
# Check where custom sounds FileStore is initialized
echo -e "\n=== Custom sounds FileStore ==="
rg -n --type=ts 'RocketChatFileCustomSoundsInstance\|FileStore' apps/meteor/app/custom-sounds/server/ -B 2 -A 3Repository: RocketChat/Rocket.Chat Length of output: 291 🏁 Script executed: #!/bin/bash
# Find the actual emoji-custom startup file
echo "=== Find emoji-custom startup files ==="
find apps/meteor/app/emoji-custom -name '*.ts' -type f | grep -i startup
# Find RocketChatFileEmojiCustomInstance definition
echo -e "\n=== Find RocketChatFileEmojiCustomInstance ==="
rg -n --type=ts 'RocketChatFileEmojiCustomInstance' apps/meteor/app/emoji-custom --glob '!*.spec.ts' -B 5 -A 5 | head -100
# Find all FileStore definitions
echo -e "\n=== All FileStore definitions ==="
rg -n --type=ts 'const.*FileStore.*=.*new' apps/meteor --glob '!*.spec.ts' -B 2 -A 2 | head -150Repository: RocketChat/Rocket.Chat Length of output: 9577 🏁 Script executed: #!/bin/bash
# Find where RocketChatFileEmojiCustomInstance is exported from
echo "=== Find emoji-custom export ==="
rg -n --type=ts 'export.*RocketChatFileEmojiCustomInstance' apps/meteor/app/emoji-custom -A 5 -B 5
# Find the startup directory
echo -e "\n=== Find emoji-custom server files ==="
find apps/meteor/app/emoji-custom/server -type f -name '*.ts' | head -30
# Search in the entire app for where these instances are created
echo -e "\n=== Search for RocketChatFile instance creation ==="
rg -n --type=ts 'new RocketChatFile' apps/meteor --glob '!*.spec.ts' -B 3 -A 3 | head -150Repository: RocketChat/Rocket.Chat Length of output: 1052 🏁 Script executed: #!/bin/bash
# Check the emoji-custom index.ts
echo "=== emoji-custom index.ts ==="
cat apps/meteor/app/emoji-custom/server/index.ts
# Search for RocketChatFileEmojiCustomInstance initialization across entire codebase
echo -e "\n=== Search for RocketChatFileEmojiCustomInstance initialization ==="
rg -n --type=ts 'RocketChatFileEmojiCustomInstance\s*=' apps/meteor --glob '!*.spec.ts' -B 3 -A 5
# Check imports from 'startup/emoji-custom' module
echo -e "\n=== Files that import from emoji-custom startup ==="
rg -n --type=ts "from.*'.*emoji-custom'" apps/meteor/app/emoji-custom --glob '!*.spec.ts' | grep -i startupRepository: RocketChat/Rocket.Chat Length of output: 793 🏁 Script executed: #!/bin/bash
# The startup file must exist since it's being imported. Let's find it with a broader search
echo "=== Search for emoji-custom.ts files ==="
find apps/meteor/app/emoji-custom -name '*emoji-custom*' -type f
# Also try with git ls-files
echo -e "\n=== git ls-files for emoji-custom ==="
git ls-files apps/meteor/app/emoji-custom | grep -i startup
# If file exists, read it
echo -e "\n=== Read the startup file ==="
if [ -f apps/meteor/app/emoji-custom/server/startup/emoji-custom.ts ]; then
cat apps/meteor/app/emoji-custom/server/startup/emoji-custom.ts
else
echo "File not found at expected path"
# Try to find all .ts files in emoji-custom
find apps/meteor/app/emoji-custom -type f -name '*.ts'
fiRepository: RocketChat/Rocket.Chat Length of output: 694 🏁 Script executed: #!/bin/bash
# Read the .js startup file
echo "=== Read emoji-custom.js startup ==="
cat apps/meteor/app/emoji-custom/server/startup/emoji-custom.js
# Also check assets startup for comparison
echo -e "\n=== Check assets startup ==="
find apps/meteor/app/assets/server -name '*startup*' -o -name '*assets*' | grep -v node_modules
cat apps/meteor/app/assets/server/assets.ts | head -50Repository: RocketChat/Rocket.Chat Length of output: 5248 The strict allowlist regex breaks backward compatibility with encodeURIComponent-encoded filenames. The regex
Any emoji with non-ASCII or space characters (e.g., "smile 😊", "my sound") will be encoded as The regex should either allow 🤖 Prompt for AI Agents |
||
|
|
||
| return base; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing edge-case coverage and weak error-type assertions.
Two gaps worth addressing:
Missing tests for
'','.', and'..'— all currently throw'error-invalid-file-name'but are not exercised. A test for a valid hidden-style filename like'.hidden'(which does pass today) would also document the intended boundary.Weak throw assertion —
.to.throw()passes for any exception including an unexpectedTypeError. Scoping to the expected error string removes false-positive risk.🛡️ Suggested additions
And tighten existing assertions, e.g.:
🤖 Prompt for AI Agents