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
6 changes: 1 addition & 5 deletions build/dockerfiles/dev.sshd.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,11 @@ RUN sed -i \
-e 's|#HostKey /etc/ssh/ssh_host_ed25519_key|HostKey /opt/ssh/ssh_host_ed25519_key|' \
/opt/ssh/sshd_config

# Prepare SSH Keys
RUN ssh-keygen -q -N "" -t ed25519 -f /opt/ssh/ssh_client_ed25519_key
RUN chmod 644 /opt/ssh/ssh_client_*

# Add script to start and stop the service
COPY --chown=0:0 /build/scripts/sshd.start /

RUN mkdir /opt/www
COPY /build/scripts/server.js /opt/www/
COPY /build/scripts/code-sshd-page/* /opt/www/

# Lock down /etc/passwd until fixed in UDI
RUN chmod 644 /etc/passwd
Expand Down
64 changes: 64 additions & 0 deletions build/scripts/code-sshd-page/page-style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright (c) 2025 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
*/

pre {
background-color: #f6f8fa; /* Light gray background */
overflow-x: auto; /* Enable horizontal scrolling for long lines */
font-family: monospace;
font-size: 14px;
display: table-cell;
width: 98%;
padding: 10px;
}

code {
background-color: #e3e6e8; /* Slightly darker gray for inline code */
padding: 2px 4px;
border-radius: 3px;
font-family: monospace;
font-size: 0.9em; /* Slightly smaller than surrounding text */
}

.parent {
background-color: #f6f8fa; /* Light gray background */
display: table;
width: 100%;
}

.clipboard {
background-color: #f6f8fa; /* Light gray background */
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; /* Slightly darker gray for inline code */
width: 10px;
height: 10px;
border: 1px solid black;
border-radius: 5px;
padding: 3px;
vertical-align: bottom;
}

.clipboard-img-pre:hover {
background:#e3e6e8;
}

.clipboard-img-code:hover {
background-color: #f6f8fa;
}
27 changes: 27 additions & 0 deletions build/scripts/code-sshd-page/page-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
Copyright (c) 2025 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;
}
}
}
157 changes: 157 additions & 0 deletions build/scripts/code-sshd-page/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
Copyright (c) 2025 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 os = require('os');

const hostname = '127.0.0.1';
const port = 3400;

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(`${process.env["HOME"]}/.ssh/ssh_client_ed25519_key`, 'utf8');
} catch (err) {
// continue
}

let keyMessage = hasUserPrefSSHKey ? pubKey : genKey;

