Skip to content

Commit 36402dc

Browse files
matteiusclaude
andcommitted
Address Copilot review: sub-stream with override, length validation, log level
- Sub-stream registration no longer bypassed when main stream has go2rtc_source_override — all three registration paths (register_all, sync_from_database, register_stream) now skip only the main stream API call while still registering {name}_sub via API - Validate go2rtc_config_override length on save (reject >= 4096 bytes) - Downgrade full config file dump from INFO to DEBUG to avoid leaking credentials from overrides into production logs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 10973a3 commit 36402dc

3 files changed

Lines changed: 80 additions & 79 deletions

File tree

src/video/go2rtc/go2rtc_integration.c

Lines changed: 72 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,29 +1355,28 @@ bool go2rtc_integration_register_all_streams(void) {
13551355
bool all_success = true;
13561356
for (int i = 0; i < count; i++) {
13571357
if (streams[i].enabled) {
1358-
// Skip streams with go2rtc source override — they are already
1359-
// defined in the go2rtc.yaml config file and don't need API registration.
1358+
// Skip main stream API registration when go2rtc source override is set —
1359+
// the main stream is already defined in go2rtc.yaml.
1360+
// Sub-stream registration still proceeds via API regardless.
13601361
if (streams[i].go2rtc_source_override[0] != '\0') {
1361-
log_info("Skipping API registration for stream %s (has go2rtc source override)", streams[i].name);
1362-
continue;
1363-
}
1364-
1365-
log_info("Registering stream %s with go2rtc", streams[i].name);
1366-
1367-
// Register the stream with go2rtc
1368-
if (!go2rtc_stream_register(streams[i].name, streams[i].url,
1369-
streams[i].onvif_username[0] != '\0' ? streams[i].onvif_username : NULL,
1370-
streams[i].onvif_password[0] != '\0' ? streams[i].onvif_password : NULL,
1371-
streams[i].backchannel_enabled, streams[i].protocol,
1372-
streams[i].record_audio)) {
1373-
log_error("Failed to register stream %s with go2rtc", streams[i].name);
1374-
all_success = false;
1375-
// Continue with other streams
1362+
log_info("Skipping main stream API registration for %s (has go2rtc source override)", streams[i].name);
13761363
} else {
1377-
log_info("Successfully registered stream %s with go2rtc", streams[i].name);
1364+
log_info("Registering stream %s with go2rtc", streams[i].name);
1365+
1366+
if (!go2rtc_stream_register(streams[i].name, streams[i].url,
1367+
streams[i].onvif_username[0] != '\0' ? streams[i].onvif_username : NULL,
1368+
streams[i].onvif_password[0] != '\0' ? streams[i].onvif_password : NULL,
1369+
streams[i].backchannel_enabled, streams[i].protocol,
1370+
streams[i].record_audio)) {
1371+
log_error("Failed to register stream %s with go2rtc", streams[i].name);
1372+
all_success = false;
1373+
} else {
1374+
log_info("Successfully registered stream %s with go2rtc", streams[i].name);
1375+
}
13781376
}
13791377

1380-
// Register sub-stream if configured (low-res for grid view)
1378+
// Register sub-stream if configured (low-res for grid view) —
1379+
// always via API, even when main stream uses config override.
13811380
if (streams[i].sub_stream_url[0] != '\0') {
13821381
char sub_name[MAX_STREAM_NAME + 8];
13831382
snprintf(sub_name, sizeof(sub_name), "%s_sub", streams[i].name);
@@ -1454,23 +1453,7 @@ bool go2rtc_sync_streams_from_database(void) {
14541453
skipped++;
14551454
continue;
14561455
}
1457-
if (db_streams[i].go2rtc_source_override[0] != '\0') {
1458-
log_debug("Skipping API sync for stream %s (has go2rtc source override)", db_streams[i].name);
1459-
skipped++;
1460-
continue;
1461-
}
1462-
1463-
// Check if stream already exists in go2rtc
1464-
if (go2rtc_api_stream_exists(db_streams[i].name)) {
1465-
log_debug("Stream %s already exists in go2rtc, skipping", db_streams[i].name);
1466-
skipped++;
1467-
continue;
1468-
}
1469-
1470-
// Stream needs to be registered
1471-
log_info("Registering missing stream %s with go2rtc", db_streams[i].name);
1472-
1473-
// Determine username and password
1456+
// Determine username and password (needed for both main and sub-stream)
14741457
const char *username = NULL;
14751458
const char *password = NULL;
14761459

@@ -1481,20 +1464,33 @@ bool go2rtc_sync_streams_from_database(void) {
14811464
password = db_streams[i].onvif_password;
14821465
}
14831466

1484-
// Register the stream
1485-
if (!go2rtc_stream_register(db_streams[i].name, db_streams[i].url,
1486-
username, password,
1487-
db_streams[i].backchannel_enabled, db_streams[i].protocol,
1488-
db_streams[i].record_audio)) {
1489-
log_error("Failed to register stream %s with go2rtc", db_streams[i].name);
1490-
all_success = false;
1491-
failed++;
1467+
// Skip main stream API sync when override is set (defined in go2rtc.yaml),
1468+
// but still fall through to sub-stream registration below.
1469+
if (db_streams[i].go2rtc_source_override[0] != '\0') {
1470+
log_debug("Skipping main stream API sync for %s (has go2rtc source override)", db_streams[i].name);
1471+
skipped++;
1472+
} else if (go2rtc_api_stream_exists(db_streams[i].name)) {
1473+
log_debug("Stream %s already exists in go2rtc, skipping", db_streams[i].name);
1474+
skipped++;
14921475
} else {
1493-
log_info("Successfully synced stream %s to go2rtc", db_streams[i].name);
1494-
synced++;
1476+
// Stream needs to be registered
1477+
log_info("Registering missing stream %s with go2rtc", db_streams[i].name);
1478+
1479+
if (!go2rtc_stream_register(db_streams[i].name, db_streams[i].url,
1480+
username, password,
1481+
db_streams[i].backchannel_enabled, db_streams[i].protocol,
1482+
db_streams[i].record_audio)) {
1483+
log_error("Failed to register stream %s with go2rtc", db_streams[i].name);
1484+
all_success = false;
1485+
failed++;
1486+
} else {
1487+
log_info("Successfully synced stream %s to go2rtc", db_streams[i].name);
1488+
synced++;
1489+
}
14951490
}
14961491

1497-
// Register sub-stream if configured
1492+
// Register sub-stream if configured — always via API,
1493+
// even when main stream uses config override.
14981494
if (db_streams[i].sub_stream_url[0] != '\0') {
14991495
char sub_name[MAX_STREAM_NAME + 8];
15001496
snprintf(sub_name, sizeof(sub_name), "%s_sub", db_streams[i].name);
@@ -1810,22 +1806,16 @@ bool go2rtc_integration_register_stream(const char *stream_name) {
18101806
return false;
18111807
}
18121808

1813-
// Check for go2rtc source override — these streams are defined in go2rtc.yaml
1814-
// and don't need API registration
1815-
{
1816-
stream_config_t check_config;
1817-
if (get_stream_config(stream, &check_config) == 0 && check_config.go2rtc_source_override[0] != '\0') {
1818-
log_info("Stream %s has go2rtc source override, skipping API registration", stream_name);
1819-
return true;
1820-
}
1821-
}
1822-
18231809
stream_config_t config;
18241810
if (get_stream_config(stream, &config) != 0) {
18251811
log_error("Failed to get config for stream %s", stream_name);
18261812
return false;
18271813
}
18281814

1815+
// Check for go2rtc source override — main stream is defined in go2rtc.yaml
1816+
// and doesn't need API registration, but sub-stream still needs it.
1817+
bool skip_main = (config.go2rtc_source_override[0] != '\0');
1818+
18291819
// Determine username and password
18301820
// Priority: 1) onvif fields, 2) extracted from URL
18311821
char username[64] = {0};
@@ -1865,29 +1855,36 @@ bool go2rtc_integration_register_stream(const char *stream_name) {
18651855
}
18661856
}
18671857

1868-
// Register with go2rtc
1869-
if (go2rtc_stream_register(stream_name, config.url,
1870-
username[0] != '\0' ? username : NULL,
1871-
password[0] != '\0' ? password : NULL,
1872-
config.backchannel_enabled, config.protocol,
1873-
config.record_audio)) {
1874-
log_info("Successfully registered stream %s with go2rtc", stream_name);
1875-
1876-
// Register sub-stream if configured
1877-
if (config.sub_stream_url[0] != '\0') {
1878-
char sub_name[MAX_STREAM_NAME + 8];
1879-
snprintf(sub_name, sizeof(sub_name), "%s_sub", stream_name);
1880-
log_info("Registering sub-stream %s with go2rtc", sub_name);
1881-
go2rtc_stream_register(sub_name, config.sub_stream_url,
1858+
// Register main stream with go2rtc (skip if override is set — defined in YAML)
1859+
bool main_ok = true;
1860+
if (skip_main) {
1861+
log_info("Stream %s has go2rtc source override, skipping main API registration", stream_name);
1862+
} else {
1863+
if (go2rtc_stream_register(stream_name, config.url,
18821864
username[0] != '\0' ? username : NULL,
18831865
password[0] != '\0' ? password : NULL,
1884-
false, config.protocol, false);
1866+
config.backchannel_enabled, config.protocol,
1867+
config.record_audio)) {
1868+
log_info("Successfully registered stream %s with go2rtc", stream_name);
1869+
} else {
1870+
log_warn("Failed to register stream %s with go2rtc", stream_name);
1871+
main_ok = false;
18851872
}
1886-
return true;
18871873
}
18881874

1889-
log_warn("Failed to register stream %s with go2rtc", stream_name);
1890-
return false;
1875+
// Register sub-stream if configured — always via API,
1876+
// even when main stream uses config override.
1877+
if (config.sub_stream_url[0] != '\0') {
1878+
char sub_name[MAX_STREAM_NAME + 8];
1879+
snprintf(sub_name, sizeof(sub_name), "%s_sub", stream_name);
1880+
log_info("Registering sub-stream %s with go2rtc", sub_name);
1881+
go2rtc_stream_register(sub_name, config.sub_stream_url,
1882+
username[0] != '\0' ? username : NULL,
1883+
password[0] != '\0' ? password : NULL,
1884+
false, config.protocol, false);
1885+
}
1886+
1887+
return main_ok || skip_main;
18911888
}
18921889

18931890
// ============================================================================

src/video/go2rtc/go2rtc_process.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -783,18 +783,19 @@ bool go2rtc_process_generate_config(const char *config_path, int api_port) {
783783
fclose(config_file);
784784
log_info("Generated go2rtc configuration file: %s", config_path);
785785

786-
// Print the content of the config file for debugging
786+
// Print the content of the config file at DEBUG level to avoid
787+
// leaking credentials from overrides into production logs.
787788
FILE *read_file = fopen(config_path, "r");
788789
if (read_file) {
789790
char line[256];
790-
log_info("Contents of go2rtc config file:");
791+
log_debug("Contents of go2rtc config file:");
791792
while (fgets(line, sizeof(line), read_file)) {
792793
// Remove newline character
793794
size_t len = strlen(line);
794795
if (len > 0 && line[len-1] == '\n') {
795796
line[len-1] = '\0';
796797
}
797-
log_info(" %s", line);
798+
log_debug(" %s", line);
798799
}
799800
fclose(read_file);
800801
}

src/web/api_handlers_settings.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -963,7 +963,10 @@ void handle_post_settings(const http_request_t *req, http_response_t *res) {
963963
// go2rtc global config override (stored in system_settings)
964964
cJSON *go2rtc_config_override = cJSON_GetObjectItem(settings, "go2rtc_config_override");
965965
if (go2rtc_config_override && cJSON_IsString(go2rtc_config_override)) {
966-
if (db_set_system_setting("go2rtc_config_override", go2rtc_config_override->valuestring) != 0) {
966+
size_t override_len = strlen(go2rtc_config_override->valuestring);
967+
if (override_len >= 4096) {
968+
log_error("go2rtc_config_override too long (%zu bytes, max 4095)", override_len);
969+
} else if (db_set_system_setting("go2rtc_config_override", go2rtc_config_override->valuestring) != 0) {
967970
log_error("Failed to save go2rtc_config_override to system_settings");
968971
} else {
969972
log_info("Updated go2rtc_config_override");

0 commit comments

Comments
 (0)