Skip to content

Commit d22598e

Browse files
committed
fix: Harden obs-websocket vendor request implementation
- Move FILTER_ID and PROC_OVERRIDE_* proc names to plugin-main.hpp as shared constants - Normalize UUID input to lowercase before obs_get_source_by_uuid() lookup - Move vendor.store() to after all request registrations complete - Replace locale-dependent std::isxdigit/isalpha with explicit ASCII range checks - Reorder obs_module_unload() to null statusDock before unregistering vendor requests - Remove lib/ from CPACK_SOURCE_IGNORE_FILES to preserve obs-websocket-api.h in source tarballs - Add SYSTEM keyword to obs-websocket include directory in CMakeLists.txt - Add early exit in build.ps1 on submodule update failure - Fix cmake-format glob pattern for lib/ submodule exclusion - Add submodule init instructions to README / README_ja - Correct error strings in API documentation
1 parent 6fd2dcf commit d22598e

13 files changed

Lines changed: 214 additions & 50 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
!screenshot2.jpg
3131
!build.ps1
3232
!/lib
33+
!.gitmodules
3334
!README_ja.md
3435
!API.md
3536
!API_ja.md

.gitmodules

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[submodule "lib/obs-websocket"]
22
path = lib/obs-websocket
33
url = https://github.com/obsproject/obs-websocket.git
4+
# Pinned to tag: 5.7.3 (commit 1fcb95b)
45
# Tag-pinned: do NOT use `git submodule update --remote`.
56
# To update, fetch and checkout a specific release tag manually
67
# (see https://github.com/obsproject/obs-websocket/tags).

API.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,16 @@ Vendor requests require a client authenticated with obs-websocket. The obs-webso
294294

295295
- `filter_uuid` must be a 36-character hyphenated UUID string. Other shapes are rejected with `"filter_uuid must be a UUID string"`.
296296
- `format` cannot exceed 1024 bytes. Longer strings are rejected with `"format too long"`.
297-
- `filter_uuid` must resolve to a Branch Output filter source. Any other source (including non-existent UUIDs) is rejected with `"Filter not found"`.
297+
- `format` must be a relative path expression. Absolute paths (POSIX `/...`, Windows `\...` or `X:\...`) and any `..` segment are rejected with `"format must not contain path traversal or absolute paths"`.
298+
- `filter_uuid` must resolve to a Branch Output filter source. Any other source (including non-existent UUIDs) is rejected with `"UUID does not refer to a Branch Output filter"`.
298299
- Do not send bursts of requests while a recording transition (file split, restart) is in progress — a request may block until the transition completes.
299300