res.end(`
<!DOCTYPE html>
<html>
<head>
<title>${process.env["DEVWORKSPACE_NAME"]}</title>
<link rel="stylesheet" href="page-style.css">
<script src="page-utils.js"></script>
</head>
<body>
<h1>Workspace ${process.env["DEVWORKSPACE_NAME"]} is running</h1>
<div class="border">
<ol>
<li>Make sure your local <a href="${process.env["CLUSTER_CONSOLE_URL"]}/command-line-tools">oc client</a> is <a href="https://oauth-openshift${getHostURL()}/oauth/token/request">logged in</a> to your OpenShift cluster</li>
<li><p class="center">Run <code id="port-forward">oc port-forward -n ${process.env["DEVWORKSPACE_NAMESPACE"]} ${process.env["HOSTNAME"]} 2022:2022</code><a href="#"><svg class="clipboard-img-code" onclick="copyToClipboard('port-forward')" title="Copy" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 20 20">
<path fill="currentColor" d="M12 0H2C.9 0 0 .9 0 2v10h1V2c0-.6.4-1 1-1h10V0z"></path>
<path fill="currentColor" d="M18 20H8c-1.1 0-2-.9-2-2V8c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2v10c0 1.1-.9 2-2 2zM8 7c-.6 0-1 .4-1 1v10c0 .6.4 1 1 1h10c.6 0 1-.4 1-1V8c0-.6-.4-1-1-1H8z"></path>
</svg></a>. This establishes a connection to the workspace.</p></li>
<li>
In your local VS Code instance, with either <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh">"Remote - SSH"</a> (for VS Code), or <a href="https://open-vsx.org/extension/jeanp413/open-remote-ssh">"Open Remote - SSH"</a> (for Code-OSS), connect to <code>localhost</code> on port <code>2022</code> with user <code>${os.userInfo().username}</code> ${hasUserPrefSSHKey ? `. The SSH key, corresponding to the following public key, configured in the "SSH Keys" tab of "User Preferences" has been authorized to connect :` : `and the following identity file :`}
<div class="parent">
<div>
<pre id="key">${keyMessage}</pre>
</div>
<div class="clipboard">
<a href="#">
<svg class="clipboard-img-pre" onclick="copyToClipboard('key')" title="Copy" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 20 20">
<path fill="currentColor" d="M12 0H2C.9 0 0 .9 0 2v10h1V2c0-.6.4-1 1-1h10V0z"></path>
<path fill="currentColor" d="M18 20H8c-1.1 0-2-.9-2-2V8c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2v10c0 1.1-.9 2-2 2zM8 7c-.6 0-1 .4-1 1v10c0 .6.4 1 1 1h10c.6 0 1-.4 1-1V8c0-.6-.4-1-1-1H8z"></path>
</svg>
</a>
</div>
</div>
<p>
<b>&#9888; Please ensure the permissions on the private key used are restricted to allow only the file owner to read/write. The SSH service may fail to correctly authenticate otherwise.</b>
</p>
This can also be configured locally in the client SSH configuration file (eg. <code class="path">$HOME/.ssh/config</code>) with the following :
<div class="parent">
<div>
<pre id="config" class="path">Host localhost
HostName 127.0.0.1
User ${os.userInfo().username}
Port 2022
IdentityFile $HOME/.ssh/ssh_client_ed25519_key
UserKnownHostsFile /dev/null</pre>
</div>
<div class="clipboard">
<a href="#">
<svg class="clipboard-img-pre" onclick="copyToClipboard('config')" title="Copy" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 20 20">
<path fill="currentColor" d="M12 0H2C.9 0 0 .9 0 2v10h1V2c0-.6.4-1 1-1h10V0z"></path>
<path fill="currentColor" d="M18 20H8c-1.1 0-2-.9-2-2V8c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2v10c0 1.1-.9 2-2 2zM8 7c-.6 0-1 .4-1 1v10c0 .6.4 1 1 1h10c.6 0 1-.4 1-1V8c0-.6-.4-1-1-1H8z"></path>
</svg>
</a>
</div>
</div>
<p>
Where <code class="path">$HOME/.ssh/ssh_client_ed25519_key</code> should be replaced by the absolute path to the private key file on your local system.
</p>
</li>
</ol>
<h3>Troubleshooting</h3>
<p>If the connection fails with "<code>WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED</code>", it may be necessary to remove the <code>localhost</code> or <code>127.0.0.1</code> entries from <code class="path">$HOME/.ssh/known_hosts</code>. This is because the SSHD service container (to which <code>oc port-forward</code> is forwarding) may change. This can be bypassed by setting <code>UserKnownHostsFile <span class="path">/dev/null</span></code></p>
<p>If the connection fails for an unknown reason, consider disabling the setting <code>remote.SSH.useExecServer</code> (set to false)</p>
<p>For any other issues, relating to the use of a VS Code-based editor and the "Remote - SSH", the "Remote - SSH" logs from the "Output" view are very helpful in diagnosing the issue.</p>
</div>
<script>initializePlatformContent();</script>
</body>
</html>
`);
} 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 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) {
if (consoleURL.substring(consoleURL.length - 1 - i) != devspacesURL.substring(devspacesURL.length - 1 - i)) {
if (i != 0) {
break;
}
}
i++;
}
return consoleURL.substring(consoleURL.length - i);
}
80 changes: 0 additions & 80 deletions build/scripts/server.js

This file was deleted.

3 changes: 2 additions & 1 deletion build/scripts/sshd.start
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ mkdir -p $HOME/.ssh
if [ -f /etc/ssh/dwo_ssh_key.pub ]; then
cp /etc/ssh/dwo_ssh_key.pub $HOME/.ssh/authorized_keys
else
cp /opt/ssh/ssh_client_ed25519_key.pub $HOME/.ssh/authorized_keys
ssh-keygen -q -N "" -t ed25519 -f $HOME/.ssh/ssh_client_ed25519_key
cp $HOME/.ssh/ssh_client_ed25519_key.pub $HOME/.ssh/authorized_keys
fi

# start
Expand Down
Loading