11package com.coder.toolbox.views
22
33import com.coder.toolbox.CoderToolboxContext
4+ import com.coder.toolbox.browser.browse
5+ import com.coder.toolbox.oauth.ClientRegistrationRequest
6+ import com.coder.toolbox.oauth.CoderAuthorizationApi
7+ import com.coder.toolbox.oauth.CoderOAuthCfg
8+ import com.coder.toolbox.plugin.PluginManager
9+ import com.coder.toolbox.sdk.CoderHttpClientBuilder
10+ import com.coder.toolbox.sdk.convertors.LoggingConverterFactory
11+ import com.coder.toolbox.sdk.interceptors.Interceptors
412import com.coder.toolbox.util.WebUrlValidationResult.Invalid
513import com.coder.toolbox.util.toURL
614import com.coder.toolbox.util.validateStrictWebUrl
@@ -14,8 +22,12 @@ import com.jetbrains.toolbox.api.ui.components.RowGroup
1422import com.jetbrains.toolbox.api.ui.components.TextField
1523import com.jetbrains.toolbox.api.ui.components.TextType
1624import com.jetbrains.toolbox.api.ui.components.ValidationErrorField
25+ import com.squareup.moshi.Moshi
1726import kotlinx.coroutines.flow.StateFlow
1827import kotlinx.coroutines.flow.update
28+ import kotlinx.coroutines.launch
29+ import retrofit2.Retrofit
30+ import retrofit2.converter.moshi.MoshiConverterFactory
1931import java.net.MalformedURLException
2032import java.net.URL
2133
@@ -42,6 +54,16 @@ class DeploymentUrlStep(
4254
4355 private val errorField = ValidationErrorField (context.i18n.pnotr(" " ))
4456
57+ val interceptors = buildList {
58+ add((Interceptors .userAgent(PluginManager .pluginInfo.version)))
59+ add(Interceptors .logging(context))
60+ }
61+ val okHttpClient = CoderHttpClientBuilder .build(
62+ context,
63+ interceptors
64+ )
65+
66+
4567 override val panel: RowGroup
4668 get() {
4769 if (! context.settingsStore.disableSignatureVerification) {
@@ -86,6 +108,61 @@ class DeploymentUrlStep(
86108 errorReporter.report(" URL is invalid" , e)
87109 return false
88110 }
111+ val service = Retrofit .Builder ()
112+ .baseUrl(CoderCliSetupContext .url!! )
113+ .client(okHttpClient)
114+ .addConverterFactory(
115+ LoggingConverterFactory .wrap(
116+ context,
117+ MoshiConverterFactory .create(Moshi .Builder ().build())
118+ )
119+ )
120+ .build()
121+ .create(CoderAuthorizationApi ::class .java)
122+ context.cs.launch {
123+ context.logger.info(" >> checking if Coder supports OAuth2" )
124+ val response = service.discoveryMetadata()
125+ if (response.isSuccessful) {
126+ val authServer = requireNotNull(response.body()) {
127+ " Successful response returned null body or oauth server discovery metadata"
128+ }
129+ context.logger.info(" >> registering coder-jetbrains-toolbox as client app $response " )
130+ val clientResponse = service.registerClient(
131+ ClientRegistrationRequest (
132+ clientName = " coder-jetbrains-toolbox" ,
133+ redirectUris = listOf (" jetbrains://gateway/com.coder.toolbox/auth" ),// URLEncoder.encode("jetbrains://gateway/com.coder.toolbox/oauth", StandardCharsets.UTF_8.toString())),
134+ grantTypes = listOf (" authorization_code" , " refresh_token" ),
135+ responseTypes = authServer.supportedResponseTypes,
136+ scope = " coder:workspaces.operate coder:workspaces.delete coder:workspaces.access user:read" ,
137+ tokenEndpointAuthMethod = " client_secret_post"
138+ )
139+ )
140+ if (clientResponse.isSuccessful) {
141+ val clientResponse =
142+ requireNotNull(clientResponse.body()) { " Successful response returned null body or client registration metadata" }
143+ context.logger.info(" >> initiating oauth login with $clientResponse " )
144+
145+ val oauthCfg = CoderOAuthCfg (
146+ baseUrl = CoderCliSetupContext .url!! .toString(),
147+ authUrl = authServer.authorizationEndpoint,
148+ tokenUrl = authServer.tokenEndpoint,
149+ clientId = clientResponse.clientId,
150+ clientSecret = clientResponse.clientSecret,
151+ )
152+
153+ val loginUrl = context.oauthManager.initiateLogin(oauthCfg)
154+ context.logger.info(" >> retrieving token" )
155+ context.desktop.browse(loginUrl) {
156+ context.ui.showErrorInfoPopup(it)
157+ }
158+ val token = context.oauthManager.getToken(" coder" , forceRefresh = false )
159+ context.logger.info(" >> token is $token " )
160+ } else {
161+ context.logger.error(" >> ${clientResponse.code()} ${clientResponse.message()} || ${clientResponse.errorBody()} " )
162+ }
163+ }
164+ }
165+
89166 if (context.settingsStore.requireTokenAuth) {
90167 CoderCliSetupWizardState .goToNextStep()
91168 } else {
0 commit comments