Skip to content

chore: clear session on launch if vpn unconfigured #76

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

Merged
merged 1 commit into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Coder Desktop/Coder Desktop/Coder_DesktopApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
name: .NEVPNStatusDidChange,
object: nil
)
Task {
// If there's no NE config, then the user needs to sign in.
// However, they might have a session from a previous install, so we
// need to clear it.
if await !vpn.loadNetworkExtensionConfig() {
state.clearSession()
}
}
}

// This function MUST eventually call `NSApp.reply(toApplicationShouldTerminate: true)`
Expand Down
5 changes: 4 additions & 1 deletion Coder Desktop/Coder Desktop/NetworkExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ enum NetworkExtensionState: Equatable {
/// An actor that handles configuring, enabling, and disabling the VPN tunnel via the
/// NetworkExtension APIs.
extension CoderVPNService {
func loadNetworkExtensionConfig() async {
// Attempts to load the NetworkExtension configuration, returning true if successful.
func loadNetworkExtensionConfig() async -> Bool {
do {
let tm = try await getTunnelManager()
neState = .disabled
serverAddress = tm.protocolConfiguration?.serverAddress
return true
} catch {
neState = .unconfigured
return false
}
}

Expand Down
5 changes: 2 additions & 3 deletions Coder Desktop/Coder Desktop/VPNService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ enum VPNServiceError: Error, Equatable {
state.description
}
}

var localizedDescription: String { description }
}

@MainActor
Expand Down Expand Up @@ -67,9 +69,6 @@ final class CoderVPNService: NSObject, VPNService {
override init() {
super.init()
installSystemExtension()
Task {
await loadNetworkExtensionConfig()
}
}

deinit {
Expand Down
2 changes: 2 additions & 0 deletions Coder Desktop/Coder Desktop/Views/LoginForm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ enum LoginError: Error {
"Could not authenticate with Coder deployment:\n\(err.description)"
}
}

var localizedDescription: String { description }
}

enum LoginPage {
Expand Down
1 change: 1 addition & 0 deletions Coder Desktop/Coder Desktop/Views/VPNMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct VPNMenu<VPN: VPNService>: View {
!state.hasSession ||
vpn.state == .connecting ||
vpn.state == .disconnecting ||
// Prevent starting the VPN before the user has approved the system extension.
vpn.state == .failed(.systemExtensionError(.needsUserApproval))
}
}
Expand Down
2 changes: 2 additions & 0 deletions Coder Desktop/CoderSDK/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,6 @@ public enum ClientError: Error {
"Failed to encode body: \(error)"
}
}

public var localizedDescription: String { description }
}
2 changes: 2 additions & 0 deletions Coder Desktop/VPN/Manager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ enum ManagerError: Error {
"Failed to communicate with dylib over tunnel: \(err)"
}
}

var localizedDescription: String { description }
}

func writeVpnLog(_ log: Vpn_Log) {
Expand Down
2 changes: 2 additions & 0 deletions Coder Desktop/VPN/TunnelHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ enum TunnelHandleError: Error {
case let .close(errs): "close tunnel: \(errs.map(\.localizedDescription).joined(separator: ", "))"
}
}

var localizedDescription: String { description }
}

enum OpenTunnelError: Int32 {
Expand Down
8 changes: 6 additions & 2 deletions Coder Desktop/VPNLib/Download.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public enum ValidationError: Error {
case missingInfoPList
case invalidVersion(version: String?)

public var errorDescription: String? {
public var description: String {
switch self {
case .fileNotFound:
"The file does not exist."
Expand All @@ -31,6 +31,8 @@ public enum ValidationError: Error {
"Info.plist is not embedded within the dylib."
}
}

public var localizedDescription: String { description }
}

public class SignatureValidator {
Expand Down Expand Up @@ -156,7 +158,7 @@ public enum DownloadError: Error {
case networkError(any Error)
case fileOpError(any Error)

var localizedDescription: String {
public var description: String {
switch self {
case let .unexpectedStatusCode(code):
"Unexpected HTTP status code: \(code)"
Expand All @@ -168,4 +170,6 @@ public enum DownloadError: Error {
"Received non-HTTP response"
}
}

public var localizedDescription: String { description }
}
11 changes: 10 additions & 1 deletion Coder Desktop/VPNLib/Receiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,18 @@ actor Receiver<RecvMsg: Message> {
}
}

enum ReceiveError: Error {
public enum ReceiveError: Error {
case readError(String)
case invalidLength

public var description: String {
switch self {
case let .readError(err): "read error: \(err)"
case .invalidLength: "invalid message length"
}
}

public var localizedDescription: String { description }
}

func deserializeLen(_ data: Data) throws -> UInt32 {
Expand Down
25 changes: 25 additions & 0 deletions Coder Desktop/VPNLib/Speaker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,19 @@ public enum HandshakeError: Error {
case wrongRole(String)
case invalidVersion(String)
case unsupportedVersion([ProtoVersion])

public var description: String {
switch self {
case let .readError(err): "read error: \(err)"
case let .writeError(err): "write error: \(err)"
case let .invalidHeader(err): "invalid header: \(err)"
case let .wrongRole(err): "wrong role: \(err)"
case let .invalidVersion(err): "invalid version: \(err)"
case let .unsupportedVersion(versions): "unsupported version: \(versions)"
}
}

public var localizedDescription: String { description }
}

public struct RPCRequest<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Sendable>: Sendable {
Expand All @@ -314,6 +327,18 @@ enum RPCError: Error {
case notAResponse
case unknownResponseID(UInt64)
case shutdown

var description: String {
switch self {
case .missingRPC: "missing RPC field"
case .notARequest: "not a request"
case .notAResponse: "not a response"
case let .unknownResponseID(id): "unknown response ID: \(id)"
case .shutdown: "RPC secretary has been shutdown"
}
}

var localizedDescription: String { description }
}

/// An actor to record outgoing RPCs and route their replies to the original sender
Expand Down
Loading