diff --git a/bitchat/Utils/InputValidator.swift b/bitchat/Utils/InputValidator.swift index 468531f2..c2b2fb53 100644 --- a/bitchat/Utils/InputValidator.swift +++ b/bitchat/Utils/InputValidator.swift @@ -52,11 +52,13 @@ struct InputValidator { // MessageType/NoisePayloadType enums; keeping validator free of stale lists. /// Validates timestamp is reasonable (not too far in past or future) + /// BCH-01-011: Reduced from ±1 hour to ±5 minutes to limit replay attack window static func validateTimestamp(_ timestamp: Date) -> Bool { let now = Date() - let oneHourAgo = now.addingTimeInterval(-3600) - let oneHourFromNow = now.addingTimeInterval(3600) - return timestamp >= oneHourAgo && timestamp <= oneHourFromNow + // 5 minutes = 300 seconds (industry standard for replay protection) + let fiveMinutesAgo = now.addingTimeInterval(-300) + let fiveMinutesFromNow = now.addingTimeInterval(300) + return timestamp >= fiveMinutesAgo && timestamp <= fiveMinutesFromNow } } diff --git a/bitchatTests/InputValidatorTests.swift b/bitchatTests/InputValidatorTests.swift index 021d454a..0611fdc0 100644 --- a/bitchatTests/InputValidatorTests.swift +++ b/bitchatTests/InputValidatorTests.swift @@ -131,6 +131,7 @@ struct InputValidatorTests { } // MARK: - Timestamp Validation Tests + // BCH-01-011: Window reduced from ±1 hour to ±5 minutes @Test func currentTimestampIsValid() throws { let now = Date() @@ -138,31 +139,48 @@ struct InputValidatorTests { #expect(result == true) } - @Test func timestampWithinOneHourIsValid() throws { + @Test func timestampWithinFiveMinutesIsValid() throws { + // 2 minutes ago should be valid (within 5-minute window) + let twoMinutesAgo = Date().addingTimeInterval(-2 * 60) + let result = InputValidator.validateTimestamp(twoMinutesAgo) + #expect(result == true) + } + + @Test func timestampThirtyMinutesAgoIsInvalid() throws { + // BCH-01-011: 30 minutes is now outside the 5-minute window let thirtyMinutesAgo = Date().addingTimeInterval(-30 * 60) let result = InputValidator.validateTimestamp(thirtyMinutesAgo) - #expect(result == true) - } - - @Test func timestampTwoHoursAgoIsInvalid() throws { - let twoHoursAgo = Date().addingTimeInterval(-2 * 3600) - let result = InputValidator.validateTimestamp(twoHoursAgo) #expect(result == false) } - @Test func timestampTwoHoursInFutureIsInvalid() throws { - let twoHoursFromNow = Date().addingTimeInterval(2 * 3600) - let result = InputValidator.validateTimestamp(twoHoursFromNow) + @Test func timestampTenMinutesAgoIsInvalid() throws { + // 10 minutes is outside the 5-minute window + let tenMinutesAgo = Date().addingTimeInterval(-10 * 60) + let result = InputValidator.validateTimestamp(tenMinutesAgo) #expect(result == false) } - @Test func timestampAtOneHourBoundaryIsValid() throws { - // Just slightly within the one-hour window - let almostOneHourAgo = Date().addingTimeInterval(-3599) - let result = InputValidator.validateTimestamp(almostOneHourAgo) + @Test func timestampTenMinutesInFutureIsInvalid() throws { + // 10 minutes in future is outside the 5-minute window + let tenMinutesFromNow = Date().addingTimeInterval(10 * 60) + let result = InputValidator.validateTimestamp(tenMinutesFromNow) + #expect(result == false) + } + + @Test func timestampAtFiveMinuteBoundaryIsValid() throws { + // Just slightly within the five-minute window (299 seconds) + let almostFiveMinutesAgo = Date().addingTimeInterval(-299) + let result = InputValidator.validateTimestamp(almostFiveMinutesAgo) #expect(result == true) } + @Test func timestampJustOutsideFiveMinuteWindowIsInvalid() throws { + // Just outside the five-minute window (301 seconds) + let justOverFiveMinutesAgo = Date().addingTimeInterval(-301) + let result = InputValidator.validateTimestamp(justOverFiveMinutesAgo) + #expect(result == false) + } + // MARK: - Edge Cases @Test func singleCharacterStringIsAccepted() throws {