Skip to content
Draft
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
34 changes: 17 additions & 17 deletions src/main/kotlin/com/coder/toolbox/views/ConnectStep.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import com.coder.toolbox.oauth.OAuth2Client
import com.coder.toolbox.plugin.PluginManager
import com.coder.toolbox.sdk.CoderRestClient
import com.coder.toolbox.views.state.CoderOAuthSessionContext
import com.coder.toolbox.views.state.CoderSetupWizardContext
import com.coder.toolbox.views.state.CoderSetupWizardState
import com.coder.toolbox.views.state.WizardModel
import com.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
import com.jetbrains.toolbox.api.ui.components.LabelField
import com.jetbrains.toolbox.api.ui.components.RowGroup
Expand All @@ -30,6 +29,7 @@ private const val USER_HIT_THE_BACK_BUTTON = "User hit the back button"
*/
class ConnectStep(
private val context: CoderToolboxContext,
private val model: WizardModel,
private val shouldAutoLogin: StateFlow<Boolean>,
private val jumpToMainPageOnError: Boolean,
visibilityState: StateFlow<ProviderVisibilityState>,
Expand All @@ -54,7 +54,7 @@ class ConnectStep(
context.i18n.pnotr("")
}

if (context.settingsStore.requiresTokenAuth && CoderSetupWizardContext.isNotReadyForAuth()) {
if (context.settingsStore.requiresTokenAuth && model.isNotReadyForAuth()) {
errorField.textState.update {
context.i18n.pnotr("URL and token were not properly configured. Please go back and provide a proper URL and token!")
}
Expand All @@ -67,21 +67,21 @@ class ConnectStep(
return
}

statusField.textState.update { context.i18n.pnotr("Connecting to ${CoderSetupWizardContext.url?.host ?: "unknown host"}...") }
statusField.textState.update { context.i18n.pnotr("Connecting to ${model.url?.host ?: "unknown host"}...") }
connect()
}

/**
* Try connecting to Coder with the provided URL and token.
*/
private fun connect() {
val url = CoderSetupWizardContext.url
val url = model.url
if (url == null) {
errorField.textState.update { context.i18n.ptrl("URL is required") }
return
}

if (context.settingsStore.requiresTokenAuth && !CoderSetupWizardContext.hasToken() && !CoderSetupWizardContext.hasOAuthSession()) {
if (context.settingsStore.requiresTokenAuth && !model.hasToken() && !model.hasOAuthSession()) {
errorField.textState.update { context.i18n.ptrl("Token is required") }
return
}
Expand All @@ -96,12 +96,12 @@ class ConnectStep(
val connectionLogic: suspend CoroutineScope.() -> Unit = {
try {
var oauthSession: CoderOAuthSessionContext? = null
if (context.settingsStore.requiresTokenAuth && context.settingsStore.preferOAuth2IfAvailable && CoderSetupWizardContext.hasOAuthSession()) {
if (context.settingsStore.requiresTokenAuth && context.settingsStore.preferOAuth2IfAvailable && model.hasOAuthSession()) {
refreshOAuthToken()
oauthSession = CoderSetupWizardContext.oauthSession!!.copy()
oauthSession = model.oauthSession!!.copy()
}

val apiToken = if (context.settingsStore.requiresTokenAuth) CoderSetupWizardContext.token else null
val apiToken = if (context.settingsStore.requiresTokenAuth) model.token else null

context.logger.info("Setting up the HTTP client...")
val client = CoderRestClient(
Expand Down Expand Up @@ -142,8 +142,8 @@ class ConnectStep(
oauthSession?.let { session ->
onTokenRefreshed?.invoke(client.url, session)
}
CoderSetupWizardContext.reset()
CoderSetupWizardState.goToDone()
model.clearFormData()
model.goToDone()
context.envPageManager.showPluginEnvironmentsPage()
} catch (ex: CancellationException) {
if (ex.message != USER_HIT_THE_BACK_BUTTON) {
Expand All @@ -162,13 +162,13 @@ class ConnectStep(
}

private suspend fun refreshOAuthToken() {
val session = CoderSetupWizardContext.oauthSession ?: return
val session = model.oauthSession ?: return
if (!session.tokenResponse?.accessToken.isNullOrBlank()) return

logAndReportProgress("Refreshing OAuth token...")
val tokenResponse = OAuth2Client(context).refreshToken(session)
context.logger.info("Successfully refreshed access token")
CoderSetupWizardContext.oauthSession = session.copy(tokenResponse = tokenResponse)
model.oauthSession = session.copy(tokenResponse = tokenResponse)
}

private fun logAndReportProgress(msg: String) {
Expand All @@ -181,17 +181,17 @@ class ConnectStep(
*/
private fun handleNavigation() {
if (shouldAutoLogin.value) {
CoderSetupWizardContext.reset()
model.clearFormData()
if (jumpToMainPageOnError) {
context.popupPluginMainPage()
} else {
CoderSetupWizardState.goToFirstStep()
model.goToFirst()
}
} else {
if (context.settingsStore.requiresTokenAuth) {
CoderSetupWizardState.goToPreviousStep()
model.goToPrevious()
} else {
CoderSetupWizardState.goToFirstStep()
model.goToFirst()
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/main/kotlin/com/coder/toolbox/views/DeploymentUrlStep.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import com.coder.toolbox.util.WebUrlValidationResult.Invalid
import com.coder.toolbox.util.toURL
import com.coder.toolbox.util.validateStrictWebUrl
import com.coder.toolbox.views.state.CoderOAuthSessionContext
import com.coder.toolbox.views.state.CoderSetupWizardContext
import com.coder.toolbox.views.state.CoderSetupWizardState
import com.coder.toolbox.views.state.WizardModel
import com.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
import com.jetbrains.toolbox.api.ui.components.CheckboxField
import com.jetbrains.toolbox.api.ui.components.LabelField
Expand Down Expand Up @@ -40,6 +39,7 @@ private const val OAUTH2_SCOPE: String =
*/
class DeploymentUrlStep(
private val context: CoderToolboxContext,
private val model: WizardModel,
visibilityState: StateFlow<ProviderVisibilityState>,
) :
WizardStep {
Expand Down Expand Up @@ -94,28 +94,28 @@ class DeploymentUrlStep(
}

try {
CoderSetupWizardContext.url = validateRawUrl(rawUrl)
model.url = validateRawUrl(rawUrl)
} catch (e: MalformedURLException) {
errorReporter.report("URL is invalid", e)
return false
}

if (context.settingsStore.requiresMTlsAuth) {
CoderSetupWizardState.goToLastStep()
model.goToLast()
return true
}
if (context.settingsStore.requiresTokenAuth && context.settingsStore.preferOAuth2IfAvailable) {
try {
context.logger.info("Prefers OAuth2 authentication")
CoderSetupWizardContext.oauthSession = handleOAuth2(rawUrl)
model.oauthSession = handleOAuth2(rawUrl)
return false
} catch (e: Exception) {
errorReporter.report("Failed to authenticate with OAuth2: ${e.message}", e)
return false
}
}
// if all else fails try the good old API token auth
CoderSetupWizardState.goToNextStep()
model.goToNext()
return true
}

Expand Down
16 changes: 8 additions & 8 deletions src/main/kotlin/com/coder/toolbox/views/TokenStep.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package com.coder.toolbox.views

import com.coder.toolbox.CoderToolboxContext
import com.coder.toolbox.util.withPath
import com.coder.toolbox.views.state.CoderSetupWizardContext
import com.coder.toolbox.views.state.CoderSetupWizardState
import com.coder.toolbox.views.state.WizardModel
import com.jetbrains.toolbox.api.ui.components.LinkField
import com.jetbrains.toolbox.api.ui.components.RowGroup
import com.jetbrains.toolbox.api.ui.components.TextField
Expand All @@ -20,6 +19,7 @@ import kotlinx.coroutines.flow.update
*/
class TokenStep(
private val context: CoderToolboxContext,
private val model: WizardModel,
) : WizardStep {
private val tokenField = TextField(context.i18n.ptrl("Token"), "", TextType.Password)
private val linkField = LinkField(context.i18n.ptrl("Get a token"), "")
Expand All @@ -35,9 +35,9 @@ class TokenStep(
errorField.textState.update {
context.i18n.pnotr("")
}
if (CoderSetupWizardContext.hasUrl()) {
if (model.hasUrl()) {
tokenField.textState.update {
context.secrets.apiTokenFor(CoderSetupWizardContext.url!!) ?: ""
context.secrets.apiTokenFor(model.url!!) ?: ""
}
} else {
errorField.textState.update {
Expand All @@ -46,7 +46,7 @@ class TokenStep(
}
}
(linkField.urlState as MutableStateFlow).update {
CoderSetupWizardContext.url!!.withPath("/login?redirect=%2Fcli-auth")?.toString() ?: ""
model.url!!.withPath("/login?redirect=%2Fcli-auth")?.toString() ?: ""
}
}

Expand All @@ -57,12 +57,12 @@ class TokenStep(
return false
}

CoderSetupWizardContext.token = token
CoderSetupWizardState.goToNextStep()
model.token = token
model.goToNext()
return true
}

override fun onBack() {
CoderSetupWizardState.goToPreviousStep()
model.goToPrevious()
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.coder.toolbox.views.state

import com.coder.toolbox.oauth.OAuthTokenResponse
import com.coder.toolbox.oauth.TokenEndpointAuthMethod

data class CoderOAuthSessionContext(
val clientId: String,
val clientSecret: String,
val tokenCodeVerifier: String,
val state: String,
val tokenEndpoint: String,
val tokenResponse: OAuthTokenResponse? = null,
val tokenAuthMethod: TokenEndpointAuthMethod
)

data class StoredOAuthSession(
val clientId: String,
val clientSecret: String,
val refreshToken: String,
val tokenAuthMethod: TokenEndpointAuthMethod,
val tokenEndpoint: String
)

fun CoderOAuthSessionContext?.hasRefreshToken(): Boolean = this?.tokenResponse?.refreshToken != null
Loading
Loading