Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Changed

- skip the Coder TLS alternate hostname when fetching IDE metadata from JetBrains

## 0.9.0 - 2026-05-14

### Added
Expand Down
12 changes: 10 additions & 2 deletions src/main/kotlin/com/coder/toolbox/feed/IdeFeedManager.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.coder.toolbox.feed

import com.coder.toolbox.CoderToolboxContext
import com.coder.toolbox.sdk.CoderHttpClientBuilder
import com.coder.toolbox.plugin.PluginManager
import com.coder.toolbox.sdk.interceptors.Interceptors
import com.coder.toolbox.sdk.proxy.applyProxySettings
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.nio.file.Path
Expand Down Expand Up @@ -40,7 +43,12 @@ class IdeFeedManager(
private val feedService: JetBrainsFeedService by lazy {
if (feedService != null) return@lazy feedService

val okHttpClient = CoderHttpClientBuilder.default(context)
val okHttpClient = OkHttpClient.Builder()
.applyProxySettings(context)
.addInterceptor(Interceptors.userAgent(PluginManager.pluginInfo.version))
.addInterceptor(Interceptors.logging(context))
.retryOnConnectionFailure(true)
.build()

val retrofit = Retrofit.Builder()
.baseUrl("https://data.services.jetbrains.com/")
Expand Down
32 changes: 4 additions & 28 deletions src/main/kotlin/com/coder/toolbox/sdk/CoderHttpClientBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ package com.coder.toolbox.sdk
import com.coder.toolbox.CoderToolboxContext
import com.coder.toolbox.plugin.PluginManager
import com.coder.toolbox.sdk.interceptors.Interceptors
import com.coder.toolbox.sdk.proxy.applyProxySettings
import com.coder.toolbox.util.CoderHostnameVerifier
import com.coder.toolbox.util.ReloadableTlsContext
import com.jetbrains.toolbox.api.remoteDev.connection.ProxyAuth
import okhttp3.Credentials
import okhttp3.Interceptor
import okhttp3.OkHttpClient

Expand All @@ -17,36 +16,13 @@ object CoderHttpClientBuilder {
tlsContext: ReloadableTlsContext
): OkHttpClient {
val builder = OkHttpClient.Builder()

context.proxySettings.getProxy()?.let { proxy ->
context.logger.info("proxy: $proxy")
builder.proxy(proxy)
} ?: context.proxySettings.getProxySelector()?.let { proxySelector ->
context.logger.info("proxy selector: $proxySelector")
builder.proxySelector(proxySelector)
}

// Note: This handles only HTTP/HTTPS proxy authentication.
// SOCKS5 proxy authentication is currently not supported due to limitations described in:
// https://youtrack.jetbrains.com/issue/TBX-14532/Missing-proxy-authentication-settings#focus=Comments-27-12265861.0-0
builder.proxyAuthenticator { _, response ->
val proxyAuth = context.proxySettings.getProxyAuth()
if (proxyAuth == null || proxyAuth !is ProxyAuth.Basic) {
return@proxyAuthenticator null
}
val credentials = Credentials.basic(proxyAuth.username, proxyAuth.password)
response.request.newBuilder()
.header("Proxy-Authorization", credentials)
.build()
}

builder.sslSocketFactory(tlsContext.sslSocketFactory, tlsContext.trustManager)
.applyProxySettings(context)
.sslSocketFactory(tlsContext.sslSocketFactory, tlsContext.trustManager)
.hostnameVerifier(CoderHostnameVerifier(context.settingsStore.tls.altHostname))
.retryOnConnectionFailure(true)

interceptors.forEach { interceptor ->
builder.addInterceptor(interceptor)

}
return builder.build()
}
Expand All @@ -62,4 +38,4 @@ object CoderHttpClientBuilder {
ReloadableTlsContext(context.settingsStore.readOnly().tls)
)
}
}
}
36 changes: 36 additions & 0 deletions src/main/kotlin/com/coder/toolbox/sdk/proxy/Proxies.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.coder.toolbox.sdk.proxy

import com.coder.toolbox.CoderToolboxContext
import com.jetbrains.toolbox.api.remoteDev.connection.ProxyAuth
import okhttp3.Credentials
import okhttp3.OkHttpClient

/**
* Applies the user's Toolbox proxy and proxy authentication settings to this builder.
*
* Note: This handles only HTTP/HTTPS proxy authentication. SOCKS5 proxy authentication is currently
* not supported due to limitations described in:
* https://youtrack.jetbrains.com/issue/TBX-14532/Missing-proxy-authentication-settings#focus=Comments-27-12265861.0-0
*/
fun OkHttpClient.Builder.applyProxySettings(context: CoderToolboxContext): OkHttpClient.Builder {
context.proxySettings.getProxy()?.let { proxy ->
context.logger.info("proxy: $proxy")
proxy(proxy)
} ?: context.proxySettings.getProxySelector()?.let { proxySelector ->
context.logger.info("proxy selector: $proxySelector")
proxySelector(proxySelector)
}

proxyAuthenticator { _, response ->
val proxyAuth = context.proxySettings.getProxyAuth()
if (proxyAuth == null || proxyAuth !is ProxyAuth.Basic) {
return@proxyAuthenticator null
}
val credentials = Credentials.basic(proxyAuth.username, proxyAuth.password)
response.request.newBuilder()
.header("Proxy-Authorization", credentials)
.build()
}

return this
}
Loading