diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md index c3cc16472d7d..a15e0499182c 100644 --- a/ios/CHANGELOG.md +++ b/ios/CHANGELOG.md @@ -24,6 +24,7 @@ Line wrap the file at 100 chars. Th ## Unreleased ### Added - Add a new access method that uses the encrypted DNS proxy to reach our API. +- Fix IPv6 parsing in API access ## [2024.7 - 2024-09-16] ### Added diff --git a/ios/MullvadTypes/AnyIPAddress.swift b/ios/MullvadTypes/AnyIPAddress.swift index ca88f73632f8..0bfb9fa2d88f 100644 --- a/ios/MullvadTypes/AnyIPAddress.swift +++ b/ios/MullvadTypes/AnyIPAddress.swift @@ -69,6 +69,10 @@ public enum AnyIPAddress: IPAddress, Codable, Equatable, CustomDebugStringConver } public init?(_ string: String) { + // Arbitrary integers should not be allowed by us and need to be handled separately + // since Apple allows them. + guard Int(string) == nil else { return nil } + if let ipv4Address = IPv4Address(string) { self = .ipv4(ipv4Address) } else if let ipv6Address = IPv6Address(string) { diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index ee362edf09b2..0749e4373149 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -609,6 +609,7 @@ 7AEF7F1A2AD00F52006FE45D /* AppMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */; }; 7AF10EB22ADE859200C090B9 /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF10EB12ADE859200C090B9 /* AlertViewController.swift */; }; 7AF10EB42ADE85BC00C090B9 /* RelayFilterCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF10EB32ADE85BC00C090B9 /* RelayFilterCoordinator.swift */; }; + 7AF36A9A2CA2964200E1D497 /* AnyIPAddressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF36A992CA2964000E1D497 /* AnyIPAddressTests.swift */; }; 7AF6E5F02A95051E00F2679D /* RouterBlockDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF6E5EF2A95051E00F2679D /* RouterBlockDelegate.swift */; }; 7AF9BE882A30C62100DBFEDB /* SelectableSettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1A264A2A29D65E00B978AA /* SelectableSettingsCell.swift */; }; 7AF9BE8C2A321D1F00DBFEDB /* RelayFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF9BE8A2A321BEF00DBFEDB /* RelayFilter.swift */; }; @@ -1918,6 +1919,7 @@ 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppMessageHandler.swift; sourceTree = ""; }; 7AF10EB12ADE859200C090B9 /* AlertViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = ""; }; 7AF10EB32ADE85BC00C090B9 /* RelayFilterCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelayFilterCoordinator.swift; sourceTree = ""; }; + 7AF36A992CA2964000E1D497 /* AnyIPAddressTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyIPAddressTests.swift; sourceTree = ""; }; 7AF6E5EF2A95051E00F2679D /* RouterBlockDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterBlockDelegate.swift; sourceTree = ""; }; 7AF9BE8A2A321BEF00DBFEDB /* RelayFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayFilter.swift; sourceTree = ""; }; 7AF9BE8D2A331C7B00DBFEDB /* RelayFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayFilterViewModel.swift; sourceTree = ""; }; @@ -2482,6 +2484,7 @@ 440E9EF92BDA95FC00B1FD11 /* MullvadTypes */ = { isa = PBXGroup; children = ( + 7AF36A992CA2964000E1D497 /* AnyIPAddressTests.swift */, 58FBFBF0291630700020E046 /* DurationTests.swift */, 58C3FA672A385C89006A450A /* FileCacheTests.swift */, 582A8A3928BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift */, @@ -5288,6 +5291,7 @@ A9A5FA3F2ACB05D90083449F /* DeviceCheckRemoteService.swift in Sources */, A9A5FA402ACB05D90083449F /* DeviceCheckRemoteServiceProtocol.swift in Sources */, A9A5FA412ACB05D90083449F /* DeviceStateAccessor.swift in Sources */, + 7AF36A9A2CA2964200E1D497 /* AnyIPAddressTests.swift in Sources */, A9A5FA422ACB05D90083449F /* DeviceStateAccessorProtocol.swift in Sources */, 7A5869C32B5820CE00640D27 /* IPOverrideRepositoryTests.swift in Sources */, A9A5FA392ACB05910083449F /* UIColor+Palette.swift in Sources */, diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift index 4ad1cea25b71..99fa9daa99c3 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift @@ -216,8 +216,7 @@ private enum CommonValidators { return .success(portNumber) } - /// Parse IP address from string by first running the input via regular expression before parsing it using Apple's facilities which are known to accept all kind of - /// malformed input. + /// Parse IP address from string by using Apple's facilities. /// /// - Parameters: /// - value: a string input. @@ -227,12 +226,7 @@ private enum CommonValidators { from value: String, context: AccessMethodFieldValidationError.Context ) -> Result { - let range = NSRange(value.startIndex ..< value.endIndex, in: value) - - let regexMatch = NSRegularExpression.ipv4RegularExpression.firstMatch(in: value, range: range) - ?? NSRegularExpression.ipv6RegularExpression.firstMatch(in: value, range: range) - - if regexMatch?.range == range, let address = AnyIPAddress(value) { + if let address = AnyIPAddress(value) { return .success(address) } else { return .failure(AccessMethodFieldValidationError(kind: .invalidIPAddress, field: .server, context: context)) diff --git a/ios/MullvadVPNTests/MullvadTypes/AnyIPAddressTests.swift b/ios/MullvadVPNTests/MullvadTypes/AnyIPAddressTests.swift new file mode 100644 index 000000000000..aa4c106fa8f3 --- /dev/null +++ b/ios/MullvadVPNTests/MullvadTypes/AnyIPAddressTests.swift @@ -0,0 +1,33 @@ +// +// AnyIPAddressTests.swift +// MullvadVPN +// +// Created by Jon Petersson on 2024-09-24. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +@testable import MullvadTypes +import XCTest + +final class AnyIPAddressTests: XCTestCase { + func testAnyIPAddressFromString() { + XCTAssertNil(AnyIPAddress("000")) + XCTAssertNil(AnyIPAddress("1")) + XCTAssertNil(AnyIPAddress("abcde")) + XCTAssertNil(AnyIPAddress("0.1.2.3.5")) + XCTAssertNil(AnyIPAddress("2a03:1b20:1:f011:bb09")) + + XCTAssertNotNil(AnyIPAddress("0.0")) + XCTAssertNotNil(AnyIPAddress("0.1")) + XCTAssertNotNil(AnyIPAddress("192.168.0.1")) + XCTAssertNotNil(AnyIPAddress("2a03:1b20:1:f011::bb09")) + XCTAssertNotNil(AnyIPAddress("FE80:0000:0000:0000:0202:B3FF:FE1E:8329")) + XCTAssertNotNil(AnyIPAddress("2001:db8::42:0:8a2e:370:7334")) + XCTAssertNotNil(AnyIPAddress("::1")) + XCTAssertNotNil(AnyIPAddress("::")) + XCTAssertNotNil(AnyIPAddress("::ffff:192.168.1.1")) + XCTAssertNotNil(AnyIPAddress("fe80::1ff:fe23:4567:890a")) + XCTAssertNotNil(AnyIPAddress("ff02::1")) + XCTAssertNotNil(AnyIPAddress("2001:0db8:85a3::8a2e:0370:7334")) + } +}