From 3d2544b22d96e3ad0c3d28303c235dc85245c345 Mon Sep 17 00:00:00 2001 From: Yuri Chukhlib Date: Sun, 23 Aug 2026 12:22:00 +0200 Subject: [PATCH] Fix deep link timestamp parsing accepting infinity as seek position (#965) URLRouter.parseTimestampValue used TimeInterval(_:) for the plain-numeric branch ("90", "90.5"). That initializer also accepts the special tokens "inf"/"infinity" and "nan", and the value infinity compares as >= 0, so a deep link or share URL carrying ?t=inf parsed to Double.infinity and was forwarded to the player as a seek target. Seeking to infinity is undefined and breaks playback startup for the affected link. Reject non-finite values explicitly alongside the existing negative check, so only finite non-negative seconds are accepted. - Add isFinite guard to the plain-numeric branch of parseTimestampValue - Cover inf/infinity/nan/negative rejection in URLRouterTests --- Yattee/Services/Navigation/URLRouter.swift | 6 ++++-- YatteeTests/NavigationTests.swift | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Yattee/Services/Navigation/URLRouter.swift b/Yattee/Services/Navigation/URLRouter.swift index 98c9e45f..f3836d7d 100644 --- a/Yattee/Services/Navigation/URLRouter.swift +++ b/Yattee/Services/Navigation/URLRouter.swift @@ -145,9 +145,11 @@ struct URLRouter: Sendable { let trimmed = raw.trimmingCharacters(in: .whitespaces) guard !trimmed.isEmpty else { return nil } - // Plain numeric value (e.g. "90", "90.5") + // Plain numeric value (e.g. "90", "90.5"). Reject non-finite values + // ("inf"/"infinity"/"nan") that `TimeInterval(_:)` accepts — a `?t=inf` + // link would otherwise seek the player to `Double.infinity`. if let value = TimeInterval(trimmed) { - return value >= 0 ? value : nil + return (value.isFinite && value >= 0) ? value : nil } // Compound form like "1h2m3s", "2m30s", "90s" diff --git a/YatteeTests/NavigationTests.swift b/YatteeTests/NavigationTests.swift index aa46c789..c0bcedb5 100644 --- a/YatteeTests/NavigationTests.swift +++ b/YatteeTests/NavigationTests.swift @@ -123,6 +123,20 @@ struct URLRouterTests { #expect(URLRouter.parseTimestampValue("90.5") == 90.5) } + @Test("Reject non-finite and negative plain timestamp values") + func rejectInvalidPlainTimestampValues() { + // Plain numeric values that are accepted by TimeInterval(_:) but are not + // valid seek targets must return nil rather than poisoning the player. + #expect(URLRouter.parseTimestampValue("inf") == nil) + #expect(URLRouter.parseTimestampValue("infinity") == nil) + #expect(URLRouter.parseTimestampValue("nan") == nil) + #expect(URLRouter.parseTimestampValue("-5") == nil) + // Valid plain seconds still parse. + #expect(URLRouter.parseTimestampValue("0") == 0) + #expect(URLRouter.parseTimestampValue("90") == 90) + #expect(URLRouter.parseTimestampValue("90.5") == 90.5) + } + // MARK: - Share Extension Wrapper Tests @Test("Unwrap yattee://open wrapper to inner URL with timestamp")