Files
XC_VM/tests/Unit/SecretMatchesTest.php
T
rootandClaude Opus 5 aa334de92f fix(auth): compare shared secrets strictly and in constant time
The internal API (LB -> main), the admin live/vod/timeshift proxies, the
admin API and RTMP publish/play checked their shared secrets —
live_streaming_pass, api_pass, the RTMP allow-list passwords — with ==.
That compares two numeric-looking strings as numbers ("1000" == "1e3") and
stops at the first differing byte, which a patient client can time.

They now go through AuthService::secretMatches(): hash_equals on strings,
false for anything a query string can make that is not one (null, an array),
and false for a secret that is not configured. Each caller keeps its own
"no secret required" rule (an empty api_pass, an allow-list entry with no
password), exactly as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EuZvjFSdodqgpyXtaoH1Xt
2026-09-12 22:42:10 +00:00

34 lines
1.4 KiB
PHP

<?php
namespace XcVm\Tests\Unit;
use PHPUnit\Framework\TestCase;
use XcVm\Core\Auth\AuthService;
/**
* The internal API, the admin stream proxies and RTMP authenticate with shared
* secrets. == compared them: loosely (two numeric-looking strings compare as
* numbers) and byte by byte until the first difference.
*/
class SecretMatchesTest extends TestCase {
public function testTheSameSecretMatches(): void {
$this->assertTrue(AuthService::secretMatches('Xk29fQ0pLmN7', 'Xk29fQ0pLmN7'));
$this->assertTrue(AuthService::secretMatches(12345, '12345'), 'a numeric setting read back as an int');
}
public function testNumbersThatAreEqualAreNotTheSameSecret(): void {
$this->assertFalse(AuthService::secretMatches('1000', '1e3'));
$this->assertFalse(AuthService::secretMatches('0e1111', '0e2222'));
$this->assertFalse(AuthService::secretMatches('10', '010'));
}
public function testAnythingElseDoesNotMatch(): void {
$this->assertFalse(AuthService::secretMatches('secret', 'Secret'));
$this->assertFalse(AuthService::secretMatches('secret', ''));
$this->assertFalse(AuthService::secretMatches('secret', null));
$this->assertFalse(AuthService::secretMatches('secret', ['secret']), 'password[]=secret');
$this->assertFalse(AuthService::secretMatches('', ''), 'no secret configured matches nothing');
$this->assertFalse(AuthService::secretMatches(null, ''));
}
}