Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite18f466

Browse files
chore: enforce minimum coder server version of v2.20.0 (#90)
This will cause Coder Desktop networking to fail to start unless the validated dylib is version `v2.20.0` or later. Obviously, using this build early would mean Coder Desktop would not work against our dogfood deployment.
1 parent75f015c commite18f466

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

‎Coder Desktop/Coder Desktop/Views/LoginForm.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import CoderSDK
22
import SwiftUI
3+
import VPNLib
34

45
structLoginForm:View{
56
@EnvironmentObjectvarstate:AppState
@@ -78,6 +79,22 @@ struct LoginForm: View {
7879
loginError=.failedAuth(error)
7980
return
8081
}
82+
letbuildInfo:BuildInfoResponse
83+
do{
84+
buildInfo=tryawait client.buildInfo()
85+
}catch{
86+
loginError=.failedAuth(error)
87+
return
88+
}
89+
guardlet semver= buildInfo.semverelse{
90+
loginError=.missingServerVersion
91+
return
92+
}
93+
// x.compare(y) is .orderedDescending if x > y
94+
guardSignatureValidator.minimumCoderVersion.compare(semver, options:.numeric)!=.orderedDescendingelse{
95+
loginError=.outdatedCoderVersion
96+
return
97+
}
8198
state.login(baseAccessURL: url, sessionToken: sessionToken)
8299
dismiss()
83100
}
@@ -190,6 +207,8 @@ enum LoginError: Error {
190207
case httpsRequired
191208
case noHost
192209
case invalidURL
210+
case outdatedCoderVersion
211+
case missingServerVersion
193212
case failedAuth(ClientError)
194213

195214
vardescription:String{
@@ -200,8 +219,15 @@ enum LoginError: Error {
200219
"URL must have a host"
201220
case.invalidURL:
202221
"Invalid URL"
222+
case.outdatedCoderVersion:
223+
"""
224+
The Coder deployment must be version\(SignatureValidator.minimumCoderVersion)
225+
or higher to use Coder Desktop.
226+
"""
203227
caselet.failedAuth(err):
204228
"Could not authenticate with Coder deployment:\n\(err.localizedDescription)"
229+
case.missingServerVersion:
230+
"Coder deployment did not provide a server version"
205231
}
206232
}
207233

‎Coder Desktop/Coder DesktopTests/LoginFormTests.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ struct LoginTests {
7373
@Test
7474
func testFailedAuthentication()asyncthrows{
7575
leturl=URL(string:"https://testFailedAuthentication.com")!
76+
letbuildInfo=BuildInfoResponse(
77+
version:"v2.20.0"
78+
)
79+
tryMock(
80+
url: url.appendingPathComponent("/api/v2/buildinfo"),
81+
statusCode:200,
82+
data:[.get:Client.encoder.encode(buildInfo)]
83+
).register()
7684
Mock(url: url.appendingPathComponent("/api/v2/users/me"), statusCode:401, data:[.get:Data()]).register()
7785

7886
tryawaitViewHosting.host(view){
@@ -87,6 +95,30 @@ struct LoginTests {
8795
}
8896
}
8997

98+
@Test
99+
func testOutdatedServer()asyncthrows{
100+
leturl=URL(string:"https://testOutdatedServer.com")!
101+
letbuildInfo=BuildInfoResponse(
102+
version:"v2.19.0"
103+
)
104+
tryMock(
105+
url: url.appendingPathComponent("/api/v2/buildinfo"),
106+
statusCode:200,
107+
data:[.get:Client.encoder.encode(buildInfo)]
108+
).register()
109+
110+
tryawaitViewHosting.host(view){
111+
tryawait sut.inspection.inspect{ viewin
112+
try view.find(ViewType.TextField.self).setInput(url.absoluteString)
113+
try view.find(button:"Next").tap()
114+
#expect(throws:Never.self){try view.find(text:"Session Token")}
115+
try view.find(ViewType.SecureField.self).setInput("valid-token")
116+
tryawait view.actualView().submit()
117+
#expect(throws:Never.self){try view.find(ViewType.Alert.self)}
118+
}
119+
}
120+
}
121+
90122
@Test
91123
func testSuccessfulLogin()asyncthrows{
92124
leturl=URL(string:"https://testSuccessfulLogin.com")!
@@ -95,13 +127,22 @@ struct LoginTests {
95127
id:UUID(),
96128
username:"admin"
97129
)
130+
letbuildInfo=BuildInfoResponse(
131+
version:"v2.20.0"
132+
)
98133

99134
tryMock(
100135
url: url.appendingPathComponent("/api/v2/users/me"),
101136
statusCode:200,
102137
data:[.get:Client.encoder.encode(user)]
103138
).register()
104139

140+
tryMock(
141+
url: url.appendingPathComponent("/api/v2/buildinfo"),
142+
statusCode:200,
143+
data:[.get:Client.encoder.encode(buildInfo)]
144+
).register()
145+
105146
tryawaitViewHosting.host(view){
106147
tryawait sut.inspection.inspect{ viewin
107148
try view.find(ViewType.TextField.self).setInput(url.absoluteString)

‎Coder Desktop/VPN/Manager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ actor Manager {
3131
// The tunnel might be asked to start before the network interfaces have woken up from sleep
3232
sessionConfig.waitsForConnectivity=true
3333
// URLSession's waiting for connectivity sometimes hangs even when
34-
// the network is up so this is deliberately short (15s) to avoid a
34+
// the network is up so this is deliberately short (30s) to avoid a
3535
// poor UX where it appears stuck.
36-
sessionConfig.timeoutIntervalForResource=15
36+
sessionConfig.timeoutIntervalForResource=30
3737
tryawaitdownload(src: dylibPath, dest: dest, urlSession:URLSession(configuration: sessionConfig))
3838
}catch{
3939
throw.download(error)

‎Coder Desktop/VPNLib/Download.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public enum ValidationError: Error {
1010
case invalidTeamIdentifier(identifier:String?)
1111
case missingInfoPList
1212
case invalidVersion(version:String?)
13+
case belowMinimumCoderVersion
1314

1415
publicvardescription:String{
1516
switchself{
@@ -29,13 +30,21 @@ public enum ValidationError: Error {
2930
"Invalid team identifier:\(identifier??"unknown")."
3031
case.missingInfoPList:
3132
"Info.plist is not embedded within the dylib."
33+
case.belowMinimumCoderVersion:
34+
"""
35+
The Coder deployment must be version\(SignatureValidator.minimumCoderVersion)
36+
or higher to use Coder Desktop.
37+
"""
3238
}
3339
}
3440

3541
publicvarlocalizedDescription:String{ description}
3642
}
3743

3844
publicclassSignatureValidator{
45+
// Whilst older dylibs exist, this app assumes v2.20 or later.
46+
publicstaticletminimumCoderVersion="2.20.0"
47+
3948
privatestaticletexpectedName="CoderVPN"
4049
privatestaticletexpectedIdentifier="com.coder.Coder-Desktop.VPN.dylib"
4150
privatestaticletexpectedTeamIdentifier="4399GN35BJ"
@@ -87,6 +96,10 @@ public class SignatureValidator {
8796
throw.missingInfoPList
8897
}
8998

99+
tryvalidateInfo(infoPlist: infoPlist, expectedVersion: expectedVersion)
100+
}
101+
102+
privatestaticfunc validateInfo(infoPlist:[String:AnyObject], expectedVersion:String)throws(ValidationError){
90103
guardlet plistIdent=infoPlist[infoIdentifierKey]as?String, plistIdent== expectedIdentifierelse{
91104
throw.invalidIdentifier(identifier:infoPlist[infoIdentifierKey]as?String)
92105
}
@@ -95,11 +108,20 @@ public class SignatureValidator {
95108
throw.invalidIdentifier(identifier:infoPlist[infoNameKey]as?String)
96109
}
97110

111+
// Downloaded dylib must match the version of the server
98112
guardlet dylibVersion=infoPlist[infoShortVersionKey]as?String,
99-
expectedVersion.compare(dylibVersion, options:.numeric)!=.orderedDescending
113+
expectedVersion== dylibVersion
100114
else{
101115
throw.invalidVersion(version:infoPlist[infoShortVersionKey]as?String)
102116
}
117+
118+
// Downloaded dylib must be at least the minimum Coder server version
119+
guardlet dylibVersion=infoPlist[infoShortVersionKey]as?String,
120+
// x.compare(y) is .orderedDescending if x > y
121+
minimumCoderVersion.compare(dylibVersion, options:.numeric)!=.orderedDescending
122+
else{
123+
throw.belowMinimumCoderVersion
124+
}
103125
}
104126
}
105127

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp