Skip to content

Commit

Permalink
Add tests for AppMessageHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Petersson committed Oct 11, 2023
1 parent d3a2fad commit 8e2a40f
Show file tree
Hide file tree
Showing 19 changed files with 335 additions and 98 deletions.
42 changes: 32 additions & 10 deletions ios/MullvadVPN.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,9 @@ enum SetAccountAction {

var taskName: String {
switch self {
case .new:
return "Set new account"
case .existing:
return "Set existing account"
case .unset:
return "Unset account"
case .new: "Set new account"
case .existing: "Set existing account"
case .unset: "Unset account"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadVPN/TunnelManager/TunnelManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ final class TunnelManager: StorePaymentObserver {
finish(result.error)
}
} catch {
if let error = error as? NoRelaysSatisfyingConstraintsError {
if error is NoRelaysSatisfyingConstraintsError {
_ = self.setTunnelStatus { tunnelStatus in
tunnelStatus.state = .error(.noRelaysSatisfyingConstraints)
}
Expand Down
13 changes: 7 additions & 6 deletions ios/MullvadVPNTests/ServerRelaysResponse+Stubs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Foundation
@testable import MullvadREST
import WireGuardKitTypes

enum ServerRelaysResponseStubs {
static let portRanges: [[UInt16]] = [[4000, 4001], [5000, 5001]]
Expand Down Expand Up @@ -77,7 +78,7 @@ enum ServerRelaysResponseStubs {
weight: 500,
ipv4AddrIn: .loopback,
ipv6AddrIn: .loopback,
publicKey: Data(),
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true
),
REST.ServerRelay(
Expand All @@ -89,7 +90,7 @@ enum ServerRelaysResponseStubs {
weight: 1000,
ipv4AddrIn: .loopback,
ipv6AddrIn: .loopback,
publicKey: Data(),
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true
),
REST.ServerRelay(
Expand All @@ -101,7 +102,7 @@ enum ServerRelaysResponseStubs {
weight: 50,
ipv4AddrIn: .loopback,
ipv6AddrIn: .loopback,
publicKey: Data(),
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true
),
REST.ServerRelay(
Expand All @@ -113,7 +114,7 @@ enum ServerRelaysResponseStubs {
weight: 100,
ipv4AddrIn: .loopback,
ipv6AddrIn: .loopback,
publicKey: Data(),
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true
),
REST.ServerRelay(
Expand All @@ -125,7 +126,7 @@ enum ServerRelaysResponseStubs {
weight: 100,
ipv4AddrIn: .loopback,
ipv6AddrIn: .loopback,
publicKey: Data(),
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true
),
REST.ServerRelay(
Expand All @@ -137,7 +138,7 @@ enum ServerRelaysResponseStubs {
weight: 100,
ipv4AddrIn: .loopback,
ipv6AddrIn: .loopback,
publicKey: Data(),
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true
),
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public struct BlockedStateErrorMapper: BlockedStateErrorMapperProtocol {
// packet tunnel provider.
return .tunnelAdapter

case is PublicKeyError:
// Returned when there is an endpoint but its public key is invalid.
return .invalidPublicKey

default:
// Everything else in case we introduce new errors and forget to handle them.
return .unknown
Expand Down
57 changes: 0 additions & 57 deletions ios/PacketTunnel/PacketTunnelProvider/State+Extensions.swift

This file was deleted.

29 changes: 22 additions & 7 deletions ios/PacketTunnelCore/Actor/ConfigurationBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,44 @@ import struct WireGuardKitTypes.IPAddressRange
import class WireGuardKitTypes.PrivateKey
import class WireGuardKitTypes.PublicKey

/// Error returned when there is an endpoint but its public key is invalid.
public struct PublicKeyError: LocalizedError {
let endpoint: MullvadEndpoint

public var errorDescription: String? {
"Public key is invalid, endpoint: \(endpoint)"
}
}

/// Struct building tunnel adapter configuration.
struct ConfigurationBuilder {
var privateKey: PrivateKey
var interfaceAddresses: [IPAddressRange]
var dns: SelectedDNSServers?
var endpoint: MullvadEndpoint?

func makeConfiguration() -> TunnelAdapterConfiguration {
func makeConfiguration() throws -> TunnelAdapterConfiguration {
return TunnelAdapterConfiguration(
privateKey: privateKey,
interfaceAddresses: interfaceAddresses,
dns: dnsServers,
peer: peer
peer: try peer
)
}

private var peer: TunnelPeer? {
guard let endpoint else { return nil }
get throws {
guard let endpoint else { return nil }

return TunnelPeer(
endpoint: .ipv4(endpoint.ipv4Relay),
publicKey: PublicKey(rawValue: endpoint.publicKey)!
)
guard let publicKey = PublicKey(rawValue: endpoint.publicKey) else {
throw PublicKeyError(endpoint: endpoint)
}

return TunnelPeer(
endpoint: .ipv4(endpoint.ipv4Relay),
publicKey: publicKey
)
}
}

private var dnsServers: [IPAddress] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ extension PacketTunnelActor {
/**
Internal helper that transitions key policy from `.usePrior` to `.useCurrent`.

- Parameter keyPolicy: a reference to key policy hend either in connection state or blocked state struct.
- Parameter keyPolicy: a reference to key policy held either in connection state or blocked state struct.
- Returns: `true` when the policy was modified, otherwise `false`.
*/
private func setCurrentKeyPolicy(_ keyPolicy: inout KeyPolicy) -> Bool {
Expand Down
2 changes: 2 additions & 0 deletions ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,5 @@ extension PacketTunnelActor {
}
}
}

extension PacketTunnelActor: PacketTunnelActorProtocol {}
16 changes: 16 additions & 0 deletions ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// PacketTunnelActorProtocol.swift
// PacketTunnelCoreTests
//
// Created by Jon Petersson on 2023-10-11.
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
//

import Foundation

public protocol PacketTunnelActorProtocol {
var state: State { get async }

func reconnect(to nextRelay: NextRelay)
func notifyKeyRotation(date: Date?)
}
47 changes: 46 additions & 1 deletion ios/PacketTunnelCore/Actor/State+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import MullvadTypes
import class WireGuardKitTypes.PrivateKey

extension State {
Expand Down Expand Up @@ -36,6 +37,50 @@ extension State {
}
}

var packetTunnelStatus: PacketTunnelStatus {
var status = PacketTunnelStatus()

switch self {
case let .connecting(connState),
let .connected(connState),
let .reconnecting(connState),
let .disconnecting(connState):
switch connState.networkReachability {
case .reachable:
status.isNetworkReachable = true
case .unreachable:
status.isNetworkReachable = false
case .undetermined:
// TODO: fix me
status.isNetworkReachable = true
}

status.numberOfFailedAttempts = connState.connectionAttemptCount
status.tunnelRelay = connState.selectedRelay.packetTunnelRelay

case .disconnected, .initial:
break

case let .error(blockedState):
status.blockedStateReason = blockedState.reason
}

return status
}

public var relayConstraints: RelayConstraints? {
switch self {
case let .connecting(connState), let .connected(connState), let .reconnecting(connState):
return connState.relayConstraints

case let .error(blockedState):
return blockedState.relayConstraints

case .initial, .disconnecting, .disconnected:
return nil
}
}

// MARK: - Logging

func logFormat() -> String {
Expand Down Expand Up @@ -105,7 +150,7 @@ extension BlockedStateReason {
return true

case .noRelaysSatisfyingConstraints, .readSettings, .invalidAccount, .deviceRevoked, .tunnelAdapter, .unknown,
.deviceLoggedOut, .outdatedSchema:
.deviceLoggedOut, .outdatedSchema, .invalidPublicKey:
return false
}
}
Expand Down
5 changes: 4 additions & 1 deletion ios/PacketTunnelCore/Actor/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public struct ConnectionState {
/// This is primarily used by packet tunnel for updating constraints in tunnel provider.
public var relayConstraints: RelayConstraints

/// Last WG key read from setings.
/// Last WG key read from settings.
/// Can be `nil` if moved to `keyPolicy`.
public var currentKey: PrivateKey?

Expand Down Expand Up @@ -192,6 +192,9 @@ public enum BlockedStateReason: String, Codable, Equatable {
/// Tunnel adapter error.
case tunnelAdapter

/// Invalid public key.
case invalidPublicKey

/// Unidentified reason.
case unknown
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@

import Foundation
import MullvadLogging
import PacketTunnelCore

/**
Actor handling packet tunnel IPC (app) messages and patching them through to the right facility.
*/
struct AppMessageHandler {
public struct AppMessageHandler {
private let logger = Logger(label: "AppMessageHandler")
private let packetTunnelActor: PacketTunnelActor
private let urlRequestProxy: URLRequestProxy
private let packetTunnelActor: PacketTunnelActorProtocol
private let urlRequestProxy: URLRequestProxyProtocol

init(packetTunnelActor: PacketTunnelActor, urlRequestProxy: URLRequestProxy) {
public init(packetTunnelActor: PacketTunnelActorProtocol, urlRequestProxy: URLRequestProxyProtocol) {
self.packetTunnelActor = packetTunnelActor
self.urlRequestProxy = urlRequestProxy
}
Expand All @@ -34,7 +33,7 @@ struct AppMessageHandler {
the acknowledgment from IPC before starting next operation, hence it's critical to return as soon as possible.
(See `TunnelManager.reconnectTunnel()`, `SendTunnelProviderMessageOperation`)
*/
func handleAppMessage(_ messageData: Data) async -> Data? {
public func handleAppMessage(_ messageData: Data) async -> Data? {
guard let message = decodeMessage(messageData) else { return nil }

logger.debug("Received app message: \(message)")
Expand All @@ -51,7 +50,7 @@ struct AppMessageHandler {
return await encodeReply(packetTunnelActor.state.packetTunnelStatus)

case .privateKeyRotation:
packetTunnelActor.notifyKeyRotation(date: nil)
packetTunnelActor.notifyKeyRotation(date: Date())
return nil

case let .reconnectTunnel(selectorResult):
Expand Down
2 changes: 2 additions & 0 deletions ios/PacketTunnelCore/URLRequestProxy/URLRequestProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ extension URLRequestProxy {
}
}
}

extension URLRequestProxy: URLRequestProxyProtocol {}
15 changes: 15 additions & 0 deletions ios/PacketTunnelCore/URLRequestProxy/URLRequestProxyProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// URLRequestProxyProtocol.swift
// PacketTunnelCore
//
// Created by Jon Petersson on 2023-10-11.
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
//

import Foundation

public protocol URLRequestProxyProtocol {
func sendRequest(_ proxyRequest: ProxyURLRequest, completionHandler: @escaping @Sendable (ProxyURLResponse) -> Void)
func sendRequest(_ proxyRequest: ProxyURLRequest) async -> ProxyURLResponse
func cancelRequest(identifier: UUID)
}
Loading

0 comments on commit 8e2a40f

Please sign in to comment.