diff --git a/build/dockerfiles/assembly.sshd.Dockerfile b/build/dockerfiles/assembly.sshd.Dockerfile index 44ba243a06b..82db93a8f67 100644 --- a/build/dockerfiles/assembly.sshd.Dockerfile +++ b/build/dockerfiles/assembly.sshd.Dockerfile @@ -36,8 +36,10 @@ RUN cp /etc/ssh/sshd_config /sshd-staging/ # Add script to start and stop the service COPY --chown=0:0 /build/scripts/sshd.init /build/scripts/sshd.start /sshd-staging/ -RUN mkdir /opt/www -COPY /build/scripts/code-sshd-page/* /opt/www/ +RUN mkdir -p /opt/www/code /opt/www/jetbrains + +COPY /build/scripts/code-sshd-page/* /opt/www/code +COPY /build/scripts/jetbrains-sshd-page/* /opt/www/jetbrains # Lock down /etc/passwd until fixed in UDI RUN chmod 644 /etc/passwd diff --git a/build/scripts/jetbrains-sshd-page/page-style.css b/build/scripts/jetbrains-sshd-page/page-style.css new file mode 100644 index 00000000000..00a29c7300b --- /dev/null +++ b/build/scripts/jetbrains-sshd-page/page-style.css @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2026 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +body { + padding-top: 300px; + background-color: #d8d8d8; + color: #444; + font-family: sans-serif; +} +h1 { + font-weight: bold; + text-align: center; +} +a { + color: #0465d7; +} +.center { + text-align: center; +} +.border { + border-style: solid; + padding: 5px; + margin: auto; + width: fit-content; +} + + + +/* Container for code block & clipboard icon */ +.parent { + background-color: #f6f8fa; + display: table; + width: 100%; +} + +/* Container for clipboard icon of code block */ +.clipboard { + background-color: #f6f8fa; + display: table-cell; + width: 2%; +} + +.clipboard-img-pre { + width: 15px; + height: 15px; + border: 2px solid black; + border-radius: 5px; + padding: 3px; +} + +.clipboard-img-code { + background-color: #e3e6e8; + width: 10px; + height: 10px; + border: 1px solid black; + border-radius: 5px; + padding: 3px; + vertical-align: bottom; +} + + +/* Colour change for clipboard icon hover */ +.clipboard-img-pre:hover { + background:#e3e6e8; +} + +.clipboard-img-code:hover { + background-color: #f6f8fa; +} + diff --git a/build/scripts/jetbrains-sshd-page/page-utils.js b/build/scripts/jetbrains-sshd-page/page-utils.js new file mode 100644 index 00000000000..3701b0b0c46 --- /dev/null +++ b/build/scripts/jetbrains-sshd-page/page-utils.js @@ -0,0 +1,26 @@ +/* + Copyright (c) 2026 Red Hat, Inc. + This program and the accompanying materials are made + available under the terms of the Eclipse Public License 2.0 + which is available at https://www.eclipse.org/legal/epl-2.0/ + + SPDX-License-Identifier: EPL-2.0 +*/ + +function copyToClipboard(id) { + var copyText = document.getElementById(id); + navigator.clipboard.writeText(copyText.innerHTML); +} + +function initializePlatformContent() { + if (navigator.userAgent.indexOf('Windows') !== -1) { + var pathEntries = document.getElementsByClassName('path'); + for (var i = 0; i < pathEntries.length; i++) { + var currText = pathEntries[i].innerHTML; + currText = currText.replaceAll("/dev/null", "nul"); + currText = currText.replaceAll("$HOME", "%USERPROFILE%"); + currText = currText.replaceAll("/","\\"); + pathEntries[i].innerHTML = currText; + } + } +} diff --git a/build/scripts/jetbrains-sshd-page/server.js b/build/scripts/jetbrains-sshd-page/server.js new file mode 100644 index 00000000000..87e3005a380 --- /dev/null +++ b/build/scripts/jetbrains-sshd-page/server.js @@ -0,0 +1,136 @@ +/* + Copyright (c) 2026 Red Hat, Inc. + This program and the accompanying materials are made + available under the terms of the Eclipse Public License 2.0 + which is available at https://www.eclipse.org/legal/epl-2.0/ + + SPDX-License-Identifier: EPL-2.0 +*/ + +const http = require('http'); +const fs = require('fs'); + +const hostname = '127.0.0.1'; +const port = 3400; + +let username = "UNKNOWN"; +try { + username = fs.readFileSync(`/sshd/username`, 'utf8'); +} catch (error) { + // continue +} + +const server = http.createServer((req, res) => { + if (req.url === '/') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html'); + + let hasUserPrefSSHKey = fs.existsSync('/etc/ssh/dwo_ssh_key.pub'); + + let pubKey = "PUBLIC KEY COULD NOT BE DISPLAYED"; + try { + pubKey = fs.readFileSync('/etc/ssh/dwo_ssh_key.pub', 'utf8'); + } catch (err) { + // continue + } + + let genKey = "PRIVATE KEY NOT FOUND"; + try { + genKey = fs.readFileSync(`/sshd/ssh_client_ed25519_key`, 'utf8'); + } catch (err) { + // continue + } + + let keyMessage = hasUserPrefSSHKey ? pubKey : genKey; + + res.end(` + + + + ${process.env["DEVWORKSPACE_NAME"]} + + + + + + +

