Skip to content

Add extra help for certificate errors #279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.URL
import java.net.UnknownHostException
import javax.net.ssl.SSLHandshakeException
import javax.swing.Icon
import javax.swing.JCheckBox
import javax.swing.JLabel
import javax.swing.JTable
import javax.swing.JTextField
import javax.swing.ListSelectionModel
Expand All @@ -101,6 +103,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
private val appPropertiesService: PropertiesComponent = service()

private var tfUrl: JTextField? = null
private var tfUrlComment: JLabel? = null
private var cbExistingToken: JCheckBox? = null

private val notificationBanner = NotificationBanner()
Expand All @@ -116,7 +119,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
minWidth = JBUI.scale(52)
}
rowHeight = 48
setEmptyState("Disconnected")
setEmptyState(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.disconnected"))
setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
selectionModel.addListSelectionListener {
setNextButtonEnabled(selectedObject?.agentStatus?.ready() == true && selectedObject?.agentOS == OS.LINUX)
Expand Down Expand Up @@ -186,6 +189,16 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
background = WelcomeScreenUIManager.getMainAssociatedComponentBackground()
}
}.layout(RowLayout.PARENT_GRID)
row {
cell() // Empty cells for alignment.
tfUrlComment = cell(
ComponentPanelBuilder.createCommentComponent(
CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.comment",
CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text")),
false, -1, true
)
).resizableColumn().align(AlignX.FILL).component
}.layout(RowLayout.PARENT_GRID)
row {
cell() // Empty cell for alignment.
cbExistingToken = checkBox(CoderGatewayBundle.message("gateway.connector.view.login.existing-token.label"))
Expand Down Expand Up @@ -410,7 +423,9 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
// Clear out old deployment details.
cliManager = null
poller?.cancel()
tableOfWorkspaces.setEmptyState("Connecting to $deploymentURL...")
tfUrlComment?.foreground = UIUtil.getContextHelpForeground()
tfUrlComment?.text = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connecting", deploymentURL.host)
tableOfWorkspaces.setEmptyState(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connecting", deploymentURL.host))
tableOfWorkspaces.listTableModel.items = emptyList()

// Authenticate and load in a background process with progress.
Expand Down Expand Up @@ -444,44 +459,55 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
triggerWorkspacePolling(false)

cliManager = cli
tableOfWorkspaces.setEmptyState("Connected to $deploymentURL")
tableOfWorkspaces.setEmptyState(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connected", deploymentURL.host))
tfUrlComment?.text = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connected", deploymentURL.host)
} catch (e: Exception) {
val errorSummary = when (e) {
is java.nio.file.AccessDeniedException -> "Access denied to ${e.file}"
is UnknownHostException -> "Unknown host ${e.message}"
is InvalidExitValueException -> "CLI exited unexpectedly with ${e.exitValue}"
else -> e.message ?: "No reason was provided"
}
var msg = CoderGatewayBundle.message(
"gateway.connector.view.workspaces.connect.failed",
deploymentURL,
errorSummary,
)
when (e) {
val reason = e.message ?: CoderGatewayBundle.message("gateway.connector.view.workspaces.connect.no-reason")
val msg = when (e) {
is java.nio.file.AccessDeniedException -> CoderGatewayBundle.message("gateway.connector.view.workspaces.connect.access-denied", e.file)
is UnknownHostException -> CoderGatewayBundle.message("gateway.connector.view.workspaces.connect.unknown-host", e.message ?: deploymentURL.host)
is InvalidExitValueException -> CoderGatewayBundle.message("gateway.connector.view.workspaces.connect.unexpected-exit", e.exitValue)
is AuthenticationResponseException -> {
msg = CoderGatewayBundle.message(
CoderGatewayBundle.message(
"gateway.connector.view.workspaces.connect.unauthorized",
deploymentURL,
)
cs.launch { onAuthFailure?.invoke() }
}

is SocketTimeoutException -> {
msg = CoderGatewayBundle.message(
CoderGatewayBundle.message(
"gateway.connector.view.workspaces.connect.timeout",
deploymentURL,
)
}

is ResponseException, is ConnectException -> {
msg = CoderGatewayBundle.message(
CoderGatewayBundle.message(
"gateway.connector.view.workspaces.connect.download-failed",
errorSummary,
reason,
)
}
is SSLHandshakeException -> {
CoderGatewayBundle.message(
"gateway.connector.view.workspaces.connect.ssl-error",
deploymentURL.host,
reason,
)
}
else -> reason
}
tableOfWorkspaces.setEmptyState(msg)
// It would be nice to place messages directly into the table
// but it does not support wrapping or markup so place it in the
// comment field of the URL input instead.
tfUrlComment?.foreground = UIUtil.getErrorForeground()
tfUrlComment?.text = msg
tableOfWorkspaces.setEmptyState(CoderGatewayBundle.message(
"gateway.connector.view.workspaces.connect.failed",
deploymentURL.host,
))
logger.error(msg, e)

if (e is AuthenticationResponseException) {
cs.launch { onAuthFailure?.invoke() }
}
}
}
}
Expand Down
17 changes: 14 additions & 3 deletions src/main/resources/messages/CoderGatewayBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ gateway.connector.view.login.token.label=Session Token:
gateway.connector.view.coder.workspaces.header.text=Coder Workspaces
gateway.connector.view.coder.workspaces.comment=Self-hosted developer workspaces in the cloud or on-premises. Coder empowers developers with secure, consistent, and fast developer workspaces.
gateway.connector.view.coder.workspaces.connect.text=Connect
gateway.connector.view.coder.workspaces.connect.text.comment=Please enter your deployment URL and press "{0}".
gateway.connector.view.coder.workspaces.connect.text.disconnected=Disconnected
gateway.connector.view.coder.workspaces.connect.text.connected=Connected to {0}
gateway.connector.view.coder.workspaces.connect.text.connecting=Connecting to {0}...
gateway.connector.view.coder.workspaces.cli.downloader.dialog.title=Authenticate and setup Coder
gateway.connector.view.coder.workspaces.next.text=Select IDE and project
gateway.connector.view.coder.workspaces.dashboard.text=Open dashboard
Expand All @@ -19,12 +23,19 @@ gateway.connector.view.coder.workspaces.stop.text=Stop workspace
gateway.connector.view.coder.workspaces.update.text=Update workspace template
gateway.connector.view.coder.workspaces.create.text=Create workspace
gateway.connector.view.coder.workspaces.unsupported.os.info=Gateway supports only Linux machines. Support for macOS and Windows is planned.
gateway.connector.view.coder.workspaces.invalid.coder.version=Could not parse Coder version {0}. Coder Gateway plugin might not be compatible with this version. <a href='https://coder.com/docs/coder-oss/latest/ides/gateway#creating-a-new-jetbrains-gateway-connection'>Connect to a Coder workspace manually</a>
gateway.connector.view.coder.workspaces.unsupported.coder.version=Coder version {0} might not be compatible with this plugin version. <a href='https://coder.com/docs/coder-oss/latest/ides/gateway#creating-a-new-jetbrains-gateway-connection'>Connect to a Coder workspace manually</a>
gateway.connector.view.coder.workspaces.invalid.coder.version=Could not parse Coder version {0}. Coder Gateway plugin might not be compatible with this version. <a href='https://coder.com/docs/v2/latest/ides/gateway#creating-a-new-jetbrains-gateway-connection'>Connect to a Coder workspace manually</a>
gateway.connector.view.coder.workspaces.unsupported.coder.version=Coder version {0} might not be compatible with this plugin version. <a href='https://coder.com/docs/v2/latest/ides/gateway#creating-a-new-jetbrains-gateway-connection'>Connect to a Coder workspace manually</a>
gateway.connector.view.workspaces.connect.failed=Connection to {0} failed. See above for details.
gateway.connector.view.workspaces.connect.no-reason=No reason was provided.
gateway.connector.view.workspaces.connect.access-denied=Access denied to {0}.
gateway.connector.view.workspaces.connect.unknown-host=Unknown host {0}.
gateway.connector.view.workspaces.connect.unexpected-exit=CLI exited unexpectedly with {0}.
gateway.connector.view.workspaces.connect.unauthorized=Token was rejected by {0}; has your token expired?
gateway.connector.view.workspaces.connect.timeout=Unable to connect to {0}; is it up?
gateway.connector.view.workspaces.connect.download-failed=Failed to download Coder CLI: {0}
gateway.connector.view.workspaces.connect.failed=Failed to connect to {0}: {1}
gateway.connector.view.workspaces.connect.ssl-error=Connection to {0} failed: {1}. See the \
<a href='https://coder.com/docs/v2/latest/ides/gateway#configuring-the-gateway-plugin-to-use-internal-certificates'>documentation for TLS certificates</a> \
for information on how to make your system trust certificates coming from your deployment.
gateway.connector.view.workspaces.token.comment=The last used token is shown above.
gateway.connector.view.workspaces.token.rejected=This token was rejected.
gateway.connector.view.workspaces.token.injected=This token was pulled from your CLI config.
Expand Down