Skip to content

Commit 612d9b8

Browse files
committed
[gitpod-desktop] Connect using ssh gateway
1 parent 25542be commit 612d9b8

File tree

9 files changed

+546
-173
lines changed

9 files changed

+546
-173
lines changed

extensions/gitpod-web/src/util/zip.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok
160160

161161
function openZip(zipFile: string, lazy: boolean = false): Promise<ZipFile> {
162162
return new Promise<ZipFile>((resolve, reject) => {
163-
_openZip(zipFile, lazy ? { lazyEntries: true } : undefined!, (error?: Error, zipfile?: ZipFile) => {
163+
_openZip(zipFile, lazy ? { lazyEntries: true } : undefined!, (error: Error | null, zipfile?: ZipFile) => {
164164
if (error) {
165165
reject(toExtractError(error));
166166
} else {
@@ -172,7 +172,7 @@ function openZip(zipFile: string, lazy: boolean = false): Promise<ZipFile> {
172172

173173
function openZipStream(zipFile: ZipFile, entry: Entry): Promise<Readable> {
174174
return new Promise<Readable>((resolve, reject) => {
175-
zipFile.openReadStream(entry, (error?: Error, stream?: Readable) => {
175+
zipFile.openReadStream(entry, (error: Error | null, stream?: Readable) => {
176176
if (error) {
177177
reject(toExtractError(error));
178178
} else {

extensions/gitpod/extension.webpack.config.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
'use strict';
99

1010
const withDefaults = require('../shared.webpack.config');
11+
const webpack = require('webpack');
1112

1213
module.exports = withDefaults({
1314
context: __dirname,
@@ -16,5 +17,13 @@ module.exports = withDefaults({
1617
},
1718
externals: {
1819
'keytar': 'commonjs keytar'
19-
}
20+
},
21+
plugins: [
22+
new webpack.IgnorePlugin({
23+
resourceRegExp: /crypto\/build\/Release\/sshcrypto\.node$/,
24+
}),
25+
new webpack.IgnorePlugin({
26+
resourceRegExp: /cpu-features/,
27+
})
28+
]
2029
});

extensions/gitpod/package.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
"description": "Gitpod Service URL. Update this if you are using a Gitpod self-hosted installation.",
4949
"default": "https://gitpod.io/",
5050
"scope": "application"
51+
},
52+
"gitpod.remote.useLocalApp":{
53+
"type":"boolean",
54+
"description": "Use the local companion app to connect to a remote workspace.\nWarning: Connecting to a remote workspace using local companion app will be removed in the near future.",
55+
"default": false,
56+
"scope": "application"
5157
}
5258
}
5359
},
@@ -93,6 +99,7 @@
9399
"@types/crypto-js": "4.1.1",
94100
"@types/node": "16.x",
95101
"@types/node-fetch": "^2.5.12",
102+
"@types/ssh2": "^0.5.52",
96103
"@types/tmp": "^0.2.1",
97104
"@types/uuid": "8.0.0",
98105
"@types/ws": "^7.2.6",
@@ -105,11 +112,9 @@
105112
"analytics-node": "^6.0.0",
106113
"node-fetch": "2.6.7",
107114
"pkce-challenge": "^3.0.0",
115+
"ssh2": "^1.10.0",
108116
"tmp": "^0.2.1",
109117
"uuid": "8.1.0",
110118
"yazl": "^2.5.1"
111-
},
112-
"extensionDependencies": [
113-
"ms-vscode-remote.remote-ssh"
114-
]
119+
}
115120
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Gitpod. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
import * as os from 'os';
6+
import * as fs from 'fs';
7+
import * as path from 'path';
8+
import * as crypto from 'crypto';
9+
10+
const KNOW_HOST_FILE = path.join(os.homedir(), '.ssh', 'known_hosts');
11+
const HASH_MAGIC = '|1|';
12+
const HASH_DELIM = '|';
13+
14+
export async function checkNewHostInHostkeys(host: string): Promise<boolean> {
15+
const fileContent = await fs.promises.readFile(KNOW_HOST_FILE, { encoding: 'utf8' });
16+
const lines = fileContent.split(/\r?\n/);
17+
for (let line of lines) {
18+
line = line.trim();
19+
if (!line.startsWith(HASH_MAGIC)) {
20+
continue;
21+
}
22+
23+
const [hostEncripted_] = line.split(' ');
24+
const [salt_, hostHash_] = hostEncripted_.substring(HASH_MAGIC.length).split(HASH_DELIM);
25+
const hostHash = crypto.createHmac('sha1', Buffer.from(salt_, 'base64')).update(host).digest();
26+
if (hostHash.toString('base64') === hostHash_) {
27+
return false;
28+
}
29+
}
30+
31+
return true;
32+
}
33+
34+
export async function addHostToHostFile(host: string, hostKey: Buffer, type: string): Promise<void> {
35+
const salt = crypto.randomBytes(20);
36+
const hostHash = crypto.createHmac('sha1', salt).update(host).digest();
37+
38+
const entry = `${HASH_MAGIC}${salt.toString('base64')}${HASH_DELIM}${hostHash.toString('base64')} ${type} ${hostKey.toString('base64')}\n`;
39+
await fs.promises.appendFile(KNOW_HOST_FILE, entry);
40+
}

extensions/gitpod/src/extension.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
import * as vscode from 'vscode';
66
import Log from './common/logger';
77
import GitpodAuthenticationProvider from './authentication';
8-
import LocalApp from './localApp';
8+
import RemoteConnector from './remoteConnector';
99
import { enableSettingsSync, updateSyncContext } from './settingsSync';
1010
import { GitpodServer } from './gitpodServer';
1111
import TelemetryReporter from './telemetryReporter';
1212
import { exportLogs } from './exportLogs';
1313

1414
const EXTENSION_ID = 'gitpod.gitpod-desktop';
1515
const FIRST_INSTALL_KEY = 'gitpod-desktop.firstInstall';
16-
const ANALITYCS_KEY = 'bUY8IRdJ42KjLOBS9LoIHMYFBD8rSzjU';
16+
17+
// const ANALITYCS_KEY = 'YErmvd89wPsrCuGcVnF2XAl846W9WIGl'; // For development
18+
const ANALITYCS_KEY = 'bUY8IRdJ42KjLOBS9LoIHMYFBD8rSzjU'; // For release
1719

1820
let telemetry: TelemetryReporter;
1921

@@ -68,16 +70,16 @@ export async function activate(context: vscode.ExtensionContext) {
6870
}));
6971

7072
const authProvider = new GitpodAuthenticationProvider(context, logger, telemetry);
71-
const localApp = new LocalApp(context, logger);
73+
const remoteConnector = new RemoteConnector(context, logger, telemetry);
7274
context.subscriptions.push(authProvider);
73-
context.subscriptions.push(localApp);
75+
context.subscriptions.push(remoteConnector);
7476
context.subscriptions.push(vscode.window.registerUriHandler({
7577
handleUri(uri: vscode.Uri) {
7678
// logger.trace('Handling Uri...', uri.toString());
7779
if (uri.path === GitpodServer.AUTH_COMPLETE_PATH) {
7880
authProvider.handleUri(uri);
7981
} else {
80-
localApp.handleUri(uri);
82+
remoteConnector.handleUri(uri);
8183
}
8284
}
8385
}));

extensions/gitpod/src/internalApi.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import ReconnectingWebSocket from 'reconnecting-websocket';
1010
import * as vscode from 'vscode';
1111
import Log from './common/logger';
1212

13-
type UsedGitpodFunction = ['getLoggedInUser', 'getGitpodTokenScopes'];
13+
type UsedGitpodFunction = ['getLoggedInUser', 'getGitpodTokenScopes', 'getWorkspace', 'getOwnerToken'];
1414
type Union<Tuple extends any[], Union = never> = Tuple[number] | Union;
1515
export type GitpodConnection = Omit<GitpodServiceImpl<GitpodClient, GitpodServer>, 'server'> & {
1616
server: Pick<GitpodServer, Union<UsedGitpodFunction>>;
@@ -28,6 +28,8 @@ class GitpodServerApi extends vscode.Disposable {
2828
constructor(accessToken: string, serviceUrl: string, private readonly logger: Log) {
2929
super(() => this.internalDispose());
3030

31+
serviceUrl = serviceUrl.replace(/\/$/, '');
32+
3133
const factory = new JsonRpcProxyFactory<GitpodServer>();
3234
this.service = new GitpodServiceImpl<GitpodClient, GitpodServer>(factory.createProxy());
3335

0 commit comments

Comments
 (0)