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

Commit208225b

Browse files
authored
fix: remember token when switching deployments (#120)
If we log in on deployment 1, then log out and login to deployment 2 andthen in the same session we try to log in back to deployment 1, thetoken is no longer valid. The plugin will associate with deployment 1the token from the second deployment.There is an overly complicated block of code inherited from Gatewayplugin with multiple fallback sequences for both the deployment url andtoken from multiple sources (secrets store, data dir config, env,etc...). This fix simplifies the approach, we only store the url and thetoken in the secrets store, the token is always associated to ahostname. If there is no previous URL to remember (like the first timelogin) we default tohttps://dev.coder.com/ and empty token.
1 parente4ce4c4 commit208225b

File tree

14 files changed

+134
-231
lines changed

14 files changed

+134
-231
lines changed

‎CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
###Fixed
1111

1212
- url on the main page is now refreshed when switching between multiple deployments (via logout/login or URI handling)
13+
- tokens are now remembered after switching between multiple deployments
1314

1415
##0.2.2 - 2025-05-21
1516

‎src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class CoderRemoteProvider(
6464
// On the first load, automatically log in if we can.
6565
privatevar firstRun=true
6666
privateval isInitialized:MutableStateFlow<Boolean>=MutableStateFlow(false)
67-
privatevar coderHeaderPage=NewEnvironmentPage(context, context.i18n.pnotr(context.deploymentUrl?.first?:""))
67+
privatevar coderHeaderPage=NewEnvironmentPage(context, context.i18n.pnotr(context.deploymentUrl.toString()))
6868
privateval linkHandler=CoderProtocolHandler(context, dialogUi, isInitialized)
6969
overrideval environments:MutableStateFlow<LoadableState<List<RemoteProviderEnvironment>>>=MutableStateFlow(
7070
LoadableState.Loading
@@ -336,6 +336,7 @@ class CoderRemoteProvider(
336336
// Store the URL and token for use next time.
337337
context.secrets.lastDeploymentURL= client.url.toString()
338338
context.secrets.lastToken= client.token?:""
339+
context.secrets.storeTokenFor(client.url, context.secrets.lastToken)
339340
// Currently we always remember, but this could be made an option.
340341
context.secrets.rememberMe=true
341342
this.client= client
Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
packagecom.coder.toolbox
22

3-
importcom.coder.toolbox.settings.SettingSource
43
importcom.coder.toolbox.store.CoderSecretsStore
54
importcom.coder.toolbox.store.CoderSettingsStore
65
importcom.coder.toolbox.util.toURL
@@ -13,6 +12,7 @@ import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentStateColorPalette
1312
importcom.jetbrains.toolbox.api.remoteDev.ui.EnvironmentUiPageManager
1413
importcom.jetbrains.toolbox.api.ui.ToolboxUi
1514
importkotlinx.coroutines.CoroutineScope
15+
importjava.net.URL
1616

1717
data classCoderToolboxContext(
1818
valui:ToolboxUi,
@@ -37,31 +37,11 @@ data class CoderToolboxContext(
3737
* 3. CODER_URL.
3838
* 4. URL in global cli config.
3939
*/
40-
val deploymentUrl:Pair<String,SettingSource>?
41-
get()=this.secrets.lastDeploymentURL.let {
42-
if (it.isNotBlank()) {
43-
it toSettingSource.LAST_USED
44-
}else {
45-
this.settingsStore.defaultURL()
40+
val deploymentUrl:URL
41+
get() {
42+
if (this.secrets.lastDeploymentURL.isNotBlank()) {
43+
returnthis.secrets.lastDeploymentURL.toURL()
4644
}
45+
returnthis.settingsStore.defaultURL.toURL()
4746
}
48-
49-
/**
50-
* Try to find a token.
51-
*
52-
* Order of preference:
53-
*
54-
* 1. Last used token, if it was for this deployment.
55-
* 2. Token on disk for this deployment.
56-
* 3. Global token for Coder, if it matches the deployment.
57-
*/
58-
fungetToken(deploymentURL:String?):Pair<String,SettingSource>?=this.secrets.lastToken.let {
59-
if (it.isNotBlank()&&this.secrets.lastDeploymentURL== deploymentURL) {
60-
it toSettingSource.LAST_USED
61-
}else {
62-
if (deploymentURL!=null) {
63-
this.settingsStore.token(deploymentURL.toURL())
64-
}elsenull
65-
}
66-
}
6747
}

‎src/main/kotlin/com/coder/toolbox/browser/BrowserUtil.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
packagecom.coder.toolbox.browser
22

3+
importcom.coder.toolbox.util.toURL
34
importcom.jetbrains.toolbox.api.core.os.LocalDesktopManager
4-
importjava.net.URI
55

66

77
suspendfun LocalDesktopManager.browse(rawUrl:String,errorHandler:suspend (BrowserException)->Unit) {
88
try {
9-
val url=URI.create(rawUrl).toURL()
9+
val url= rawUrl.toURL()
1010
this.openUrl(url)
1111
}catch (e:Exception) {
1212
errorHandler(

‎src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface ReadOnlyCoderSettings {
1010
/**
1111
* The default URL to show in the connection window.
1212
*/
13-
val defaultURL:String?
13+
val defaultURL:String
1414

1515
/**
1616
* Used to download the Coder CLI which is necessary to proxy SSH
@@ -116,16 +116,6 @@ interface ReadOnlyCoderSettings {
116116
*/
117117
val networkInfoDir:String
118118

119-
/**
120-
* The default URL to show in the connection window.
121-
*/
122-
fundefaultURL():Pair<String,SettingSource>?
123-
124-
/**
125-
* Given a deployment URL, try to find a token for it if required.
126-
*/
127-
funtoken(deploymentURL:URL):Pair<String,SettingSource>?
128-
129119
/**
130120
* Where the specified deployment should put its data.
131121
*/

‎src/main/kotlin/com/coder/toolbox/store/CoderSecretsStore.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
packagecom.coder.toolbox.store
22

33
importcom.jetbrains.toolbox.api.core.PluginSecretStore
4+
importjava.net.URL
45

56

67
/**
@@ -26,4 +27,10 @@ class CoderSecretsStore(private val store: PluginSecretStore) {
2627
var rememberMe:Boolean
2728
get()= get("remember-me").toBoolean()
2829
set(value)= set("remember-me", value.toString())
30+
31+
funtokenFor(url:URL):String?= store[url.host]
32+
33+
funstoreTokenFor(url:URL,token:String) {
34+
store[url.host]= token
35+
}
2936
}

‎src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.coder.toolbox.store
33
importcom.coder.toolbox.settings.Environment
44
importcom.coder.toolbox.settings.ReadOnlyCoderSettings
55
importcom.coder.toolbox.settings.ReadOnlyTLSSettings
6-
importcom.coder.toolbox.settings.SettingSource
76
importcom.coder.toolbox.util.Arch
87
importcom.coder.toolbox.util.OS
98
importcom.coder.toolbox.util.expand
@@ -35,7 +34,7 @@ class CoderSettingsStore(
3534
) : ReadOnlyTLSSettings
3635

3736
// Properties implementation
38-
overrideval defaultURL:String? get()= store[DEFAULT_URL]
37+
overrideval defaultURL:String get()= store[DEFAULT_URL]?:"https://dev.coder.com"
3938
overrideval binarySource:String? get()= store[BINARY_SOURCE]
4039
overrideval binaryDirectory:String? get()= store[BINARY_DIRECTORY]
4140
overrideval defaultCliBinaryNameByOsAndArch:String get()= getCoderCLIForOS(getOS(), getArch())
@@ -71,48 +70,6 @@ class CoderSettingsStore(
7170
.normalize()
7271
.toString()
7372

74-
/**
75-
* The default URL to show in the connection window.
76-
*/
77-
overridefundefaultURL():Pair<String,SettingSource>? {
78-
val envURL= env.get(CODER_URL)
79-
if (!defaultURL.isNullOrEmpty()) {
80-
return defaultURL!! toSettingSource.SETTINGS
81-
}elseif (envURL.isNotBlank()) {
82-
return envURL toSettingSource.ENVIRONMENT
83-
}else {
84-
val (configUrl, _)= readConfig(Path.of(globalConfigDir))
85-
if (!configUrl.isNullOrBlank()) {
86-
return configUrl toSettingSource.CONFIG
87-
}
88-
}
89-
returnnull
90-
}
91-
92-
/**
93-
* Given a deployment URL, try to find a token for it if required.
94-
*/
95-
overridefuntoken(deploymentURL:URL):Pair<String,SettingSource>? {
96-
// No need to bother if we do not need token auth anyway.
97-
if (!requireTokenAuth) {
98-
returnnull
99-
}
100-
// Try the deployment's config directory. This could exist if someone
101-
// has entered a URL that they are not currently connected to, but have
102-
// connected to in the past.
103-
val (_, deploymentToken)= readConfig(dataDir(deploymentURL).resolve("config"))
104-
if (!deploymentToken.isNullOrBlank()) {
105-
return deploymentToken toSettingSource.DEPLOYMENT_CONFIG
106-
}
107-
// Try the global config directory, in case they previously set up the
108-
// CLI with this URL.
109-
val (configUrl, configToken)= readConfig(Path.of(globalConfigDir))
110-
if (configUrl== deploymentURL.toString()&&!configToken.isNullOrBlank()) {
111-
return configToken toSettingSource.CONFIG
112-
}
113-
returnnull
114-
}
115-
11673
/**
11774
* Where the specified deployment should put its data.
11875
*/

‎src/main/kotlin/com/coder/toolbox/views/AuthWizardPage.kt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package com.coder.toolbox.views
33
importcom.coder.toolbox.CoderToolboxContext
44
importcom.coder.toolbox.cli.CoderCLIManager
55
importcom.coder.toolbox.sdk.CoderRestClient
6+
importcom.coder.toolbox.util.toURL
7+
importcom.coder.toolbox.views.state.AuthContext
68
importcom.coder.toolbox.views.state.AuthWizardState
79
importcom.coder.toolbox.views.state.WizardStep
810
importcom.jetbrains.toolbox.api.ui.actions.RunnableActionDescription
@@ -23,17 +25,30 @@ class AuthWizardPage(
2325
privateval settingsAction=Action(context.i18n.ptrl("Settings"), actionBlock= {
2426
context.ui.showUiPage(settingsPage)
2527
})
28+
2629
privateval signInStep=SignInStep(context,this::notify)
2730
privateval tokenStep=TokenStep(context)
28-
privateval connectStep=ConnectStep(context, shouldAutoLogin,this::notify,this::displaySteps, onConnect)
29-
31+
privateval connectStep=ConnectStep(
32+
context,
33+
shouldAutoLogin,
34+
this::notify,
35+
this::displaySteps,
36+
onConnect
37+
)
3038

3139
/**
3240
* Fields for this page, displayed in order.
3341
*/
3442
overrideval fields:MutableStateFlow<List<UiField>>=MutableStateFlow(emptyList())
3543
overrideval actionButtons:MutableStateFlow<List<RunnableActionDescription>>=MutableStateFlow(emptyList())
3644

45+
init {
46+
if (shouldAutoLogin.value) {
47+
AuthContext.url= context.secrets.lastDeploymentURL.toURL()
48+
AuthContext.token= context.secrets.lastToken
49+
}
50+
}
51+
3752
overridefunbeforeShow() {
3853
displaySteps()
3954
}

‎src/main/kotlin/com/coder/toolbox/views/ConnectStep.kt

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.coder.toolbox.cli.CoderCLIManager
55
importcom.coder.toolbox.cli.ensureCLI
66
importcom.coder.toolbox.plugin.PluginManager
77
importcom.coder.toolbox.sdk.CoderRestClient
8-
importcom.coder.toolbox.util.toURL
8+
importcom.coder.toolbox.views.state.AuthContext
99
importcom.coder.toolbox.views.state.AuthWizardState
1010
importcom.jetbrains.toolbox.api.localization.LocalizableString
1111
importcom.jetbrains.toolbox.api.ui.components.LabelField
@@ -50,34 +50,38 @@ class ConnectStep(
5050
context.i18n.pnotr("")
5151
}
5252

53-
val url= context.deploymentUrl?.first?.toURL()
54-
statusField.textState.update { context.i18n.pnotr("Connecting to${url?.host}...") }
53+
if (AuthContext.isNotReadyForAuth()) {
54+
errorField.textState.update {
55+
context.i18n.pnotr("URL and token were not properly configured. Please go back and provide a proper URL and token!")
56+
}
57+
return
58+
}
59+
60+
statusField.textState.update { context.i18n.pnotr("Connecting to${AuthContext.url!!.host}...") }
5561
connect()
5662
}
5763

5864
/**
5965
* Try connecting to Coder with the provided URL and token.
6066
*/
6167
privatefunconnect() {
62-
val url= context.deploymentUrl?.first?.toURL()
63-
val token= context.getToken(context.deploymentUrl?.first)?.first
64-
if (url==null) {
68+
if (!AuthContext.hasUrl()) {
6569
errorField.textState.update { context.i18n.ptrl("URL is required") }
6670
return
6771
}
6872

69-
if (token.isNullOrBlank()) {
73+
if (!AuthContext.hasToken()) {
7074
errorField.textState.update { context.i18n.ptrl("Token is required") }
7175
return
7276
}
7377
signInJob?.cancel()
7478
signInJob= context.cs.launch {
7579
try {
76-
statusField.textState.update { (context.i18n.ptrl("Authenticating to${url.host}...")) }
80+
statusField.textState.update { (context.i18n.ptrl("Authenticating to${AuthContext.url!!.host}...")) }
7781
val client=CoderRestClient(
7882
context,
79-
url,
80-
token,
83+
AuthContext.url!!,
84+
AuthContext.token!!,
8185
PluginManager.pluginInfo.version,
8286
)
8387
// allows interleaving with the back/cancel action
@@ -92,19 +96,20 @@ class ConnectStep(
9296
yield()
9397
cli.login(client.token)
9498
}
95-
statusField.textState.update { (context.i18n.ptrl("Successfully configured${url.host}...")) }
99+
statusField.textState.update { (context.i18n.ptrl("Successfully configured${AuthContext.url!!.host}...")) }
96100
// allows interleaving with the back/cancel action
97101
yield()
98-
onConnect(client, cli)
102+
AuthContext.reset()
99103
AuthWizardState.resetSteps()
104+
onConnect(client, cli)
100105
}catch (ex:CancellationException) {
101106
if (ex.message!=USER_HIT_THE_BACK_BUTTON) {
102-
notify("Connection to${url.host} was configured", ex)
107+
notify("Connection to${AuthContext.url!!.host} was configured", ex)
103108
onBack()
104109
refreshWizard()
105110
}
106111
}catch (ex:Exception) {
107-
notify("Failed to configure${url.host}", ex)
112+
notify("Failed to configure${AuthContext.url!!.host}", ex)
108113
onBack()
109114
refreshWizard()
110115
}
@@ -120,6 +125,7 @@ class ConnectStep(
120125
signInJob?.cancel(CancellationException(USER_HIT_THE_BACK_BUTTON))
121126
}finally {
122127
if (shouldAutoLogin.value) {
128+
AuthContext.reset()
123129
AuthWizardState.resetSteps()
124130
context.secrets.rememberMe=false
125131
}else {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp