Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanitize location selection against remote locations #764

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

graeme
Copy link
Contributor

@graeme graeme commented Apr 5, 2024

Please review the release process for BrowserServicesKit here.

Required:

Task/Issue URL: https://app.asana.com/0/1203137811378537/1206773442486707/f
iOS PR: duckduckgo/iOS#2688
macOS PR:
What kind of version bump will this require?: Major

Optional:

Tech Design URL:
CC:

Description:

Steps to test this PR:
1.
1.

OS Testing:

  • iOS 14
  • iOS 15
  • iOS 16
  • macOS 10.15
  • macOS 11
  • macOS 12

Internal references:

Software Engineering Expectations
Technical Design Template

Copy link
Contributor

@diegoreymendez diegoreymendez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think direction is ok for helping us prevent issues, and I think this direction is great... but this is not recovery. Are we planning to follow up with proper recovery from failed registration / connection attempts?

PS: Just being extra cautious here since I'm the one asking for recovery - if we do add recovery, let's do a follow up PR to avoid this becoming huge / neverending etc. I'm happy to keep things separated.

@@ -1041,9 +993,6 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
}

settings.selectedServer = .endpoint(serverName)
if case .connected = connectionStatus {
try? await updateTunnelConfiguration(environment: settings.selectedEnvironment, serverSelectionMethod: .preferredServer(serverName: serverName), reassert: true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is actually changing behaviour. Why is it no longer necessary to update the tunnel configuration when the server selection changes?

func sanitizedServerSelectionMethod() async -> NetworkProtectionServerSelectionMethod
}

public final class VPNServerSelectionSanitizer: VPNServerSelectionSanitizing {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments here:

  1. Let's add unit tests to cover this class in its entirety.
  2. The name of this class sounds off to me. This does more than just sanitize the selection - it effectively manages the entire selection logic (locations vs servers in settings). Additionally when referencing this in the init parameter below (for PacketTunnelProvider) the instance is named serverSelection, which makes me think you agree. Why not name this something more generic like VPNServerSelector or VPNServerSelectionResolver.
  3. To further expand on point 2, I really think that to the PacketTunnelProvider whether this does sanitization or not is an implementation detail - what matters is that this class provides a server / location to connect to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the naming here gave me a lot of trouble. So just decided to open it up to get opinions. Thanks for the input.

Comment on lines -922 to -946
case .setSelectedServer(let selectedServer):
let serverSelectionMethod: NetworkProtectionServerSelectionMethod

switch selectedServer {
case .automatic:
serverSelectionMethod = .automatic
case .endpoint(let serverName):
serverSelectionMethod = .preferredServer(serverName: serverName)
}

Task { @MainActor in
if case .connected = connectionStatus {
try? await updateTunnelConfiguration(environment: settings.selectedEnvironment, serverSelectionMethod: serverSelectionMethod, reassert: true)
}
completionHandler?(nil)
}
case .setSelectedLocation(let selectedLocation):
let serverSelectionMethod: NetworkProtectionServerSelectionMethod

switch selectedLocation {
case .nearest:
serverSelectionMethod = .automatic
case .location(let location):
serverSelectionMethod = .preferredLocation(location)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is all going away? Admittedly I'm not looking to deeply into this and opting to ask as I want to avoid making (mistaken) assumptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sure. It’s essentially extracting this logic into the… class that has yet to be named ;). Let’s go with ServerSelector. I’ve been trying to avoid adding too much more logic to the PacketTunnelProvider, but this selection logic seemed closely related to the responsibilities of the ServerSelector. The extraction should allow it to all be unit tested too which I’ll do before moving this PR out of draft.

serverSelectionMethod = .preferredLocation(location)
}

case .setSelectedServer, .setSelectedLocation:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this is now handling both server selection and location selection cases.

@graeme
Copy link
Contributor Author

graeme commented Apr 10, 2024

@diegoreymendez I agree about this not fully handling recovery. This however, does add some improvement to the robustness of the location / server selection logic and I’m trying to go for incremental improvements. However, recovering from a failed register request feels a bit more generic and not just relating to locations…

…again though, however, I’m also not 100% sure if this is the right approach or whether the location fallback logic should not be pre-emptive as it currently is, but a reaction of a railed register request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants