Skip to content
Open
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/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class AppState: ObservableObject {
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "AppState")
let appId = Bundle.main.bundleIdentifier!

let dangerousDisableCoderSignatureValidation: Bool

// Stored in UserDefaults
@Published private(set) var hasSession: Bool {
didSet {
Expand Down Expand Up @@ -87,6 +89,8 @@ class AppState: ObservableObject {
if useLiteralHeaders, let headers = try? JSONEncoder().encode(literalHeaders) {
proto.providerConfiguration?["literalHeaders"] = headers
}
// swiftlint:disable:next line_length
proto.providerConfiguration?["dangerousDisableCoderSignatureValidation"] = dangerousDisableCoderSignatureValidation
proto.serverAddress = baseAccessURL!.absoluteString
return proto
}
Expand All @@ -106,6 +110,9 @@ class AppState: ObservableObject {
{
self.persistent = persistent
self.onChange = onChange
dangerousDisableCoderSignatureValidation = persistent
? UserDefaults.standard.bool(forKey: Keys.dangerousDisableCoderSignatureValidation)
: false
keychain = Keychain(service: Bundle.main.bundleIdentifier!)
_hasSession = Published(initialValue: persistent ? UserDefaults.standard.bool(forKey: Keys.hasSession) : false)
_baseAccessURL = Published(
Expand Down Expand Up @@ -219,6 +226,7 @@ class AppState: ObservableObject {
static let stopVPNOnQuit = "StopVPNOnQuit"
static let startVPNOnLaunch = "StartVPNOnLaunch"

static let dangerousDisableCoderSignatureValidation = "DangerousDisableCoderSignatureValidation"
static let skipHiddenIconAlert = "SkipHiddenIconAlert"
}
}
Expand Down
2 changes: 1 addition & 1 deletion Coder-Desktop/Coder-Desktop/Views/Util.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private struct ActivationPolicyModifier: ViewModifier {
NSApp.setActivationPolicy(.regular)
}
.onDisappear {
if NSApp.windows.filter { $0.level != .statusBar && $0.isVisible }.count <= 1 {
if NSApp.windows.filter({ $0.level != .statusBar && $0.isVisible }).count <= 1 {
NSApp.setActivationPolicy(.accessory)
}
}
Expand Down
10 changes: 9 additions & 1 deletion Coder-Desktop/Coder-DesktopHelper/HelperXPCListeners.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ class HelperNEXPCServer: NSObject, NSXPCListenerDelegate, @unchecked Sendable {
}

extension HelperNEXPCServer: HelperNEXPCInterface {
// swiftlint:disable:next function_parameter_count
func startDaemon(
accessURL: URL,
token: String,
tun: FileHandle,
headers: Data?,
dangerousDisableSignatureValidation: Bool,
reply: @escaping (Error?) -> Void
) {
logger.info("startDaemon called")
Expand All @@ -92,7 +94,13 @@ extension HelperNEXPCServer: HelperNEXPCInterface {
apiToken: token,
serverUrl: accessURL,
tunFd: tun.fileDescriptor,
literalHeaders: headers.flatMap { try? JSONDecoder().decode([HTTPHeader].self, from: $0) } ?? []
literalHeaders: headers.flatMap {
try? JSONDecoder().decode(
[HTTPHeader].self,
from: $0
)
} ?? [],
dangerousDisableSignatureValidation: dangerousDisableSignatureValidation
)
)
try await manager.startVPN()
Expand Down
14 changes: 10 additions & 4 deletions Coder-Desktop/Coder-DesktopHelper/Manager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ actor Manager {

private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "manager")

// swiftlint:disable:next function_body_length
// swiftlint:disable:next function_body_length cyclomatic_complexity
init(cfg: ManagerConfig) async throws(ManagerError) {
self.cfg = cfg
telemetryEnricher = TelemetryEnricher()
Expand Down Expand Up @@ -74,12 +74,17 @@ actor Manager {
} catch {
throw .download(error)
}
pushProgress(stage: .validating)

do {
try Validator.validateSignature(binaryPath: dest)
if cfg.dangerousDisableSignatureValidation {
logger.warning("Skipping code signature validation of downloaded binary (disabled by configuration)")
} else {
pushProgress(stage: .validating)
try Validator.validateSignature(binaryPath: dest)
}
try await Validator.validateVersion(binaryPath: dest, serverVersion: buildInfo.version)
} catch {
// Cleanup unvalid binary
// Cleanup invalid binary
try? FileManager.default.removeItem(at: dest)
throw .validation(error)
}
Expand Down Expand Up @@ -270,6 +275,7 @@ struct ManagerConfig {
let serverUrl: URL
let tunFd: Int32
let literalHeaders: [HTTPHeader]
let dangerousDisableSignatureValidation: Bool
}

enum ManagerError: Error {
Expand Down
16 changes: 14 additions & 2 deletions Coder-Desktop/VPN/NEHelperXPCClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ final class HelperXPCClient: @unchecked Sendable {
return connection
}

func startDaemon(accessURL: URL, token: String, tun: FileHandle, headers: Data?) async throws {
func startDaemon(
accessURL: URL,
token: String,
tun: FileHandle,
headers: Data?,
dangerousDisableSignatureValidation: Bool
) async throws {
let conn = connect()
return try await withCheckedThrowingContinuation { continuation in
guard let proxy = conn.remoteObjectProxyWithErrorHandler({ err in
Expand All @@ -46,7 +52,13 @@ final class HelperXPCClient: @unchecked Sendable {
continuation.resume(throwing: XPCError.wrongProxyType)
return
}
proxy.startDaemon(accessURL: accessURL, token: token, tun: tun, headers: headers) { err in
proxy.startDaemon(
accessURL: accessURL,
token: token,
tun: tun,
headers: headers,
dangerousDisableSignatureValidation: dangerousDisableSignatureValidation
) { err in
if let error = err {
self.logger.error("Failed to start daemon: \(error.localizedDescription, privacy: .public)")
continuation.resume(throwing: error)
Expand Down
4 changes: 3 additions & 1 deletion Coder-Desktop/VPN/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
throw makeNSError(suffix: "PTP", desc: "Missing Token")
}
let headers = proto.providerConfiguration?["literalHeaders"] as? Data
let disableSigVal = proto.providerConfiguration?["dangerousDisableCoderSignatureValidation"] as? Bool ?? false
logger.debug("retrieved token & access URL")
guard let tunFd = tunnelFileDescriptor else {
logger.error("startTunnel called with nil tunnelFileDescriptor")
Expand All @@ -68,7 +69,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
accessURL: .init(string: baseAccessURL)!,
token: token,
tun: FileHandle(fileDescriptor: tunFd),
headers: headers
headers: headers,
dangerousDisableSignatureValidation: disableSigVal
)
}

Expand Down
10 changes: 9 additions & 1 deletion Coder-Desktop/VPNLib/XPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ public let helperNEMachServiceName = "4399GN35BJ.com.coder.Coder-Desktop.HelperN
@preconcurrency
@objc public protocol HelperNEXPCInterface {
// headers is a JSON `[HTTPHeader]`
func startDaemon(accessURL: URL, token: String, tun: FileHandle, headers: Data?, reply: @escaping (Error?) -> Void)
// swiftlint:disable:next function_parameter_count
func startDaemon(
accessURL: URL,
token: String,
tun: FileHandle,
headers: Data?,
dangerousDisableSignatureValidation: Bool,
reply: @escaping (Error?) -> Void
)
func stopDaemon(reply: @escaping (Error?) -> Void)
}

Expand Down
Loading