Skip to content

Commit 67ea616

Browse files
committed
fix: pass configured http headers to network extension
1 parent de12d33 commit 67ea616

File tree

8 files changed

+32
-16
lines changed

8 files changed

+32
-16
lines changed

Coder Desktop/Coder Desktop/State.swift

+11-5
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ class AppState: ObservableObject {
3131

3232
@Published var useLiteralHeaders: Bool = UserDefaults.standard.bool(forKey: Keys.useLiteralHeaders) {
3333
didSet {
34+
if let onChange { onChange(tunnelProviderProtocol()) }
3435
guard persistent else { return }
3536
UserDefaults.standard.set(useLiteralHeaders, forKey: Keys.useLiteralHeaders)
3637
}
3738
}
3839

3940
@Published var literalHeaders: [LiteralHeader] {
4041
didSet {
42+
if let onChange { onChange(tunnelProviderProtocol()) }
4143
guard persistent else { return }
4244
try? UserDefaults.standard.set(JSONEncoder().encode(literalHeaders), forKey: Keys.literalHeaders)
4345
}
@@ -57,13 +59,17 @@ class AppState: ObservableObject {
5759
// HACK: We can't write to the system keychain, and the user keychain
5860
// isn't accessible, so we'll use providerConfiguration, which is over XPC.
5961
proto.providerConfiguration = ["token": sessionToken!]
62+
if useLiteralHeaders, let headers = try? JSONEncoder().encode(literalHeaders) {
63+
proto.providerConfiguration?["literalHeaders"] = headers
64+
}
6065
proto.serverAddress = baseAccessURL!.absoluteString
6166
return proto
6267
}
6368

6469
private let keychain: Keychain
6570
private let persistent: Bool
6671

72+
// This closure must be called when any property used to configure the VPN changes
6773
let onChange: ((NETunnelProviderProtocol?) -> Void)?
6874

6975
public init(onChange: ((NETunnelProviderProtocol?) -> Void)? = nil,
@@ -125,20 +131,20 @@ class AppState: ObservableObject {
125131
}
126132

127133
struct LiteralHeader: Hashable, Identifiable, Equatable, Codable {
128-
var header: String
134+
var name: String
129135
var value: String
130136
var id: String {
131-
"\(header):\(value)"
137+
"\(name):\(value)"
132138
}
133139

134-
init(header: String, value: String) {
135-
self.header = header
140+
init(name: String, value: String) {
141+
self.name = name
136142
self.value = value
137143
}
138144
}
139145

140146
extension LiteralHeader {
141147
func toSDKHeader() -> HTTPHeader {
142-
.init(header: header, value: value)
148+
.init(name: name, value: value)
143149
}
144150
}

Coder Desktop/Coder Desktop/Views/Settings/LiteralHeaderModal.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ struct LiteralHeaderModal: View {
2626
}.padding(20)
2727
}.onAppear {
2828
if let existingHeader {
29-
header = existingHeader.header
29+
header = existingHeader.name
3030
value = existingHeader.value
3131
}
3232
}
@@ -37,7 +37,7 @@ struct LiteralHeaderModal: View {
3737
if let existingHeader {
3838
state.literalHeaders.removeAll { $0 == existingHeader }
3939
}
40-
let newHeader = LiteralHeader(header: header, value: value)
40+
let newHeader = LiteralHeader(name: header, value: value)
4141
if !state.literalHeaders.contains(newHeader) {
4242
state.literalHeaders.append(newHeader)
4343
}

Coder Desktop/Coder Desktop/Views/Settings/LiteralHeadersSection.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ struct LiteralHeadersSection<VPN: VPNService>: View {
2020
.controlSize(.large)
2121

2222
Table(state.literalHeaders, selection: $selectedHeader) {
23-
TableColumn("Header", value: \.header)
23+
TableColumn("Header", value: \.name)
2424
TableColumn("Value", value: \.value)
2525
}.opacity(state.useLiteralHeaders ? 1 : 0.5)
2626
.frame(minWidth: 400, minHeight: 200)

Coder Desktop/CoderSDK/Client.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public struct Client {
3333
if let token { req.addValue(token, forHTTPHeaderField: Headers.sessionToken) }
3434
req.httpMethod = method.rawValue
3535
for header in headers {
36-
req.addValue(header.value, forHTTPHeaderField: header.header)
36+
req.addValue(header.value, forHTTPHeaderField: header.name)
3737
}
3838
req.httpBody = body
3939
let data: Data

Coder Desktop/CoderSDK/HTTP.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ public struct HTTPResponse {
66
let req: URLRequest
77
}
88

9-
public struct HTTPHeader: Sendable {
10-
public let header: String
9+
public struct HTTPHeader: Sendable, Codable {
10+
public let name: String
1111
public let value: String
12-
public init(header: String, value: String) {
13-
self.header = header
12+
public init(name: String, value: String) {
13+
self.name = name
1414
self.value = value
1515
}
1616
}

Coder Desktop/CoderSDKTests/CoderSDKTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct CoderSDKTests {
2828

2929
let url = URL(string: "https://example.com")!
3030
let token = "fake-token"
31-
let client = Client(url: url, token: token, headers: [.init(header: "X-Test-Header", value: "foo")])
31+
let client = Client(url: url, token: token, headers: [.init(name: "X-Test-Header", value: "foo")])
3232
var mock = try Mock(
3333
url: url.appending(path: "api/v2/users/johndoe"),
3434
contentType: .json,

Coder Desktop/VPN/Manager.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ actor Manager {
5454
do {
5555
try tunnelHandle = TunnelHandle(dylibPath: dest)
5656
} catch {
57-
logger.error("couldn't open dylib \(error, privacy: .public)")
5857
throw .tunnelSetup(error)
5958
}
6059
speaker = await Speaker<Vpn_ManagerMessage, Vpn_TunnelMessage>(
@@ -164,6 +163,12 @@ actor Manager {
164163
req.tunnelFileDescriptor = tunFd
165164
req.apiToken = cfg.apiToken
166165
req.coderURL = cfg.serverUrl.absoluteString
166+
req.headers = cfg.literalHeaders.map { header in
167+
.with { req in
168+
req.name = header.name
169+
req.value = header.value
170+
}
171+
}
167172
}
168173
})
169174
} catch {
@@ -223,6 +228,7 @@ actor Manager {
223228
struct ManagerConfig {
224229
let apiToken: String
225230
let serverUrl: URL
231+
let literalHeaders: [HTTPHeader]
226232
}
227233

228234
enum ManagerError: Error {

Coder Desktop/VPN/PacketTunnelProvider.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import CoderSDK
12
import NetworkExtension
23
import os
34
import VPNLib
@@ -65,6 +66,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
6566
completionHandler(makeNSError(suffix: "PTP", desc: "Missing Token"))
6667
return
6768
}
69+
let headers: [HTTPHeader] = (proto.providerConfiguration?["literalHeaders"] as? Data)
70+
.flatMap { try? JSONDecoder().decode([HTTPHeader].self, from: $0) } ?? []
6871
logger.debug("retrieved token & access URL")
6972
let completionHandler = CallbackWrapper(completionHandler)
7073
Task {
@@ -73,7 +76,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
7376
let manager = try await Manager(
7477
with: self,
7578
cfg: .init(
76-
apiToken: token, serverUrl: .init(string: baseAccessURL)!
79+
apiToken: token, serverUrl: .init(string: baseAccessURL)!,
80+
literalHeaders: headers
7781
)
7882
)
7983
globalXPCListenerDelegate.vpnXPCInterface.manager = manager

0 commit comments

Comments
 (0)