Skip to content

Commit 71e6738

Browse files
authored
fix: Sanitize sessionId (#594)
* Add CLAUDE.md. * fix: Sanitize sessionId
1 parent c73bef3 commit 71e6738

3 files changed

Lines changed: 177 additions & 1 deletion

File tree

CLAUDE.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## About Jibri
6+
7+
Jibri (JItsi BRoadcasting Infrastructure) provides services for recording or streaming Jitsi Meet conferences. It works by launching a Chrome instance in a virtual framebuffer, capturing and encoding output with ffmpeg. Only one recording at a time is supported per Jibri instance.
8+
9+
## Build and Test Commands
10+
11+
### Building
12+
```bash
13+
# Full build with tests and linting
14+
mvn verify
15+
16+
# Package without running tests
17+
mvn package -DskipTests
18+
19+
# Build JAR with dependencies
20+
mvn clean package
21+
# Output: target/jibri-8.0-SNAPSHOT-jar-with-dependencies.jar
22+
```
23+
24+
### Testing
25+
```bash
26+
# Run all tests
27+
mvn test
28+
29+
# Run a specific test class
30+
mvn test -Dtest=SeleniumStateMachineTest
31+
32+
# Run a specific test method
33+
mvn test -Dtest=SeleniumStateMachineTest#testMethodName
34+
```
35+
36+
### Linting
37+
```bash
38+
# Run both Java checkstyle and Kotlin ktlint
39+
mvn verify
40+
41+
# Run only ktlint
42+
mvn ktlint:check
43+
44+
# Auto-format Kotlin code
45+
mvn ktlint:format
46+
```
47+
48+
## Architecture
49+
50+
### Core Components
51+
52+
1. **JibriManager** (`JibriManager.kt`) - Central orchestrator that manages Jibri services and tracks busy/idle state. Publishes status updates and enforces single-service-at-a-time constraint.
53+
54+
2. **Services** (in `service/impl/`) - Three main service types:
55+
- `FileRecordingJibriService` - Records conferences to local files
56+
- `StreamingJibriService` - Streams conferences to RTMP endpoints
57+
- `SipGatewayJibriService` - SIP gateway functionality
58+
59+
All services extend `StatefulJibriService` and use a state machine pattern.
60+
61+
3. **APIs** - Three API layers for control:
62+
- `XmppApi` - XMPP-based control via MUC (JibriBrewery)
63+
- `HttpApi` - External HTTP API (port 2222) for start/stop recording
64+
- `InternalHttpApi` - Internal HTTP API (port 3333) for health checks and shutdown
65+
66+
4. **Selenium Layer** (`selenium/`) - Controls Chrome browser:
67+
- `JibriSelenium` - WebDriver wrapper for browser control
68+
- `SeleniumStateMachine` - Manages browser state transitions
69+
- Status checks in `status_checks/` monitor call health (media received, ICE connection, empty call detection)
70+
71+
5. **Capture Layer** (`capture/ffmpeg/`) - FFmpeg integration:
72+
- `FfmpegCapturer` - Manages ffmpeg process for audio/video capture
73+
- `FfmpegStatusStateMachine` - Tracks capture state
74+
- Platform-specific capture commands (Linux X11grab, macOS AVFoundation)
75+
76+
6. **Configuration** (`config/`) - Uses jitsi-metaconfig library:
77+
- `reference.conf` contains all default values
78+
- Override defaults in `/etc/jitsi/jibri/jibri.conf`
79+
- Config hot-reloading triggers graceful restart when idle
80+
81+
### Control Flow
82+
83+
1. Request arrives via XMPP or HTTP API
84+
2. JibriManager checks if idle, creates appropriate service
85+
3. Service starts Selenium (Chrome browser joins call)
86+
4. Service starts FFmpeg (captures screen/audio)
87+
5. Status checks monitor call health
88+
6. On completion, service finalizes recording and returns to idle
89+
90+
### State Management
91+
92+
Extensive use of state machines via Tinder StateMachine library:
93+
- `JibriServiceStateMachine` - Service lifecycle states
94+
- `SeleniumStateMachine` - Browser states
95+
- `FfmpegStatusStateMachine` - Capture states
96+
97+
All state transitions are logged and published to metrics.
98+
99+
## Configuration
100+
101+
Configuration is layered (priority order):
102+
1. Command-line arguments
103+
2. `jibri.conf` (HOCON format)
104+
3. `reference.conf` (defaults in resources)
105+
106+
Key config sections:
107+
- `jibri.api.xmpp.environments` - XMPP connection details
108+
- `jibri.ffmpeg.*` - FFmpeg encoding parameters
109+
- `jibri.chrome.flags` - Chrome launch flags
110+
- `jibri.call-status-checks.*` - Timeouts for empty call detection
111+
112+
## Code Style
113+
114+
- Primary language: Kotlin (Java only in extreme cases)
115+
- Follow Kotlin style guide (enforced by ktlint)
116+
- Pre-commit hook available: `resources/add_git_pre_commit_script.sh`
117+
- All Kotlin warnings are errors (`-Werror` compiler flag)
118+
119+
## Testing
120+
121+
- Test framework: Kotest (JUnit 5 compatible)
122+
- Mocking: MockK for Kotlin
123+
- Test helpers in `src/test/kotlin/org/jitsi/jibri/helpers/`
124+
- Tests use in-memory filesystems for file operations
125+
126+
## Java Version
127+
128+
- Source/Target: Java 11 minimum
129+
- Runtime: Java 21 supported (as of recent commits)
130+
- Kotlin JVM target: 11
131+
132+
## Dependencies
133+
134+
Key external dependencies:
135+
- Selenium WebDriver 3.12.0 - Browser automation
136+
- Ktor 3.0 - HTTP server framework
137+
- jicoco libraries - Jitsi common components (XMPP, config, metrics)
138+
- Tinder StateMachine - State machine implementation
139+
- FFmpeg - External binary for capture (not a Maven dependency)
140+
141+
## Important Notes
142+
143+
- Jibri requires exclusive access to display and audio devices
144+
- Single-use mode: If `jibri.single-use-mode = true`, Jibri exits after one session
145+
- Health checks exposed at internal HTTP API `/jibri/api/v1.0/health`
146+
- Metrics available via StatsD and optionally Prometheus
147+
- Webhook support for external status notifications

src/main/kotlin/org/jitsi/jibri/service/impl/FileRecordingJibriService.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,15 @@ class FileRecordingJibriService(
128128
* be nested within [recordingsDirectory].
129129
*/
130130
private val sessionRecordingDirectory =
131-
fileSystem.getPath(recordingsDirectory).resolve(fileRecordingParams.sessionId)
131+
fileSystem.getPath(recordingsDirectory).resolve(sanitizeSessionId(fileRecordingParams.sessionId))
132+
133+
/**
134+
* Sanitize the session ID to ensure it's safe for use as a directory name.
135+
*/
136+
private fun sanitizeSessionId(sessionId: String): String {
137+
// Replace any character that is not alphanumeric, dash, or underscore with underscore
138+
return sessionId.replace(Regex("[^a-zA-Z0-9_-]"), "_")
139+
}
132140

133141
init {
134142
logger.info("Writing recording to $sessionRecordingDirectory, finalize script path $finalizeScriptPath")

src/test/kotlin/org/jitsi/jibri/service/impl/FileRecordingJibriServiceTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,27 @@ internal class FileRecordingJibriServiceTest : ShouldSpec() {
203203
}
204204
}
205205
}
206+
context("when sessionId contains special characters") {
207+
val sessionId = "foo&bar/baz"
208+
val fileRecordingParams = FileRecordingParams(
209+
callParams,
210+
sessionId,
211+
callLoginParams
212+
)
213+
214+
FileRecordingJibriService(
215+
fileRecordingParams,
216+
SeleniumMockHelper().mock,
217+
CapturerMockHelper().mock,
218+
mockk(),
219+
fs
220+
).start()
221+
222+
should("sanitize the sessionId") {
223+
// The sanitized version should replace all special chars with underscores
224+
Files.exists(fs.getPath(recordingsDir.toString(), "foo_bar_baz")) shouldBe true
225+
}
226+
}
206227
}
207228

208229
private fun setPerms(permsStr: String, p: Path) {

0 commit comments

Comments
 (0)