fix(security): redact Plex Home PIN from logs

This commit is contained in:
edde746
2026-07-02 11:41:25 +02:00
parent 72d37f2362
commit bfcd11538e
2 changed files with 21 additions and 0 deletions
+6
View File
@@ -24,6 +24,11 @@ class LogRedactionManager {
/// Pattern-based catch-all for Jellyfin Quick Connect auth handles.
static final RegExp _jellyfinQuickConnectSecretQueryParam = RegExp(r'secret=[^&#\s]+', caseSensitive: false);
/// Pattern-based catch-all for the Plex Home PIN sent as a `pin=` query
/// param by `/home/users/{uuid}/switch`. The `\b` keeps compound params
/// like `checkPin=` intact.
static final RegExp _pinQueryParam = RegExp(r'\bpin=[^&#\s]+', caseSensitive: false);
/// Pattern-based catch-all for the legacy Emby/Jellyfin header form.
static final RegExp _embyTokenHeader = RegExp(r'X-Emby-Token[:=]\s*[^,;&#\s"]+', caseSensitive: false);
@@ -120,6 +125,7 @@ class LogRedactionManager {
redacted = redacted.replaceAll(_jellyfinApiKeyQueryParam, 'api_key=[REDACTED]');
redacted = redacted.replaceAll(_jellyfinQuickConnectSecretQueryParam, 'secret=[REDACTED]');
redacted = redacted.replaceAll(_pinQueryParam, 'pin=[REDACTED]');
redacted = redacted.replaceAllMapped(_embyTokenHeader, (m) {
final value = m.group(0)!;
final separator = value.contains(':') ? ':' : '=';
@@ -60,6 +60,21 @@ void main() {
expect(result.contains('Authenticated=false'), isTrue);
});
test('redacts Plex Home pin query parameter without registration', () {
final input = 'POST https://clients.plex.tv/api/v2/home/users/uuid/switch?X-Plex-Token=tok&pin=1234 → 201';
final result = LogRedactionManager.redact(input);
expect(result.contains('pin=1234'), isFalse);
expect(result.contains('pin=[REDACTED]'), isTrue);
});
test('pin redaction is case-insensitive and leaves compound params intact', () {
final result = LogRedactionManager.redact('PIN=0000&checkPin=abc&next=1');
expect(result.contains('PIN=0000'), isFalse);
expect(result.contains('pin=[REDACTED]'), isTrue);
expect(result.contains('checkPin=abc'), isTrue);
expect(result.contains('next=1'), isTrue);
});
test('redacts X-Emby-Token header form', () {
final result = LogRedactionManager.redact('X-Emby-Token: emby-secret');
expect(result.contains('emby-secret'), isFalse);