Workspace ${process.env["DEVWORKSPACE_NAME"]} is running

+ + +
+

Make sure your local oc client is logged in to your OpenShift cluster

+

Run oc port-forward -n ${process.env["DEVWORKSPACE_NAMESPACE"]} ${process.env["HOSTNAME"]} 2022:2022 + + + . This establishes a connection to the workspace.

+
+ +

Can't open the workspace?

+

If your browser doesn't ask you to open Toolbox, make sure the prerequisites mentioned in the documentation are met.

+ + +

Open the workspace over Toolbox

+

Open Dashboard

+ + + + + `); + } else { + let loc = req.url.substring(1); + let isBinaryData = false; + let content = ""; + + res.statusCode = 200; + if (loc.endsWith(".css")) { + res.setHeader("Content-Type", "text/css"); + } else if (loc.endsWith(".js")) { + res.setHeader("Content-Type", "text/javascript"); + } else if (loc.endsWith(".png")) { + res.setHeader("Content-Type", "image/png"); + isBinaryData = true; + } else { + res.setHeader("Content-Type", "text/plain"); + } + + try { + content = fs.readFileSync(loc, isBinaryData ? null : "utf8"); + } catch (err) { + // continue + res.statusCode = 404; + res.setHeader("Content-Type", "text/plain"); + content = "Not Found"; + } + res.end(content); + } +}); + +server.listen(port, hostname, () => { + console.log(`Server is running at http://${hostname}:${port}/`); +}); + +function getHostURL () { + const consoleURL = process.env["CLUSTER_CONSOLE_URL"]; + const devspacesURL = process.env["CHE_DASHBOARD_URL"]; + if (consoleURL === undefined || devspacesURL === undefined) { + return undefined; + } + let i = 0; + while (i < consoleURL.length && i < devspacesURL.length + && consoleURL.substring(consoleURL.length - 1 - i) === devspacesURL.substring(devspacesURL.length - 1 - i)) { + i++; + } + return consoleURL.substring(consoleURL.length - i); +} diff --git a/build/scripts/sshd.init b/build/scripts/sshd.init index 0f795129839..636a7306482 100755 --- a/build/scripts/sshd.init +++ b/build/scripts/sshd.init @@ -17,6 +17,11 @@ while [ ! -e /sshd/username ]; do done # start the landing page -pushd /opt/www/ -exec node /opt/www/server.js +ide_provider="$1" +if [ "$ide_provider" = "jetbrains" ]; then + pushd /opt/www/jetbrains + else # default to landing page for Code + pushd /opt/www/code +fi +exec node server.js