Merge branch master into code-asher/ch1385
This commit is contained in:
commit
e1702a1d21
|
@ -2,4 +2,7 @@ blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Question
|
- name: Question
|
||||||
url: https://github.com/cdr/code-server/discussions/new?category_id=22503114
|
url: https://github.com/cdr/code-server/discussions/new?category_id=22503114
|
||||||
about: Ask the community for help
|
about: Ask the community for help on our GitHub Discussions board
|
||||||
|
- name: Chat
|
||||||
|
about: Need immediate help or just want to talk? Hop in our Slack
|
||||||
|
url: https://cdr.co/join-community
|
||||||
|
|
53
README.md
53
README.md
|
@ -6,62 +6,63 @@ Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and a
|
||||||
|
|
||||||
## Highlights
|
## Highlights
|
||||||
|
|
||||||
- **Code everywhere**
|
- Code on any device with a consistent development environment
|
||||||
- Code on your Chromebook, tablet, and laptop with a consistent development environment.
|
- Use cloud servers to speed up tests, compilations, downloads, and more
|
||||||
- Develop on a Linux machine and pick up from any device with a web browser.
|
- Preserve battery life when you're on the go; all intensive tasks run on your server
|
||||||
- **Server-powered**
|
|
||||||
- Take advantage of large cloud servers to speed up tests, compilations, downloads, and more.
|
|
||||||
- Preserve battery life when you're on the go as all intensive tasks run on your server.
|
|
||||||
- Make use of a spare computer you have lying around and turn it into a full development environment.
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
For a full setup and walkthrough, please see [./doc/guide.md](./doc/guide.md).
|
There are two ways to get started:
|
||||||
|
|
||||||
### Quick Install
|
1. Using the [install script](./install.sh), which automates most of the process. The script uses the system package manager (if possible)
|
||||||
|
2. Manually installing code-server; see [Installation](./doc/install.md) for instructions applicable to most use cases
|
||||||
|
|
||||||
We have a [script](./install.sh) to install code-server for Linux, macOS and FreeBSD.
|
If you choose to use the install script, you can preview what occurs during the install process:
|
||||||
|
|
||||||
It tries to use the system package manager if possible.
|
|
||||||
|
|
||||||
First run to print out the install process:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
||||||
```
|
```
|
||||||
|
|
||||||
Now to actually install:
|
To install, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://code-server.dev/install.sh | sh
|
curl -fsSL https://code-server.dev/install.sh | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The install script will print out how to run and start using code-server.
|
When done, the install script prints out instructions for running and starting code-server.
|
||||||
|
|
||||||
### Manual Install
|
We also have an in-depth [setup and configuration](./doc/guide.md) guide.
|
||||||
|
|
||||||
Docs on the install script, manual installation and docker image are at [./doc/install.md](./doc/install.md).
|
### Alpha Program 🐣
|
||||||
|
|
||||||
|
We're working on a cloud platform that makes deploying and managing code-server easier. Consider [updating to 3.6.2](https://github.com/cdr/code-server/releases/tag/v3.6.2) and running code-server with our experimental flag `--link` if you don't want to worry about
|
||||||
|
|
||||||
|
- TLS
|
||||||
|
- Authentication
|
||||||
|
- Port Forwarding
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ code-server --link
|
||||||
|
Proxying code-server to Coder Cloud, you can access your IDE at https://valmar-jon.cdr.co
|
||||||
|
```
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
See [./doc/FAQ.md](./doc/FAQ.md).
|
See [./doc/FAQ.md](./doc/FAQ.md).
|
||||||
|
|
||||||
## Contributing
|
## Want to help?
|
||||||
|
|
||||||
See [./doc/CONTRIBUTING.md](./doc/CONTRIBUTING.md).
|
See [CONTRIBUTING](./doc/CONTRIBUTING.md) for details.
|
||||||
|
|
||||||
## Hiring
|
## Hiring
|
||||||
|
|
||||||
We ([@cdr](https://github.com/cdr)) are looking for engineers to help maintain
|
We ([@cdr](https://github.com/cdr)) are looking for engineers to help [maintain
|
||||||
code-server, innovate on open source and streamline dev workflows.
|
code-server](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8), innovate on open source, and streamline dev workflows.
|
||||||
|
|
||||||
Our main office is in Austin, Texas. Remote is ok as long as
|
Our main office is in Austin, Texas. Remote is ok as long as
|
||||||
you're in North America or Europe.
|
you're in North America or Europe.
|
||||||
|
|
||||||
Please get in [touch](mailto:jobs@coder.com) with your resume/github if interested.
|
Please get in [touch](mailto:jobs@coder.com) with your resume/GitHub if interested.
|
||||||
|
|
||||||
We're also hiring someone specifically to help maintain code-server.
|
|
||||||
See the listing [here](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8).
|
|
||||||
|
|
||||||
## For Organizations
|
## For Organizations
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ EOF
|
||||||
bundle_vscode() {
|
bundle_vscode() {
|
||||||
mkdir -p "$VSCODE_OUT_PATH"
|
mkdir -p "$VSCODE_OUT_PATH"
|
||||||
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
|
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
|
||||||
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY+-min}/" "$VSCODE_OUT_PATH/out"
|
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
|
||||||
|
|
||||||
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
|
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
|
||||||
if [ "$KEEP_MODULES" = 0 ]; then
|
if [ "$KEEP_MODULES" = 0 ]; then
|
||||||
|
|
|
@ -25,8 +25,11 @@ main() {
|
||||||
esac
|
esac
|
||||||
|
|
||||||
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||||
curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
|
if curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent; then
|
||||||
chmod +x ./lib/coder-cloud-agent
|
chmod +x ./lib/coder-cloud-agent
|
||||||
|
else
|
||||||
|
echo "Failed to download cloud agent; --link will not work"
|
||||||
|
fi
|
||||||
|
|
||||||
if ! vscode_yarn; then
|
if ! vscode_yarn; then
|
||||||
echo "You may not have the required dependencies to build the native modules."
|
echo "You may not have the required dependencies to build the native modules."
|
||||||
|
|
|
@ -26,6 +26,7 @@ main() {
|
||||||
doctoc --title '# Install' doc/install.md > /dev/null
|
doctoc --title '# Install' doc/install.md > /dev/null
|
||||||
doctoc --title '# npm Install Requirements' doc/npm.md > /dev/null
|
doctoc --title '# npm Install Requirements' doc/npm.md > /dev/null
|
||||||
doctoc --title '# Contributing' doc/CONTRIBUTING.md > /dev/null
|
doctoc --title '# Contributing' doc/CONTRIBUTING.md > /dev/null
|
||||||
|
doctoc --title '# iPad' doc/ipad.md > /dev/null
|
||||||
|
|
||||||
if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
|
if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
|
||||||
echo "Files need generation or are formatted incorrectly:"
|
echo "Files need generation or are formatted incorrectly:"
|
||||||
|
|
|
@ -1225,10 +1225,10 @@ index 0000000000000000000000000000000000000000..4ea6d95d36aaac07dbd4d0e16ab3c1bb
|
||||||
+}
|
+}
|
||||||
diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
|
diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..ab020fbb4e4ab3748cc807765ff9c362389faafa
|
index 0000000000000000000000000000000000000000..8482c48bae007ed6b39183001ae2cc6d140fcd50
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/vs/server/entry.ts
|
+++ b/src/vs/server/entry.ts
|
||||||
@@ -0,0 +1,78 @@
|
@@ -0,0 +1,79 @@
|
||||||
+import { field } from '@coder/logger';
|
+import { field } from '@coder/logger';
|
||||||
+import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
+import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
||||||
+import { CodeServerMessage, VscodeMessage } from 'vs/server/ipc';
|
+import { CodeServerMessage, VscodeMessage } from 'vs/server/ipc';
|
||||||
|
@ -1273,7 +1273,8 @@ index 0000000000000000000000000000000000000000..ab020fbb4e4ab3748cc807765ff9c362
|
||||||
+// Wait for the init message then start up VS Code. Subsequent messages will
|
+// Wait for the init message then start up VS Code. Subsequent messages will
|
||||||
+// return new workbench options without starting a new instance.
|
+// return new workbench options without starting a new instance.
|
||||||
+process.on('message', async (message: CodeServerMessage, socket) => {
|
+process.on('message', async (message: CodeServerMessage, socket) => {
|
||||||
+ logger.debug('got message from code-server', field('message', message));
|
+ logger.debug('got message from code-server', field('type', message.type));
|
||||||
|
+ logger.trace('code-server message content', field('message', message));
|
||||||
+ switch (message.type) {
|
+ switch (message.type) {
|
||||||
+ case 'init':
|
+ case 'init':
|
||||||
+ try {
|
+ try {
|
||||||
|
@ -1821,10 +1822,11 @@ index 0000000000000000000000000000000000000000..609c4d1cb43f52f92906b901c14c790f
|
||||||
+}
|
+}
|
||||||
diff --git a/src/vs/server/node/connection.ts b/src/vs/server/node/connection.ts
|
diff --git a/src/vs/server/node/connection.ts b/src/vs/server/node/connection.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759f396be18
|
index 0000000000000000000000000000000000000000..93062cadc627c61e0829c27a72894b81e6a0e039
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/vs/server/node/connection.ts
|
+++ b/src/vs/server/node/connection.ts
|
||||||
@@ -0,0 +1,157 @@
|
@@ -0,0 +1,171 @@
|
||||||
|
+import { field, Logger, logger } from '@coder/logger';
|
||||||
+import * as cp from 'child_process';
|
+import * as cp from 'child_process';
|
||||||
+import { VSBuffer } from 'vs/base/common/buffer';
|
+import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
+import { Emitter } from 'vs/base/common/event';
|
+import { Emitter } from 'vs/base/common/event';
|
||||||
|
@ -1832,10 +1834,8 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||||
+import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
|
+import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
|
||||||
+import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
+import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||||
+import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
+import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
+import { ILogService } from 'vs/platform/log/common/log';
|
|
||||||
+import { getNlsConfiguration } from 'vs/server/node/nls';
|
+import { getNlsConfiguration } from 'vs/server/node/nls';
|
||||||
+import { Protocol } from 'vs/server/node/protocol';
|
+import { Protocol } from 'vs/server/node/protocol';
|
||||||
+import { IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
|
||||||
+
|
+
|
||||||
+export abstract class Connection {
|
+export abstract class Connection {
|
||||||
+ private readonly _onClose = new Emitter<void>();
|
+ private readonly _onClose = new Emitter<void>();
|
||||||
|
@ -1899,13 +1899,14 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||||
+
|
+
|
||||||
+export class ExtensionHostConnection extends Connection {
|
+export class ExtensionHostConnection extends Connection {
|
||||||
+ private process?: cp.ChildProcess;
|
+ private process?: cp.ChildProcess;
|
||||||
|
+ private readonly logger: Logger;
|
||||||
+
|
+
|
||||||
+ public constructor(
|
+ public constructor(
|
||||||
+ locale:string, protocol: Protocol, buffer: VSBuffer, token: string,
|
+ locale:string, protocol: Protocol, buffer: VSBuffer, token: string,
|
||||||
+ private readonly log: ILogService,
|
|
||||||
+ private readonly environment: INativeEnvironmentService,
|
+ private readonly environment: INativeEnvironmentService,
|
||||||
+ ) {
|
+ ) {
|
||||||
+ super(protocol, token);
|
+ super(protocol, token);
|
||||||
|
+ this.logger = logger.named("exthost", field("token", token));
|
||||||
+ this.protocol.dispose();
|
+ this.protocol.dispose();
|
||||||
+ this.spawn(locale, buffer).then((p) => this.process = p);
|
+ this.spawn(locale, buffer).then((p) => this.process = p);
|
||||||
+ this.protocol.getUnderlyingSocket().pause();
|
+ this.protocol.getUnderlyingSocket().pause();
|
||||||
|
@ -1928,6 +1929,7 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||||
+ private sendInitMessage(buffer: VSBuffer): void {
|
+ private sendInitMessage(buffer: VSBuffer): void {
|
||||||
+ const socket = this.protocol.getUnderlyingSocket();
|
+ const socket = this.protocol.getUnderlyingSocket();
|
||||||
+ socket.pause();
|
+ socket.pause();
|
||||||
|
+ this.logger.trace('Sending socket');
|
||||||
+ this.process!.send({ // Process must be set at this point.
|
+ this.process!.send({ // Process must be set at this point.
|
||||||
+ type: 'VSCODE_EXTHOST_IPC_SOCKET',
|
+ type: 'VSCODE_EXTHOST_IPC_SOCKET',
|
||||||
+ initialDataChunk: (buffer.buffer as Buffer).toString('base64'),
|
+ initialDataChunk: (buffer.buffer as Buffer).toString('base64'),
|
||||||
|
@ -1936,7 +1938,9 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private async spawn(locale: string, buffer: VSBuffer): Promise<cp.ChildProcess> {
|
+ private async spawn(locale: string, buffer: VSBuffer): Promise<cp.ChildProcess> {
|
||||||
|
+ this.logger.trace('Getting NLS configuration...');
|
||||||
+ const config = await getNlsConfiguration(locale, this.environment.userDataPath);
|
+ const config = await getNlsConfiguration(locale, this.environment.userDataPath);
|
||||||
|
+ this.logger.trace('Spawning extension host...');
|
||||||
+ const proc = cp.fork(
|
+ const proc = cp.fork(
|
||||||
+ FileAccess.asFileUri('bootstrap-fork', require).fsPath,
|
+ FileAccess.asFileUri('bootstrap-fork', require).fsPath,
|
||||||
+ [ '--type=extensionHost' ],
|
+ [ '--type=extensionHost' ],
|
||||||
|
@ -1956,30 +1960,41 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||||
+ },
|
+ },
|
||||||
+ );
|
+ );
|
||||||
+
|
+
|
||||||
+ proc.on('error', () => this.dispose());
|
+ proc.on('error', (error) => {
|
||||||
+ proc.on('exit', () => this.dispose());
|
+ this.logger.error('Exited unexpectedly', field('error', error));
|
||||||
|
+ this.dispose();
|
||||||
|
+ });
|
||||||
|
+ proc.on('exit', (code) => {
|
||||||
|
+ this.logger.trace('Exited', field('code', code));
|
||||||
|
+ this.dispose();
|
||||||
|
+ });
|
||||||
+ if (proc.stdout && proc.stderr) {
|
+ if (proc.stdout && proc.stderr) {
|
||||||
+ proc.stdout.setEncoding('utf8').on('data', (d) => this.log.info('Extension host stdout', d));
|
+ proc.stdout.setEncoding('utf8').on('data', (d) => this.logger.info(d));
|
||||||
+ proc.stderr.setEncoding('utf8').on('data', (d) => this.log.error('Extension host stderr', d));
|
+ proc.stderr.setEncoding('utf8').on('data', (d) => this.logger.error(d));
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
+ proc.on('message', (event) => {
|
+ proc.on('message', (event) => {
|
||||||
+ if (event && event.type === '__$console') {
|
+ switch (event && event.type) {
|
||||||
+ const severity = (<any>this.log)[event.severity] ? event.severity : 'info';
|
+ case '__$console':
|
||||||
+ (<any>this.log)[severity]('Extension host', event.arguments);
|
+ const severity = (<any>this.logger)[event.severity] || 'info';
|
||||||
+ }
|
+ (<any>this.logger)[severity]('console', field('arguments', event.arguments));
|
||||||
+ if (event && event.type === 'VSCODE_EXTHOST_DISCONNECTED') {
|
+ break;
|
||||||
+ this.setOffline();
|
+ case 'VSCODE_EXTHOST_DISCONNECTED':
|
||||||
|
+ this.logger.trace('Going offline');
|
||||||
|
+ this.setOffline();
|
||||||
|
+ break;
|
||||||
|
+ case 'VSCODE_EXTHOST_IPC_READY':
|
||||||
|
+ this.logger.trace('Got ready message');
|
||||||
|
+ this.sendInitMessage(buffer);
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ this.logger.error('Unexpected message', field("event", event));
|
||||||
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+ });
|
+ });
|
||||||
+
|
+
|
||||||
+ const listen = (message: IExtHostReadyMessage) => {
|
+ this.logger.trace('Waiting for handshake...');
|
||||||
+ if (message.type === 'VSCODE_EXTHOST_IPC_READY') {
|
+ return proc;
|
||||||
+ proc.removeListener('message', listen);
|
|
||||||
+ this.sendInitMessage(buffer);
|
|
||||||
+ }
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ return proc.on('message', listen);
|
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
diff --git a/src/vs/server/node/insights.ts b/src/vs/server/node/insights.ts
|
diff --git a/src/vs/server/node/insights.ts b/src/vs/server/node/insights.ts
|
||||||
|
@ -2463,15 +2478,17 @@ index 0000000000000000000000000000000000000000..3d428a57d31f29c40f9c3ce45f715b44
|
||||||
+};
|
+};
|
||||||
diff --git a/src/vs/server/node/protocol.ts b/src/vs/server/node/protocol.ts
|
diff --git a/src/vs/server/node/protocol.ts b/src/vs/server/node/protocol.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b9cfd5fbf
|
index 0000000000000000000000000000000000000000..0d9310038c0ca378579652d89bc8ac84924213db
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/vs/server/node/protocol.ts
|
+++ b/src/vs/server/node/protocol.ts
|
||||||
@@ -0,0 +1,73 @@
|
@@ -0,0 +1,91 @@
|
||||||
|
+import { field } from '@coder/logger';
|
||||||
+import * as net from 'net';
|
+import * as net from 'net';
|
||||||
+import { VSBuffer } from 'vs/base/common/buffer';
|
+import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
+import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
|
+import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
|
||||||
+import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
+import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||||
+import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection';
|
+import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||||
|
+import { logger } from 'vs/server/node/logger';
|
||||||
+
|
+
|
||||||
+export interface SocketOptions {
|
+export interface SocketOptions {
|
||||||
+ readonly reconnectionToken: string;
|
+ readonly reconnectionToken: string;
|
||||||
|
@ -2499,29 +2516,45 @@ index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b
|
||||||
+ * Perform a handshake to get a connection request.
|
+ * Perform a handshake to get a connection request.
|
||||||
+ */
|
+ */
|
||||||
+ public handshake(): Promise<ConnectionTypeRequest> {
|
+ public handshake(): Promise<ConnectionTypeRequest> {
|
||||||
|
+ logger.trace('Protocol handshake', field('token', this.options.reconnectionToken));
|
||||||
+ return new Promise((resolve, reject) => {
|
+ return new Promise((resolve, reject) => {
|
||||||
|
+ const timeout = setTimeout(() => {
|
||||||
|
+ logger.error('Handshake timed out', field('token', this.options.reconnectionToken));
|
||||||
|
+ reject(new Error("timed out"));
|
||||||
|
+ }, 10000); // Matches the client timeout.
|
||||||
|
+
|
||||||
+ const handler = this.onControlMessage((rawMessage) => {
|
+ const handler = this.onControlMessage((rawMessage) => {
|
||||||
+ try {
|
+ try {
|
||||||
+ const message = JSON.parse(rawMessage.toString());
|
+ const raw = rawMessage.toString();
|
||||||
|
+ logger.trace('Protocol message', field('token', this.options.reconnectionToken), field('message', raw));
|
||||||
|
+ const message = JSON.parse(raw);
|
||||||
+ switch (message.type) {
|
+ switch (message.type) {
|
||||||
+ case 'auth': return this.authenticate(message);
|
+ case 'auth':
|
||||||
|
+ return this.authenticate(message);
|
||||||
+ case 'connectionType':
|
+ case 'connectionType':
|
||||||
+ handler.dispose();
|
+ handler.dispose();
|
||||||
|
+ clearTimeout(timeout);
|
||||||
+ return resolve(message);
|
+ return resolve(message);
|
||||||
+ default: throw new Error('Unrecognized message type');
|
+ default:
|
||||||
|
+ throw new Error('Unrecognized message type');
|
||||||
+ }
|
+ }
|
||||||
+ } catch (error) {
|
+ } catch (error) {
|
||||||
+ handler.dispose();
|
+ handler.dispose();
|
||||||
|
+ clearTimeout(timeout);
|
||||||
+ reject(error);
|
+ reject(error);
|
||||||
+ }
|
+ }
|
||||||
+ });
|
+ });
|
||||||
|
+
|
||||||
|
+ // Kick off the handshake in case we missed the client's opening shot.
|
||||||
|
+ // TODO: Investigate why that message seems to get lost.
|
||||||
|
+ this.authenticate();
|
||||||
+ });
|
+ });
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /**
|
+ /**
|
||||||
+ * TODO: This ignores the authentication process entirely for now.
|
+ * TODO: This ignores the authentication process entirely for now.
|
||||||
+ */
|
+ */
|
||||||
+ private authenticate(_message: AuthRequest): void {
|
+ private authenticate(_?: AuthRequest): void {
|
||||||
+ this.sendMessage({ type: 'sign', data: '' });
|
+ this.sendMessage({ type: 'sign', data: '' });
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
@ -2542,10 +2575,11 @@ index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b
|
||||||
+}
|
+}
|
||||||
diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
|
diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0aadffd5e5
|
index 0000000000000000000000000000000000000000..45a7bf62a6c07d8771b0257e7c98fae095109eb1
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/vs/server/node/server.ts
|
+++ b/src/vs/server/node/server.ts
|
||||||
@@ -0,0 +1,286 @@
|
@@ -0,0 +1,291 @@
|
||||||
|
+import { field } from '@coder/logger';
|
||||||
+import * as fs from 'fs';
|
+import * as fs from 'fs';
|
||||||
+import * as net from 'net';
|
+import * as net from 'net';
|
||||||
+import * as path from 'path';
|
+import * as path from 'path';
|
||||||
|
@ -2709,6 +2743,7 @@ index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0a
|
||||||
+ );
|
+ );
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ logger.debug('New connection', field('token', token));
|
||||||
+ protocol.sendMessage(await ok());
|
+ protocol.sendMessage(await ok());
|
||||||
+
|
+
|
||||||
+ let connection: Connection;
|
+ let connection: Connection;
|
||||||
|
@ -2727,12 +2762,14 @@ index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0a
|
||||||
+ connection = new ExtensionHostConnection(
|
+ connection = new ExtensionHostConnection(
|
||||||
+ message.args ? message.args.language : 'en',
|
+ message.args ? message.args.language : 'en',
|
||||||
+ protocol, buffer, token,
|
+ protocol, buffer, token,
|
||||||
+ this.services.get(ILogService) as ILogService,
|
|
||||||
+ this.services.get(IEnvironmentService) as INativeEnvironmentService,
|
+ this.services.get(IEnvironmentService) as INativeEnvironmentService,
|
||||||
+ );
|
+ );
|
||||||
+ }
|
+ }
|
||||||
+ connections.set(token, connection);
|
+ connections.set(token, connection);
|
||||||
+ connection.onClose(() => connections.delete(token));
|
+ connection.onClose(() => {
|
||||||
|
+ logger.debug('Connection closed', field('token', token));
|
||||||
|
+ connections.delete(token);
|
||||||
|
+ });
|
||||||
+ this.disposeOldOfflineConnections(connections);
|
+ this.disposeOldOfflineConnections(connections);
|
||||||
+ break;
|
+ break;
|
||||||
+ case ConnectionType.Tunnel: return protocol.tunnel();
|
+ case ConnectionType.Tunnel: return protocol.tunnel();
|
||||||
|
@ -2744,6 +2781,7 @@ index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0a
|
||||||
+ const offline = Array.from(connections.values())
|
+ const offline = Array.from(connections.values())
|
||||||
+ .filter((connection) => typeof connection.offline !== 'undefined');
|
+ .filter((connection) => typeof connection.offline !== 'undefined');
|
||||||
+ for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) {
|
+ for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) {
|
||||||
|
+ logger.debug('Disposing offline connection', field("token", offline[i].token));
|
||||||
+ offline[i].dispose();
|
+ offline[i].dispose();
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
|
@ -43,5 +43,6 @@ EXPOSE 8080
|
||||||
# the uid will remain the same. note: only relevant if -u isn't passed to
|
# the uid will remain the same. note: only relevant if -u isn't passed to
|
||||||
# docker-run.
|
# docker-run.
|
||||||
USER 1000
|
USER 1000
|
||||||
|
ENV USER=coder
|
||||||
WORKDIR /home/coder
|
WORKDIR /home/coder
|
||||||
ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]
|
ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
# This isn't set by default.
|
# We do this first to ensure sudo works below when renaming the user.
|
||||||
USER="$(whoami)"
|
# Otherwise the current container UID may not exist in the passwd database.
|
||||||
export USER
|
eval "$(fixuid -q)"
|
||||||
|
|
||||||
if [ "${DOCKER_USER-}" ] && [ "$DOCKER_USER" != "$USER" ]; then
|
if [ "${DOCKER_USER-}" ]; then
|
||||||
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
|
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
|
||||||
# Unfortunately we cannot change $HOME as we cannot move any bind mounts
|
# Unfortunately we cannot change $HOME as we cannot move any bind mounts
|
||||||
# nor can we bind mount $HOME into a new home as that requires a privileged container.
|
# nor can we bind mount $HOME into a new home as that requires a privileged container.
|
||||||
|
@ -15,7 +15,6 @@ if [ "${DOCKER_USER-}" ] && [ "$DOCKER_USER" != "$USER" ]; then
|
||||||
USER="$DOCKER_USER"
|
USER="$DOCKER_USER"
|
||||||
|
|
||||||
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
|
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
|
||||||
sudo sed -i "s/coder/$DOCKER_USER/g" /etc/fixuid/config.yml
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dumb-init fixuid -q /usr/bin/code-server "$@"
|
dumb-init /usr/bin/code-server "$@"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
- [Build](#build)
|
- [Build](#build)
|
||||||
- [Structure](#structure)
|
- [Structure](#structure)
|
||||||
- [VS Code Patch](#vs-code-patch)
|
- [VS Code Patch](#vs-code-patch)
|
||||||
|
- [Currently Known Issues](#currently-known-issues)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
@ -15,24 +16,26 @@
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
Please link to the issue each PR solves.
|
Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) for each issue
|
||||||
If there is no existing issue, please first create one unless the fix is minor.
|
you'd like to address unless the proposed fix is minor.
|
||||||
|
|
||||||
Please make sure the base of your PR is the master branch. We keep the GitHub
|
In your Pull Requests (PR), link to the issue that the PR solves.
|
||||||
default branch the latest release branch to avoid confusion as the
|
|
||||||
documentation is on GitHub and we don't want users to see docs on unreleased
|
Please ensure that the base of your PR is the **master** branch. (Note: The default
|
||||||
features.
|
GitHub branch is the latest release branch, though you should point all of your changes to be merged into
|
||||||
|
master).
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
Please refer to [VS Code's prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
The prerequisites for contributing to code-server are almost the same as those for
|
||||||
|
[VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
||||||
|
There are several differences, however. You must:
|
||||||
|
|
||||||
Differences:
|
- Use Node.js version 12.x (or greater)
|
||||||
|
- Have [nfpm](https://github.com/goreleaser/nfpm) (which is used to build `.deb` and `.rpm` packages and [jq](https://stedolan.github.io/jq/) (used to build code-server releases) installed
|
||||||
|
|
||||||
- We require a minimum of node v12 but later versions should work.
|
The [CI container](../ci/images/debian8/Dockerfile) is a useful reference for all
|
||||||
- We use [nfpm](https://github.com/goreleaser/nfpm) to build `.deb` and `.rpm` packages.
|
of the dependencies code-server uses.
|
||||||
- We use [jq](https://stedolan.github.io/jq/) to build code-server releases.
|
|
||||||
- The [CI container](../ci/images/debian10/Dockerfile) is a useful reference for all our dependencies.
|
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
|
|
||||||
|
@ -40,10 +43,10 @@ Differences:
|
||||||
yarn
|
yarn
|
||||||
yarn vscode
|
yarn vscode
|
||||||
yarn watch
|
yarn watch
|
||||||
# Visit http://localhost:8080 once the build completed.
|
# Visit http://localhost:8080 once the build is completed.
|
||||||
```
|
```
|
||||||
|
|
||||||
To develop inside of an isolated docker container:
|
To develop inside an isolated Docker container:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
./ci/dev/image/run.sh yarn
|
./ci/dev/image/run.sh yarn
|
||||||
|
@ -53,12 +56,12 @@ To develop inside of an isolated docker container:
|
||||||
|
|
||||||
`yarn watch` will live reload changes to the source.
|
`yarn watch` will live reload changes to the source.
|
||||||
|
|
||||||
If changes are made to the patch and you've built previously you must manually
|
If you introduce changes to the patch and you've previously built, you
|
||||||
reset VS Code then run `yarn vscode:patch`.
|
must (1) manually reset VS Code and (2) run `yarn vscode:patch`.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
You can build with:
|
You can build using:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
./ci/dev/image/run.sh ./ci/steps/release.sh
|
./ci/dev/image/run.sh ./ci/steps/release.sh
|
||||||
|
@ -66,22 +69,22 @@ You can build with:
|
||||||
|
|
||||||
Run your build with:
|
Run your build with:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cd release
|
cd release
|
||||||
yarn --production
|
yarn --production
|
||||||
# Runs the built JavaScript with Node.
|
# Runs the built JavaScript with Node.
|
||||||
node .
|
node .
|
||||||
```
|
```
|
||||||
|
|
||||||
Build release packages (make sure you run `./ci/steps/release.sh` first):
|
Build the release packages (make sure that you run `./ci/steps/release.sh` first):
|
||||||
|
|
||||||
```
|
```shell
|
||||||
IMAGE=centos7 ./ci/dev/image/run.sh ./ci/steps/release-packages.sh
|
IMAGE=centos7 ./ci/dev/image/run.sh ./ci/steps/release-packages.sh
|
||||||
# The standalone release is in ./release-standalone
|
# The standalone release is in ./release-standalone
|
||||||
# .deb, .rpm and the standalone archive are in ./release-packages
|
# .deb, .rpm and the standalone archive are in ./release-packages
|
||||||
```
|
```
|
||||||
|
|
||||||
The `release.sh` script is the equivalent of:
|
The `release.sh` script is equal to running:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
yarn
|
yarn
|
||||||
|
@ -91,73 +94,69 @@ yarn build:vscode
|
||||||
yarn release
|
yarn release
|
||||||
```
|
```
|
||||||
|
|
||||||
And `release-packages.sh` is:
|
And `release-packages.sh` is equal to:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
yarn release:standalone
|
yarn release:standalone
|
||||||
yarn test:standalone-release
|
yarn test:standalone-release
|
||||||
yarn package
|
yarn package
|
||||||
```
|
```
|
||||||
|
|
||||||
For a faster release build you can also run:
|
For a faster release build, you can run instead:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
KEEP_MODULES=1 ./ci/steps/release.sh
|
KEEP_MODULES=1 ./ci/steps/release.sh
|
||||||
node ./release
|
node ./release
|
||||||
```
|
```
|
||||||
|
|
||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
The `code-server` script serves an HTTP API to login and start a remote VS Code process.
|
The `code-server` script serves an HTTP API for login and starting a remote VS Code process.
|
||||||
|
|
||||||
The CLI code is in [./src/node](./src/node) and the HTTP routes are implemented in
|
The CLI code is in [./src/node](./src/node) and the HTTP routes are implemented in
|
||||||
[./src/node/app](./src/node/app).
|
[./src/node/app](./src/node/app).
|
||||||
|
|
||||||
Most of the meaty parts are in our VS Code patch which is described next.
|
Most of the meaty parts are in the VS Code patch, which we described next.
|
||||||
|
|
||||||
### VS Code Patch
|
### VS Code Patch
|
||||||
|
|
||||||
Back in v1 of code-server, we had an extensive patch of VS Code that split the codebase
|
In v1 of code-server, we had a patch of VS Code that split the codebase into a front-end
|
||||||
into a frontend and server. The frontend consisted of all UI code and the server ran
|
and a server. The front-end consisted of all UI code, while the server ran the extensions
|
||||||
the extensions and exposed an API to the frontend for file access and everything else
|
and exposed an API to the front-end for file access and all UI needs.
|
||||||
that the UI needed.
|
|
||||||
|
|
||||||
This worked but eventually Microsoft added support to VS Code to run it in the web.
|
Over time, Microsoft added support to VS Code to run it on the web. They have made
|
||||||
They have open sourced the frontend but have kept the server closed source.
|
the front-end open source, but not the server. As such, code-server v2 (and later) uses
|
||||||
|
the VS Code front-end and implements the server. You can find this in
|
||||||
So in interest of piggy backing off their work, v2 and beyond use the VS Code
|
|
||||||
web frontend and fill in the server. This is contained in our
|
|
||||||
[./ci/dev/vscode.patch](../ci/dev/vscode.patch) under the path `src/vs/server`.
|
[./ci/dev/vscode.patch](../ci/dev/vscode.patch) under the path `src/vs/server`.
|
||||||
|
|
||||||
Other notable changes in our patch include:
|
Other notable changes in our patch include:
|
||||||
|
|
||||||
- Add our own build file which includes our code and VS Code's web code.
|
- Adding our build file, which includes our code and VS Code's web code
|
||||||
- Allow multiple extension directories (both user and built-in).
|
- Allowing multiple extension directories (both user and built-in)
|
||||||
- Modify the loader, websocket, webview, service worker, and asset requests to
|
- Modifying the loader, websocket, webview, service worker, and asset requests to
|
||||||
use the URL of the page as a base (and TLS if necessary for the websocket).
|
use the URL of the page as a base (and TLS, if necessary for the websocket)
|
||||||
- Send client-side telemetry through the server.
|
- Sending client-side telemetry through the server
|
||||||
- Allow modification of the display language.
|
- Allowing modification of the display language
|
||||||
- Make it possible for us to load code on the client.
|
- Making it possible for us to load code on the client
|
||||||
- Make extensions work in the browser.
|
- Making extensions work in the browser
|
||||||
- Make it possible to install extensions of any kind.
|
- Making it possible to install extensions of any kind
|
||||||
- Fix getting permanently disconnected when you sleep or hibernate for a while.
|
- Fixing issue with getting disconnected when your machine sleeps or hibernates
|
||||||
- Add connection type to web socket query parameters.
|
- Adding connection type to web socket query parameters
|
||||||
|
|
||||||
Some known issues presently:
|
As the web portion of VS Code matures, we'll be able to shrink and possibly
|
||||||
|
eliminate our patch. In the meantime, upgrading the VS Code version requires
|
||||||
- Creating custom VS Code extensions and debugging them doesn't work.
|
us to ensure that the patch is applied and works as intended. In the future,
|
||||||
- Extension profiling and tips are currently disabled.
|
we'd like to run VS Code unit tests against our builds to ensure that features
|
||||||
|
|
||||||
As the web portion of VS Code matures, we'll be able to shrink and maybe even entirely
|
|
||||||
eliminate our patch. In the meantime, however, upgrading the VS Code version requires
|
|
||||||
ensuring that the patch still applies and has the intended effects.
|
|
||||||
|
|
||||||
To generate a new patch run `yarn vscode:diff`.
|
|
||||||
|
|
||||||
**note**: We have extension docs on the CI and build system at [./ci/README.md](../ci/README.md)
|
|
||||||
|
|
||||||
If functionality doesn't depend on code from VS Code then it should be moved
|
|
||||||
into code-server otherwise it should be in the patch.
|
|
||||||
|
|
||||||
In the future we'd like to run VS Code unit tests against our builds to ensure features
|
|
||||||
work as expected.
|
work as expected.
|
||||||
|
|
||||||
|
To generate a new patch, run `yarn vscode:diff`
|
||||||
|
|
||||||
|
**Note**: We have [extension docs](../ci/README.md) on the CI and build system.
|
||||||
|
|
||||||
|
If the functionality you're working on does NOT depend on code from VS Code, please
|
||||||
|
move it out and into code-server.
|
||||||
|
|
||||||
|
### Currently Known Issues
|
||||||
|
|
||||||
|
- Creating custom VS Code extensions and debugging them doesn't work
|
||||||
|
- Extension profiling and tips are currently disabled
|
||||||
|
|
18
doc/FAQ.md
18
doc/FAQ.md
|
@ -3,6 +3,7 @@
|
||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
- [Questions?](#questions)
|
- [Questions?](#questions)
|
||||||
|
- [iPad Status?](#ipad-status)
|
||||||
- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
|
- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
|
||||||
- [Differences compared to VS Code?](#differences-compared-to-vs-code)
|
- [Differences compared to VS Code?](#differences-compared-to-vs-code)
|
||||||
- [How can I request a missing extension?](#how-can-i-request-a-missing-extension)
|
- [How can I request a missing extension?](#how-can-i-request-a-missing-extension)
|
||||||
|
@ -21,7 +22,6 @@
|
||||||
- [Heartbeat File](#heartbeat-file)
|
- [Heartbeat File](#heartbeat-file)
|
||||||
- [Healthz endpoint](#healthz-endpoint)
|
- [Healthz endpoint](#healthz-endpoint)
|
||||||
- [How does the config file work?](#how-does-the-config-file-work)
|
- [How does the config file work?](#how-does-the-config-file-work)
|
||||||
- [Blank screen on iPad?](#blank-screen-on-ipad)
|
|
||||||
- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
|
- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
|
||||||
- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
|
- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
|
||||||
- [Differences compared to Theia?](#differences-compared-to-theia)
|
- [Differences compared to Theia?](#differences-compared-to-theia)
|
||||||
|
@ -33,6 +33,10 @@
|
||||||
|
|
||||||
Please file all questions and support requests at https://github.com/cdr/code-server/discussions.
|
Please file all questions and support requests at https://github.com/cdr/code-server/discussions.
|
||||||
|
|
||||||
|
## iPad Status?
|
||||||
|
|
||||||
|
Please see [./ipad.md](./ipad.md).
|
||||||
|
|
||||||
## How can I reuse my VS Code configuration?
|
## How can I reuse my VS Code configuration?
|
||||||
|
|
||||||
The very popular [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) extension works.
|
The very popular [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) extension works.
|
||||||
|
@ -144,6 +148,9 @@ For HTTPS, you can use a self signed certificate by passing in just `--cert` or
|
||||||
pass in an existing certificate by providing the path to `--cert` and the path to
|
pass in an existing certificate by providing the path to `--cert` and the path to
|
||||||
the key with `--cert-key`.
|
the key with `--cert-key`.
|
||||||
|
|
||||||
|
The self signed certificate will be generated into
|
||||||
|
`~/.local/share/code-server/self-signed.crt`.
|
||||||
|
|
||||||
If `code-server` has been passed a certificate it will also respond to HTTPS
|
If `code-server` has been passed a certificate it will also respond to HTTPS
|
||||||
requests and will redirect all HTTP requests to HTTPS.
|
requests and will redirect all HTTP requests to HTTPS.
|
||||||
|
|
||||||
|
@ -279,15 +286,6 @@ The `--config` flag or `$CODE_SERVER_CONFIG` can be used to change the config fi
|
||||||
|
|
||||||
The default location also respects `$XDG_CONFIG_HOME`.
|
The default location also respects `$XDG_CONFIG_HOME`.
|
||||||
|
|
||||||
## Blank screen on iPad?
|
|
||||||
|
|
||||||
Unfortunately at the moment self signed certificates cause a blank screen on iPadOS
|
|
||||||
|
|
||||||
There does seem to be a way to get it to work if you create your own CA and create a
|
|
||||||
certificate using the CA and then import the CA onto your iPad.
|
|
||||||
|
|
||||||
See [#1566](https://github.com/cdr/code-server/issues/1566#issuecomment-623159434).
|
|
||||||
|
|
||||||
## Isn't an install script piped into sh insecure?
|
## Isn't an install script piped into sh insecure?
|
||||||
|
|
||||||
Please give
|
Please give
|
||||||
|
|
|
@ -251,8 +251,7 @@ Visit `https://<your-domain-name>` to access `code-server`. Congratulations!
|
||||||
|
|
||||||
### Self Signed Certificate
|
### Self Signed Certificate
|
||||||
|
|
||||||
**note:** Self signed certificates do not work with iPad and will cause a blank page. You'll
|
**note:** Self signed certificates do not work with iPad normally. See [./ipad.md](./ipad.md) for details.
|
||||||
have to use [Let's Encrypt](#lets-encrypt) instead. See the [FAQ](./FAQ.md#blank-screen-on-ipad).
|
|
||||||
|
|
||||||
Recommended reading: https://security.stackexchange.com/a/8112.
|
Recommended reading: https://security.stackexchange.com/a/8112.
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ commands presented in the rest of this document.
|
||||||
## Debian, Ubuntu
|
## Debian, Ubuntu
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fOL https://github.com/cdr/code-server/releases/download/v3.6.0/code-server_3.6.0_amd64.deb
|
curl -fOL https://github.com/cdr/code-server/releases/download/v3.6.1/code-server_3.6.1_amd64.deb
|
||||||
sudo dpkg -i code-server_3.6.0_amd64.deb
|
sudo dpkg -i code-server_3.6.1_amd64.deb
|
||||||
sudo systemctl enable --now code-server@$USER
|
sudo systemctl enable --now code-server@$USER
|
||||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||||
```
|
```
|
||||||
|
@ -88,8 +88,8 @@ sudo systemctl enable --now code-server@$USER
|
||||||
## Fedora, CentOS, RHEL, SUSE
|
## Fedora, CentOS, RHEL, SUSE
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fOL https://github.com/cdr/code-server/releases/download/v3.6.0/code-server-3.6.0-amd64.rpm
|
curl -fOL https://github.com/cdr/code-server/releases/download/v3.6.1/code-server-3.6.1-amd64.rpm
|
||||||
sudo rpm -i code-server-3.6.0-amd64.rpm
|
sudo rpm -i code-server-3.6.1-amd64.rpm
|
||||||
sudo systemctl enable --now code-server@$USER
|
sudo systemctl enable --now code-server@$USER
|
||||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||||
```
|
```
|
||||||
|
@ -158,10 +158,10 @@ Here is an example script for installing and using a standalone `code-server` re
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p ~/.local/lib ~/.local/bin
|
mkdir -p ~/.local/lib ~/.local/bin
|
||||||
curl -fL https://github.com/cdr/code-server/releases/download/v3.6.0/code-server-3.6.0-linux-amd64.tar.gz \
|
curl -fL https://github.com/cdr/code-server/releases/download/v3.6.1/code-server-3.6.1-linux-amd64.tar.gz \
|
||||||
| tar -C ~/.local/lib -xz
|
| tar -C ~/.local/lib -xz
|
||||||
mv ~/.local/lib/code-server-3.6.0-linux-amd64 ~/.local/lib/code-server-3.6.0
|
mv ~/.local/lib/code-server-3.6.1-linux-amd64 ~/.local/lib/code-server-3.6.1
|
||||||
ln -s ~/.local/lib/code-server-3.6.0/bin/code-server ~/.local/bin/code-server
|
ln -s ~/.local/lib/code-server-3.6.1/bin/code-server ~/.local/bin/code-server
|
||||||
PATH="~/.local/bin:$PATH"
|
PATH="~/.local/bin:$PATH"
|
||||||
code-server
|
code-server
|
||||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
# iPad
|
||||||
|
|
||||||
|
- [iPad](#ipad)
|
||||||
|
- [Known Issues](#known-issues)
|
||||||
|
- [How to access code-server with a self signed certificate on iPad?](#how-to-access-code-server-with-a-self-signed-certificate-on-ipad)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
# iPad
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
|
- Getting self signed certificates certificates to work is involved, see below.
|
||||||
|
- Keyboard may disappear sometimes [#1313](https://github.com/cdr/code-server/issues/1313), [#979](https://github.com/cdr/code-server/issues/979)
|
||||||
|
- Trackpad scrolling does not work [#1455](https://github.com/cdr/code-server/issues/1455)
|
||||||
|
- See [issues tagged with the iPad label](https://github.com/cdr/code-server/issues?q=is%3Aopen+is%3Aissue+label%3AiPad) for more.
|
||||||
|
|
||||||
|
## How to access code-server with a self signed certificate on iPad?
|
||||||
|
|
||||||
|
Accessing a self signed certificate on iPad isn't as easy as accepting through all
|
||||||
|
the security warnings. Safari will prevent WebSocket connections unless the certificate
|
||||||
|
is installed as a profile on the device.
|
||||||
|
|
||||||
|
The below assumes you are using the self signed certificate that code-server
|
||||||
|
generates for you. If not, that's fine but you'll have to make sure your certificate
|
||||||
|
abides by the following guidelines from Apple: https://support.apple.com/en-us/HT210176
|
||||||
|
|
||||||
|
**note**: Another undocumented requirement we noticed is that the certificate has to have `basicConstraints=CA:true`.
|
||||||
|
|
||||||
|
The following instructions assume you have code-server installed and running
|
||||||
|
with a self signed certificate. If not, please first go through [./guide.md](./guide.md)!
|
||||||
|
|
||||||
|
**warning**: Your iPad must access code-server via a domain name. It could be local
|
||||||
|
DNS like `mymacbookpro.local` but it must be a domain name. Otherwise Safari will
|
||||||
|
refuse to allow WebSockets to connect.
|
||||||
|
|
||||||
|
1. Your certificate **must** have a subject alt name that matches the hostname
|
||||||
|
at which you will access code-server from your iPad. You can pass this to code-server
|
||||||
|
so that it generates the certificate correctly with `--cert-host`.
|
||||||
|
2. Share your self signed certificate with the iPad.
|
||||||
|
- code-server will print the location of the certificate it has generated in the logs.
|
||||||
|
|
||||||
|
```
|
||||||
|
[2020-10-30T08:55:45.139Z] info - Using generated certificate and key for HTTPS: ~/.local/share/code-server/mymbp_local.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
- You can mail it to yourself or if you have a Mac, it's easiest to just Airdrop to the iPad.
|
||||||
|
|
||||||
|
3. When opening the `*.crt` file, you'll be prompted to go into settings to install.
|
||||||
|
4. Go to `Settings -> General -> Profile`, select the profile and then hit `Install`.
|
||||||
|
- It should say the profile is verified.
|
||||||
|
5. Go to `Settings -> About -> Certificate Trust Settings` and enable full trust for
|
||||||
|
the certificate.
|
||||||
|
6. Now you can access code-server! 🍻
|
26
install.sh
26
install.sh
|
@ -24,7 +24,7 @@ ${not_curl_usage-}
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
$arg0 [--dry-run] [--version X.X.X] [--method detect] \
|
$arg0 [--dry-run] [--version X.X.X] [--method detect] \
|
||||||
[--prefix ~/.local] [user@host]
|
[--prefix ~/.local] [--rsh ssh] [user@host]
|
||||||
|
|
||||||
--dry-run
|
--dry-run
|
||||||
Echo the commands for the install process without running them.
|
Echo the commands for the install process without running them.
|
||||||
|
@ -45,6 +45,9 @@ Usage:
|
||||||
and the binary symlinked into ~/.local/bin/code-server
|
and the binary symlinked into ~/.local/bin/code-server
|
||||||
To install system wide pass ---prefix=/usr/local
|
To install system wide pass ---prefix=/usr/local
|
||||||
|
|
||||||
|
--rsh <bin>
|
||||||
|
Specifies the remote shell for remote installation. Defaults to ssh.
|
||||||
|
|
||||||
- For Debian, Ubuntu and Raspbian it will install the latest deb package.
|
- For Debian, Ubuntu and Raspbian it will install the latest deb package.
|
||||||
- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package.
|
- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package.
|
||||||
- For Arch Linux it will install the AUR package.
|
- For Arch Linux it will install the AUR package.
|
||||||
|
@ -109,7 +112,8 @@ main() {
|
||||||
VERSION \
|
VERSION \
|
||||||
OPTIONAL \
|
OPTIONAL \
|
||||||
ALL_FLAGS \
|
ALL_FLAGS \
|
||||||
SSH_ARGS
|
RSH_ARGS \
|
||||||
|
RSH
|
||||||
|
|
||||||
ALL_FLAGS=""
|
ALL_FLAGS=""
|
||||||
while [ "$#" -gt 0 ]; do
|
while [ "$#" -gt 0 ]; do
|
||||||
|
@ -144,6 +148,13 @@ main() {
|
||||||
--version=*)
|
--version=*)
|
||||||
VERSION="$(parse_arg "$@")"
|
VERSION="$(parse_arg "$@")"
|
||||||
;;
|
;;
|
||||||
|
--rsh)
|
||||||
|
RSH="$(parse_arg "$@")"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--rsh=*)
|
||||||
|
RSH="$(parse_arg "$@")"
|
||||||
|
;;
|
||||||
-h | --h | -help | --help)
|
-h | --h | -help | --help)
|
||||||
usage
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -152,7 +163,7 @@ main() {
|
||||||
shift
|
shift
|
||||||
# We remove the -- added above.
|
# We remove the -- added above.
|
||||||
ALL_FLAGS="${ALL_FLAGS% --}"
|
ALL_FLAGS="${ALL_FLAGS% --}"
|
||||||
SSH_ARGS="$*"
|
RSH_ARGS="$*"
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
-*)
|
-*)
|
||||||
|
@ -161,7 +172,7 @@ main() {
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
SSH_ARGS="$*"
|
RSH_ARGS="$*"
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -169,9 +180,10 @@ main() {
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "${SSH_ARGS-}" ]; then
|
if [ "${RSH_ARGS-}" ]; then
|
||||||
echoh "Installing remotely with ssh $SSH_ARGS"
|
RSH="${RSH-ssh}"
|
||||||
curl -fsSL https://code-server.dev/install.sh | prefix "$SSH_ARGS" ssh "$SSH_ARGS" sh -s -- "$ALL_FLAGS"
|
echoh "Installing remotely with $RSH $RSH_ARGS"
|
||||||
|
curl -fsSL https://code-server.dev/install.sh | prefix "$RSH_ARGS" "$RSH" "$RSH_ARGS" sh -s -- "$ALL_FLAGS"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "code-server",
|
"name": "code-server",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "3.6.0",
|
"version": "3.6.2",
|
||||||
"description": "Run VS Code on a remote server.",
|
"description": "Run VS Code on a remote server.",
|
||||||
"homepage": "https://github.com/cdr/code-server",
|
"homepage": "https://github.com/cdr/code-server",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -30,6 +30,7 @@ export interface Args extends VsArgs {
|
||||||
auth?: AuthType
|
auth?: AuthType
|
||||||
password?: string
|
password?: string
|
||||||
cert?: OptionalString
|
cert?: OptionalString
|
||||||
|
"cert-host"?: string
|
||||||
"cert-key"?: string
|
"cert-key"?: string
|
||||||
"disable-telemetry"?: boolean
|
"disable-telemetry"?: boolean
|
||||||
help?: boolean
|
help?: boolean
|
||||||
|
@ -105,7 +106,11 @@ const options: Options<Required<Args>> = {
|
||||||
cert: {
|
cert: {
|
||||||
type: OptionalString,
|
type: OptionalString,
|
||||||
path: true,
|
path: true,
|
||||||
description: "Path to certificate. Generated if no path is provided.",
|
description: "Path to certificate. A self signed certificate is generated if none is provided.",
|
||||||
|
},
|
||||||
|
"cert-host": {
|
||||||
|
type: "string",
|
||||||
|
description: "Hostname to use when generating a self signed certificate.",
|
||||||
},
|
},
|
||||||
"cert-key": { type: "string", path: true, description: "Path to certificate key when using non-generated cert." },
|
"cert-key": { type: "string", path: true, description: "Path to certificate key when using non-generated cert." },
|
||||||
"disable-telemetry": { type: "boolean", description: "Disable telemetry." },
|
"disable-telemetry": { type: "boolean", description: "Disable telemetry." },
|
||||||
|
@ -429,7 +434,7 @@ export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promi
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.cert && !args.cert.value) {
|
if (args.cert && !args.cert.value) {
|
||||||
const { cert, certKey } = await generateCertificate()
|
const { cert, certKey } = await generateCertificate(args["cert-host"] || "localhost")
|
||||||
args.cert = {
|
args.cert = {
|
||||||
value: cert,
|
value: cert,
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,11 +121,7 @@ const main = async (args: DefaultedArgs): Promise<void> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.cert) {
|
if (args.cert) {
|
||||||
logger.info(
|
logger.info(" - Using certificate for HTTPS: ${humanPath(args.cert.value)}")
|
||||||
args.cert && args.cert.value
|
|
||||||
? ` - Using provided certificate and key for HTTPS`
|
|
||||||
: ` - Using generated certificate and key for HTTPS`,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
logger.info(" - Not serving HTTPS")
|
logger.info(" - Not serving HTTPS")
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,25 +54,45 @@ export function humanPath(p?: string): string {
|
||||||
return p.replace(os.homedir(), "~")
|
return p.replace(os.homedir(), "~")
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateCertificate = async (): Promise<{ cert: string; certKey: string }> => {
|
export const generateCertificate = async (hostname: string): Promise<{ cert: string; certKey: string }> => {
|
||||||
const paths = {
|
const certPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.crt`)
|
||||||
cert: path.join(tmpdir, "self-signed.cert"),
|
const certKeyPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.key`)
|
||||||
certKey: path.join(tmpdir, "self-signed.key"),
|
|
||||||
}
|
const checks = await Promise.all([fs.pathExists(certPath), fs.pathExists(certKeyPath)])
|
||||||
const checks = await Promise.all([fs.pathExists(paths.cert), fs.pathExists(paths.certKey)])
|
|
||||||
if (!checks[0] || !checks[1]) {
|
if (!checks[0] || !checks[1]) {
|
||||||
// Require on demand so openssl isn't required if you aren't going to
|
// Require on demand so openssl isn't required if you aren't going to
|
||||||
// generate certificates.
|
// generate certificates.
|
||||||
const pem = require("pem") as typeof import("pem")
|
const pem = require("pem") as typeof import("pem")
|
||||||
const certs = await new Promise<import("pem").CertificateCreationResult>((resolve, reject): void => {
|
const certs = await new Promise<import("pem").CertificateCreationResult>((resolve, reject): void => {
|
||||||
pem.createCertificate({ selfSigned: true }, (error, result) => {
|
pem.createCertificate(
|
||||||
return error ? reject(error) : resolve(result)
|
{
|
||||||
})
|
selfSigned: true,
|
||||||
|
commonName: hostname,
|
||||||
|
config: `
|
||||||
|
[req]
|
||||||
|
req_extensions = v3_req
|
||||||
|
|
||||||
|
[ v3_req ]
|
||||||
|
basicConstraints = CA:true
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1 = ${hostname}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
(error, result) => {
|
||||||
|
return error ? reject(error) : resolve(result)
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
await fs.mkdirp(tmpdir)
|
await fs.mkdirp(paths.data)
|
||||||
await Promise.all([fs.writeFile(paths.cert, certs.certificate), fs.writeFile(paths.certKey, certs.serviceKey)])
|
await Promise.all([fs.writeFile(certPath, certs.certificate), fs.writeFile(certKeyPath, certs.serviceKey)])
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cert: certPath,
|
||||||
|
certKey: certKeyPath,
|
||||||
}
|
}
|
||||||
return paths
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generatePassword = async (length = 24): Promise<string> => {
|
export const generatePassword = async (length = 24): Promise<string> => {
|
||||||
|
|
|
@ -144,7 +144,7 @@ export class VscodeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc.on("message", (message: ipc.VscodeMessage) => {
|
proc.on("message", (message: ipc.VscodeMessage) => {
|
||||||
logger.debug("got message from vscode", field("message", message))
|
logger.trace("got message from vscode", field("message", message))
|
||||||
if (fn(message)) {
|
if (fn(message)) {
|
||||||
cleanup()
|
cleanup()
|
||||||
resolve(message)
|
resolve(message)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import * as net from "net"
|
||||||
|
|
||||||
export const handleUpgrade = (app: express.Express, server: http.Server): void => {
|
export const handleUpgrade = (app: express.Express, server: http.Server): void => {
|
||||||
server.on("upgrade", (req, socket, head) => {
|
server.on("upgrade", (req, socket, head) => {
|
||||||
|
socket.pause()
|
||||||
|
|
||||||
req.ws = socket
|
req.ws = socket
|
||||||
req.head = head
|
req.head = head
|
||||||
req._ws_handled = false
|
req._ws_handled = false
|
||||||
|
|
|
@ -45,7 +45,7 @@ describe("SocketProxyProvider", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const cert = await generateCertificate()
|
const cert = await generateCertificate("localhost")
|
||||||
const options = {
|
const options = {
|
||||||
cert: fs.readFileSync(cert.cert),
|
cert: fs.readFileSync(cert.cert),
|
||||||
key: fs.readFileSync(cert.certKey),
|
key: fs.readFileSync(cert.certKey),
|
||||||
|
|
Loading…
Reference in New Issue