Skip to content

Commit 94b329f

Browse files
authored
impl: store last used URL in Toolbox Settings Store (#200)
Context: Toolbox can store key/value pairs in two places: - a settings store which is backed by a clear text json file per each plugin - native keystore for sensitive data At the same time some of Coder's clients (ex: Netflix) would like to deploy at scale preconfigured settings for Toolbox. Most of the needed settings are part of json backed store except the last used URL. This PR reworks the code around the last used URL/token and moves the URL in the json backed store, making it easy to configure. At the same time we still support the pair stored in the native keystore for backward compatibility reasons.
1 parent 08c2912 commit 94b329f

File tree

9 files changed

+37
-37
lines changed

9 files changed

+37
-37
lines changed

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Changed
6+
7+
- simplified storage for last used url and token
8+
59
## 0.6.6 - 2025-09-24
610

711
### Changed

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version=0.6.6
1+
version=0.7.0
22
group=com.coder.toolbox
33
name=coder-toolbox

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import com.coder.toolbox.sdk.ex.APIResponseException
77
importcom.coder.toolbox.sdk.v2.models.WorkspaceStatus
88
importcom.coder.toolbox.util.CoderProtocolHandler
99
importcom.coder.toolbox.util.DialogUi
10-
importcom.coder.toolbox.util.toURL
1110
importcom.coder.toolbox.util.waitForTrue
1211
importcom.coder.toolbox.util.withPath
1312
importcom.coder.toolbox.views.Action
@@ -364,8 +363,8 @@ class CoderRemoteProvider(
364363
if (shouldDoAutoSetup()){
365364
try{
366365
CoderCliSetupContext.apply{
367-
url = context.secrets.lastDeploymentURL.toURL()
368-
token = context.secrets.lastToken
366+
url = context.deploymentUrl
367+
token = context.secrets.tokenFor(context.deploymentUrl)
369368
}
370369
CoderCliSetupWizardState.goToStep(WizardStep.CONNECT)
371370
returnCoderCliSetupWizardPage(
@@ -399,14 +398,15 @@ class CoderRemoteProvider(
399398
* Auto-login only on first the firs run if there is a url & token configured or the auth
400399
* should be done via certificates.
401400
*/
402-
privatefunshouldDoAutoSetup(): Boolean= firstRun && (context.secrets.canAutoLogin ||!settings.requireTokenAuth)
401+
privatefunshouldDoAutoSetup(): Boolean= firstRun && (canAutoLogin() ||!settings.requireTokenAuth)
402+
403+
funcanAutoLogin(): Boolean=!context.secrets.tokenFor(context.deploymentUrl).isNullOrBlank()
403404

404405
privatefunonConnect(client:CoderRestClient, cli:CoderCLIManager){
405406
// Store the URL and token for use next time.
406-
context.secrets.lastDeploymentURL =client.url.toString()
407+
context.settingsStore.updateLastUsedUrl(client.url)
407408
if (context.settingsStore.requireTokenAuth){
408-
context.secrets.lastToken = client.token ?:""
409-
context.secrets.storeTokenFor(client.url, context.secrets.lastToken)
409+
context.secrets.storeTokenFor(client.url, client.token ?:"")
410410
context.logger.info("Deployment URL and token were stored and will be available for automatic connection")
411411
} else{
412412
context.logger.info("Deployment URL was stored and will be available for automatic connection")

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,15 @@ data class CoderToolboxContext(
3636
*
3737
* In order of preference:
3838
*
39-
* 1. Last used URL.
40-
* 2. URL in settings.
41-
* 3. CODER_URL.
42-
* 4. URL in global cli config.
39+
* 1. Last used URL from the settings.
40+
* 2. Last used URL from the secrets store.
41+
* 3. Default URL
4342
*/
4443
val deploymentUrl:URL
4544
get(){
46-
if (this.secrets.lastDeploymentURL.isNotBlank()){
47-
returnthis.secrets.lastDeploymentURL.toURL()
48-
}
49-
returnthis.settingsStore.defaultURL.toURL()
45+
return settingsStore.lastDeploymentURL?.takeIf{it.isNotBlank() }?.toURL()
46+
?: secrets.lastDeploymentURL.takeIf{it.isNotBlank() }?.toURL()
47+
?: settingsStore.defaultURL.toURL()
5048
}
5149

5250
suspendfunlogAndShowError(title:String, error:String){

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import java.util.Locale.getDefault
88
* Read-only interface for accessing Coder settings
99
*/
1010
interfaceReadOnlyCoderSettings{
11+
12+
/**
13+
* The last used deployment URL.
14+
*/
15+
val lastDeploymentURL:String?
16+
1117
/**
1218
* The default URL to show in the connection window.
1319
*/

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

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,11 @@ import java.net.URL
88
* Provides Coder secrets backed by the secrets store service.
99
*/
1010
classCoderSecretsStore(privatevalstore:PluginSecretStore){
11-
privatefunget(key:String): String= store[key] ?:""
12-
13-
privatefunset(key:String, value:String){
14-
if (value.isBlank()){
15-
store.clear(key)
16-
} else{
17-
store[key] = value
18-
}
19-
}
20-
21-
var lastDeploymentURL:String
22-
get() = get("last-deployment-url")
23-
set(value) = set("last-deployment-url", value)
24-
var lastToken:String
25-
get() = get("last-token")
26-
set(value) = set("last-token", value)
27-
val canAutoLogin:Boolean
28-
get() = lastDeploymentURL.isNotBlank() && lastToken.isNotBlank()
11+
@Deprecated(
12+
message ="The URL is now stored the JSON backed settings store. Use CoderSettingsStore#lastDeploymentURL",
13+
replaceWith =ReplaceWith("context.settingsStore.lastDeploymentURL")
14+
)
15+
val lastDeploymentURL:String= store["last-deployment-url"] ?:""
2916

3017
funtokenFor(url:URL): String?= store[url.host]
3118

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class CoderSettingsStore(
3636
) : ReadOnlyTLSSettings
3737

3838
// Properties implementation
39+
overrideval lastDeploymentURL:String? get() = store[LAST_USED_URL]
3940
overrideval defaultURL:String get() = store[DEFAULT_URL] ?:"https://dev.coder.com"
4041
overrideval binarySource:String? get() = store[BINARY_SOURCE]
4142
overrideval binaryDirectory:String? get() = store[BINARY_DIRECTORY]
@@ -155,6 +156,10 @@ class CoderSettingsStore(
155156
funreadOnly(): ReadOnlyCoderSettings=this
156157

157158
// Write operations
159+
funupdateLastUsedUrl(url:URL){
160+
store[LAST_USED_URL] = url.toString()
161+
}
162+
158163
funupdateBinarySource(source:String){
159164
store[BINARY_SOURCE] = source
160165
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.coder.toolbox.store
22

33
internalconstvalCODER_SSH_CONFIG_OPTIONS="CODER_SSH_CONFIG_OPTIONS"
44

5-
internalconstvalCODER_URL="CODER_URL"
5+
internalconstvalLAST_USED_URL="lastDeploymentURL"
66

77
internalconstvalDEFAULT_URL="defaultURL"
88

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ class DeploymentUrlStep(
6363
errorField.textState.update{
6464
context.i18n.pnotr("")
6565
}
66-
urlField.textState.update{
67-
context.secrets.lastDeploymentURL
66+
urlField.contentState.update{
67+
context.deploymentUrl.toString()
6868
}
6969

7070
signatureFallbackStrategyField.checkedState.update{

0 commit comments

Comments
(0)