301+
### Client-side throttling
302+
303+
The plugin does **not** rate-limit `override_recording_filename_format` or `override_replay_buffer_filename_format`. Each request that produces a different `format` while recording is active may trigger a file split or a recording restart, so a client that fires updates faster than the recording can settle will fragment files and stress the encoder pipeline.
304+
305+
The bundled OBS scripts (see [Throttling](#recording-filename-from-text)) deduplicate by value and apply at most one update every 30 seconds per distinct `format`. Vendor requests do not pass through that script, so this guard is bypassed when driving the plugin over obs-websocket. **Implement equivalent throttling in your client** — at minimum, suppress duplicate `format` values and rate-limit distinct updates (≥ 30 s is a safe starting point; tune to match your file-split and restart tolerance).
306+
300307
### `get_filter_list`
301308

302309
Enumerates every Branch Output filter currently loaded in OBS.

API_ja.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,16 @@ vendor request は obs-websocket に認証済みのクライアントからの
294294

295295
- `filter_uuid` は 36 文字のハイフン付き UUID 文字列である必要があります。それ以外の形式は `"filter_uuid must be a UUID string"` で拒否されます。
296296
- `format` は 1024 バイトを超えられません。超過した場合は `"format too long"` で拒否されます。
297-
- `filter_uuid` は Branch Output フィルターソースに解決される必要があります。他種別のソースや存在しない UUID は `"Filter not found"` で拒否されます。
297+
- `format` は相対パス表現である必要があります。絶対パス(POSIX の `/...`、Windows の `\...``X:\...`)および `..` セグメントは `"format must not contain path traversal or absolute paths"` で拒否されます。
298+
- `filter_uuid` は Branch Output フィルターソースに解決される必要があります。他種別のソースや存在しない UUID は `"UUID does not refer to a Branch Output filter"` で拒否されます。
298299
- 録画遷移中(ファイル分割、リスタート)にリクエストを連続送信すると、遷移完了までリクエストがブロックされることがあります。
299300

301+
### クライアント側スロットリング
302+
303+
プラグインは `override_recording_filename_format` および `override_replay_buffer_filename_format` に対して**レート制限を行いません**。録画中に `format` が異なるリクエストを受けるたびに、ファイル分割または録画リスタートが発生する可能性があるため、録画側が落ち着くより速く更新を投げ続けるクライアントはファイルを断片化させ、エンコーダパイプラインに負荷をかけます。
304+
305+
同梱の OBS スクリプト([スロットリング](#recording-filename-from-text)を参照)は同一値を重複排除し、異なる `format` ごとに 30 秒に最大 1 回までの更新に制限しています。vendor request はこのスクリプトを経由しないため、obs-websocket 経由で操作する場合はこのガードを迂回します。**クライアント側で同等のスロットリングを実装してください** — 最低限、同一の `format` 値を抑制し、異なる更新もレート制限してください(30 秒以上を出発点とし、ファイル分割・リスタートの許容度に合わせて調整してください)。
306+
300307
### `get_filter_list`
301308

302309
現在 OBS にロードされている Branch Output フィルター一覧を列挙します。

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/obs-websocket/lib/obs-websocket-a
3838
message(FATAL_ERROR "lib/obs-websocket submodule not found. Run: git submodule update --init --recursive")
3939
endif()
4040

41-
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib/obs-websocket/lib)
41+
target_include_directories(${CMAKE_PROJECT_NAME} SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib/obs-websocket/lib)
4242

4343
target_sources(
4444
${CMAKE_PROJECT_NAME}

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,14 @@ See the [API reference](./API.md) for procedure signatures, sample code, and usa
125125

126126
This plugin is developed under [obs-plugintemplate](https://github.com/obsproject/obs-plugintemplate)
127127

128+
## Prerequisites
129+
130+
This repository depends on the [obs-websocket](https://github.com/obsproject/obs-websocket) headers, which are included
131+
as a Git submodule under `lib/obs-websocket`. After cloning, initialize the submodule before configuring the build:
132+
133+
```bash
134+
git submodule update --init --recursive
135+
```
136+
137+
If you cloned with `--recurse-submodules`, this step is unnecessary.
138+

README_ja.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,13 @@ Branch Output は、外部スクリプトから実行時にストリーム録画
127127

128128
This plugin is developed under [obs-plugintemplate](https://github.com/obsproject/obs-plugintemplate)
129129

130+
## 事前準備
131+
132+
本リポジトリは [obs-websocket](https://github.com/obsproject/obs-websocket) のヘッダに依存しており、`lib/obs-websocket` 配下に Git サブモジュールとして含まれています。クローン後、ビルド設定の前にサブモジュールを初期化してください。
133+
134+
```bash
135+
git submodule update --init --recursive
136+
```
137+
138+
`--recurse-submodules` 付きでクローンした場合は、この手順は不要です。
139+

build-aux/.run-format.zsh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ invoke_formatter() {
7070

7171
local -a source_files=(**/(CMakeLists.txt|*.cmake)(.N))
7272
source_files=(${source_files:#(build_*)/*})
73-
source_files=(${source_files:#lib/*})
73+
# Exclude vendored submodules under lib/ from cmake-format (nested paths included)
74+
source_files=(${source_files:#lib/**/*})
7475

7576
local -a format_args=()
7677
if (( _loglevel > 2 )) format_args+=(--log-level debug)

build.ps1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ $ProductVersion = $BuildSpec.version
88

99
$OutputName = "${ProductName}-${ProductVersion}-windows-x64"
1010

11+
if (-not (Test-Path "lib/obs-websocket/lib/obs-websocket-api.h")) {
12+
git submodule update --init --recursive lib/obs-websocket
13+
if (-not $?) { exit 1 }
14+
}
15+
1116
cmake --fresh -S . -B build_x64 -Wdev -Wdeprecated -DCMAKE_SYSTEM_VERSION="10.0.18363.657" -G "Visual Studio 17 2022" -A x64
1217
cmake --build build_x64 --config RelWithDebInfo --target ALL_BUILD --
1318
cmake --install build_x64 --prefix release/Package --config RelWithDebInfo

cmake/linux/defaults.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(CPACK_SOURCE_IGNORE_FILES
3434
\\.git/
3535
\\.github/
3636
\\.gitignore
37+
\\.gitmodules
3738
build_.*
3839
cmake/\\.CMakeBuildNumber
3940
release/)

0 commit comments

Comments
 (0)