diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9dfc0f7f5..1e213f0ad 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,10 +33,10 @@ jobs: fetch-depth: 0 submodules: true - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Install helm uses: azure/setup-helm@v2.1 @@ -74,10 +74,10 @@ jobs: fetch-depth: 0 submodules: true - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Fetch dependencies from cache id: cache-yarn @@ -116,10 +116,10 @@ jobs: - name: Patch Code run: quilt push -a - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Fetch dependencies from cache id: cache-yarn @@ -253,15 +253,15 @@ jobs: with: fetch-depth: 0 - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Install development tools run: | yum install -y epel-release centos-release-scl - yum install -y devtoolset-9-{make,gcc,gcc-c++} jq rsync + yum install -y devtoolset-9-{make,gcc,gcc-c++} jq rsync python3 - name: Install nfpm and envsubst run: | @@ -337,7 +337,7 @@ jobs: CXX: ${{ format('{0}-g++', matrix.prefix) }} LINK: ${{ format('{0}-g++', matrix.prefix) }} NPM_CONFIG_ARCH: ${{ matrix.arch }} - NODE_VERSION: v14.17.4 + NODE_VERSION: v16.13.0 steps: - name: Checkout repo @@ -345,10 +345,10 @@ jobs: with: fetch-depth: 0 - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Install nfpm run: | @@ -397,10 +397,10 @@ jobs: with: fetch-depth: 0 - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Install nfpm run: | @@ -446,10 +446,10 @@ jobs: fetch-depth: 0 submodules: true - - name: Install Node.js v14 + - name: Install Node.js v16 uses: actions/setup-node@v3 with: - node-version: "14" + node-version: "16" - name: Fetch dependencies from cache id: cache-yarn diff --git a/ci/build/build-release.sh b/ci/build/build-release.sh index 07a879c28..e484b2518 100755 --- a/ci/build/build-release.sh +++ b/ci/build/build-release.sh @@ -146,7 +146,7 @@ EOF # Include global extension dependencies as well. rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions/package.json" rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions/yarn.lock" - rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions/postinstall.js" + rsync "$VSCODE_SRC_PATH/extensions/postinstall.mjs" "$VSCODE_OUT_PATH/extensions/postinstall.mjs" pushd "$VSCODE_OUT_PATH" symlink_asar diff --git a/ci/build/npm-postinstall.sh b/ci/build/npm-postinstall.sh index fd437a652..d98bd992d 100755 --- a/ci/build/npm-postinstall.sh +++ b/ci/build/npm-postinstall.sh @@ -33,8 +33,8 @@ main() { echo "USE AT YOUR OWN RISK!" fi - if [ "$major_node_version" -ne "${FORCE_NODE_VERSION:-14}" ]; then - echo "ERROR: code-server currently requires node v14." + if [ "$major_node_version" -ne "${FORCE_NODE_VERSION:-16}" ]; then + echo "ERROR: code-server currently requires node v16." if [ -n "$FORCE_NODE_VERSION" ]; then echo "However, you have overrided the version check to use v$FORCE_NODE_VERSION." fi @@ -92,7 +92,7 @@ symlink_asar() { vscode_yarn() { echo 'Installing Code dependencies...' cd lib/vscode - yarn --production --frozen-lockfile + yarn --production --frozen-lockfile --no-default-rc symlink_asar diff --git a/ci/dev/postinstall.sh b/ci/dev/postinstall.sh index 170cdb46f..a83fda555 100755 --- a/ci/dev/postinstall.sh +++ b/ci/dev/postinstall.sh @@ -7,6 +7,9 @@ install-deps() { if [[ ${CI-} ]]; then args+=(--frozen-lockfile) fi + if [[ "$1" == "lib/vscode" ]]; then + args+=(--no-default-rc) + fi # If there is no package.json then yarn will look upward and end up installing # from the root resulting in an infinite loop (this can happen if you have not # checked out the submodule yet for example). diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index eaa4b736a..c12ff3020 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -96,6 +96,8 @@ re-apply the patches. ### Version updates to Code 1. Update the `lib/vscode` submodule to the desired upstream version branch. + 1. `cd lib/vscode && git checkout release/1.66 && cd ../..` + 2. `git add lib && git commit -m "chore: update Code"` 2. Apply the patches (`quilt push -a`) or restore your stashed changes. At this stage you may need to resolve conflicts. For example use `quilt push -f`, manually apply the rejected portions, then `quilt refresh`. @@ -130,11 +132,13 @@ yarn build:vscode yarn release ``` +_NOTE: this does not keep `node_modules`. If you want them to be kept, use `KEEP_MODULES=1 yarn release` (if you're testing in Coder, you'll want to do this)_ + Run your build: ```shell cd release -yarn --production +yarn --production # Skip if you used KEEP_MODULES=1 # Runs the built JavaScript with Node. node . ``` diff --git a/docs/android.md b/docs/android.md index 41fd92dbe..74bbcf503 100644 --- a/docs/android.md +++ b/docs/android.md @@ -11,11 +11,11 @@ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash ``` 6. Exit the terminal using `exit` and then reopen the terminal -7. Install and use Node.js 14: +7. Install and use Node.js 16: ```shell -nvm install 14 -nvm use 14 +nvm install 16 +nvm use 16 ``` 8. Install code-server globally on device with: `npm i -g code-server` diff --git a/docs/npm.md b/docs/npm.md index 27ceaf22f..5b50235bb 100644 --- a/docs/npm.md +++ b/docs/npm.md @@ -22,8 +22,8 @@ includes installing instructions based on your operating system. ## Node.js version -We use the same major version of Node.js shipped with VSCode's Electron, -which is currently `14.x`. VS Code also [lists Node.js +We use the same major version of Node.js shipped with Code's remote, which is +currently `16.x`. VS Code also [lists Node.js requirements](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites). Using other versions of Node.js [may lead to unexpected @@ -72,7 +72,7 @@ Proceed to [installing](#installing) ## FreeBSD ```sh -pkg install -y git python npm-node14 yarn-node14 pkgconf +pkg install -y git python npm-node16 yarn-node16 pkgconf pkg install -y libinotify ``` diff --git a/lib/vscode b/lib/vscode index c722ca6c7..dfd34e826 160000 --- a/lib/vscode +++ b/lib/vscode @@ -1 +1 @@ -Subproject commit c722ca6c7eed3d7987c0d5c3df5c45f6b15e77d1 +Subproject commit dfd34e8260c270da74b5c2d86d61aee4b6d56977 diff --git a/package.json b/package.json index 0d9e7ad93..be5253bb3 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "browser-ide" ], "engines": { - "node": ">= 14" + "node": "16" }, "jest": { "transform": { diff --git a/patches/base-path.diff b/patches/base-path.diff index c7d032b18..95bb8388e 100644 --- a/patches/base-path.diff +++ b/patches/base-path.diff @@ -159,7 +159,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -252,7 +252,10 @@ export class WebClientServer { +@@ -253,7 +253,10 @@ export class WebClientServer { return res.end(); } @@ -171,7 +171,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts function escapeAttribute(value: string): string { return value.replace(/"/g, '"'); -@@ -272,6 +275,8 @@ export class WebClientServer { +@@ -275,6 +278,8 @@ export class WebClientServer { accessToken: this._environmentService.args['github-auth'], scopes: [['user:email'], ['repo']] } : undefined; @@ -180,15 +180,15 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts const data = (await util.promisify(fs.readFile)(filePath)).toString() .replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({ remoteAuthority, -@@ -279,6 +284,7 @@ export class WebClientServer { - developmentOptions: { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined }, - settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, +@@ -285,6 +290,7 @@ export class WebClientServer { + folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']), + workspaceUri: resolveWorkspaceURI(this._environmentService.args['default-workspace']), productConfiguration: >{ + rootEndpoint: base, codeServerVersion: this._productService.codeServerVersion, embedderIdentifier: 'server-distro', extensionsGallery: this._webExtensionResourceUrlTemplate ? { -@@ -291,7 +297,9 @@ export class WebClientServer { +@@ -297,7 +303,9 @@ export class WebClientServer { } : undefined } }))) @@ -199,7 +199,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts const cspDirectives = [ 'default-src \'self\';', -@@ -370,3 +378,70 @@ export class WebClientServer { +@@ -376,3 +384,70 @@ export class WebClientServer { return res.end(data); } } diff --git a/patches/connection-type.diff b/patches/connection-type.diff index 9f04bc299..050715c90 100644 --- a/patches/connection-type.diff +++ b/patches/connection-type.diff @@ -4,12 +4,18 @@ This allows the backend to distinguish them. In our case we use them to count a single "open" of Code so we need to be able to distinguish between web sockets from two instances and two web sockets used in a single instance. +To test this, +1. Run code-server +2. Open Network tab in Browser DevTools and filter for websocket requests +3. You should see the `type=` in the request url + + Index: code-server/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts +++ code-server/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts @@ -231,7 +231,7 @@ async function connectToRemoteExtensionH - + let socket: ISocket; try { - socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, `renderer-${connectionTypeToString(connectionType)}-${options.reconnectionToken}`, timeoutCancellationToken); diff --git a/patches/disable-builtin-ext-update.diff b/patches/disable-builtin-ext-update.diff new file mode 100644 index 000000000..4cee1361a --- /dev/null +++ b/patches/disable-builtin-ext-update.diff @@ -0,0 +1,30 @@ +Prevent builtin extensions from being updated + +Updating builtin extensions from the marketplace prevents us from patching them +(for example out GitHub authentication patches). + +Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +=================================================================== +--- code-server.orig/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts ++++ code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +@@ -206,6 +206,9 @@ export class Extension implements IExten + if (!this.gallery || !this.local) { + return false; + } ++ if (this.type !== ExtensionType.User) { ++ return false; ++ } + if (!this.local.preRelease && this.gallery.properties.isPreReleaseVersion) { + return false; + } +@@ -1057,6 +1060,10 @@ export class ExtensionsWorkbenchService + // Skip if check updates only for builtin extensions and current extension is not builtin. + continue; + } ++ if (installed.type !== ExtensionType.User) { ++ // Never update builtin extensions. ++ continue; ++ } + if (installed.isBuiltin && !installed.local?.identifier.uuid) { + // Skip if the builtin extension does not have Marketplace id + continue; diff --git a/patches/disable-downloads.diff b/patches/disable-downloads.diff index 3c4b87da9..7568fcd0b 100644 --- a/patches/disable-downloads.diff +++ b/patches/disable-downloads.diff @@ -12,7 +12,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/web.api.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/browser/web.api.ts +++ code-server/lib/vscode/src/vs/workbench/browser/web.api.ts -@@ -210,6 +210,11 @@ export interface IWorkbenchConstructionO +@@ -215,6 +215,11 @@ export interface IWorkbenchConstructionO */ readonly userDataPath?: string @@ -66,7 +66,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts /* ----- server setup ----- */ -@@ -92,6 +93,7 @@ export interface ServerParsedArgs { +@@ -96,6 +97,7 @@ export interface ServerParsedArgs { 'disable-update-check'?: boolean; 'auth'?: string 'locale'?: string @@ -78,14 +78,14 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -290,6 +290,7 @@ export class WebClientServer { +@@ -293,6 +293,7 @@ export class WebClientServer { logLevel: this._logService.getLevel(), }, userDataPath: this._environmentService.userDataPath, + isEnabledFileDownloads: !this._environmentService.args['disable-file-downloads'], settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, - productConfiguration: >{ - rootEndpoint: base, + enableWorkspaceTrust: !this._environmentService.args['disable-workspace-trust'], + folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']), Index: code-server/lib/vscode/src/vs/workbench/browser/contextkeys.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/browser/contextkeys.ts @@ -135,7 +135,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts -@@ -21,7 +21,7 @@ import { CLOSE_SAVED_EDITORS_COMMAND_ID, +@@ -22,7 +22,7 @@ import { CLOSE_SAVED_EDITORS_COMMAND_ID, import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { Schemas } from 'vs/base/common/network'; @@ -144,7 +144,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; -@@ -475,13 +475,16 @@ MenuRegistry.appendMenuItem(MenuId.Explo +@@ -476,13 +476,16 @@ MenuRegistry.appendMenuItem(MenuId.Explo id: DOWNLOAD_COMMAND_ID, title: DOWNLOAD_LABEL }, diff --git a/patches/display-language.diff b/patches/display-language.diff index 6bfc0c75d..aad709545 100644 --- a/patches/display-language.diff +++ b/patches/display-language.diff @@ -6,7 +6,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/serverServices.ts +++ code-server/lib/vscode/src/vs/server/node/serverServices.ts -@@ -188,6 +188,9 @@ export async function setupServerService +@@ -192,6 +192,9 @@ export async function setupServerService const channel = new ExtensionManagementChannel(extensionManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority)); socketServer.registerChannel('extensions', channel); @@ -94,7 +94,7 @@ Index: code-server/lib/vscode/src/vs/platform/environment/common/environmentServ =================================================================== --- code-server.orig/lib/vscode/src/vs/platform/environment/common/environmentService.ts +++ code-server/lib/vscode/src/vs/platform/environment/common/environmentService.ts -@@ -105,7 +105,7 @@ export abstract class AbstractNativeEnvi +@@ -108,7 +108,7 @@ export abstract class AbstractNativeEnvi return URI.file(join(vscodePortable, 'argv.json')); } @@ -168,7 +168,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -26,6 +26,7 @@ import { URI } from 'vs/base/common/uri' +@@ -27,6 +27,7 @@ import { URI } from 'vs/base/common/uri' import { streamToBuffer } from 'vs/base/common/buffer'; import { IProductConfiguration } from 'vs/base/common/product'; import { isString } from 'vs/base/common/types'; @@ -176,7 +176,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts const textMimeType = { '.html': 'text/html', -@@ -277,6 +278,8 @@ export class WebClientServer { +@@ -280,6 +281,8 @@ export class WebClientServer { } : undefined; const base = relativeRoot(getOriginalUrl(req)) const vscodeBase = relativePath(getOriginalUrl(req)) @@ -185,7 +185,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts const data = (await util.promisify(fs.readFile)(filePath)).toString() .replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({ remoteAuthority, -@@ -303,7 +306,8 @@ export class WebClientServer { +@@ -309,7 +312,8 @@ export class WebClientServer { }))) .replace('{{WORKBENCH_AUTH_SESSION}}', () => authSessionInfo ? escapeAttribute(JSON.stringify(authSessionInfo)) : '') .replace(/{{BASE}}/g, base) @@ -207,7 +207,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts /* ----- server setup ----- */ -@@ -90,6 +91,7 @@ export interface ServerParsedArgs { +@@ -94,6 +95,7 @@ export interface ServerParsedArgs { /* ----- code-server ----- */ 'disable-update-check'?: boolean; 'auth'?: string @@ -252,7 +252,7 @@ Index: code-server/lib/vscode/src/vs/workbench/workbench.web.main.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/workbench.web.main.ts +++ code-server/lib/vscode/src/vs/workbench/workbench.web.main.ts -@@ -111,6 +111,10 @@ registerSingleton(IDiagnosticsService, N +@@ -112,6 +112,10 @@ registerSingleton(IDiagnosticsService, N //#region --- workbench contributions diff --git a/patches/github-auth.diff b/patches/github-auth.diff index 9e0af8094..53b98d0f4 100644 --- a/patches/github-auth.diff +++ b/patches/github-auth.diff @@ -1,118 +1,104 @@ -Use our own GitHub auth relay server +Add the ability to provide a GitHub token -Microsoft's does not work with self-hosted instances so we run our own. +To test install the GitHub PR extension and start code-server with GITHUB_TOKEN +or set github-auth in the config file. The extension should be authenticated. -Also add an extra set of scopes so that tokens provided via --github-auth will -work for the PR extension. - -Index: code-server/lib/vscode/extensions/github-authentication/src/githubServer.ts +Index: code-server/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts =================================================================== ---- code-server.orig/lib/vscode/extensions/github-authentication/src/githubServer.ts -+++ code-server/lib/vscode/extensions/github-authentication/src/githubServer.ts -@@ -17,7 +17,7 @@ const localize = nls.loadMessageBundle() - const CLIENT_ID = '01ab8ac9400c4e429b23'; +--- code-server.orig/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts ++++ code-server/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts +@@ -5,18 +5,32 @@ - const NETWORK_ERROR = 'network error'; --const AUTH_RELAY_SERVER = 'vscode-auth.github.com'; -+const AUTH_RELAY_SERVER = 'auth.code-server.dev'; - // const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com'; - - class UriEventHandler extends vscode.EventEmitter implements vscode.UriHandler { -Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts -=================================================================== ---- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts -+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -274,7 +274,7 @@ export class WebClientServer { - id: generateUuid(), - providerId: 'github', - accessToken: this._environmentService.args['github-auth'], -- scopes: [['user:email'], ['repo']] -+ scopes: [['read:user', 'user:email', 'repo'], ['user:email'], ['repo']] - } : undefined; - const base = relativeRoot(getOriginalUrl(req)) - const vscodeBase = relativePath(getOriginalUrl(req)) -Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts -=================================================================== ---- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts -+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts -@@ -17,6 +17,7 @@ import { isFolderToOpen, isWorkspaceToOp - import { create, ICredentialsProvider, IURLCallbackProvider, IWorkbenchConstructionOptions, IWorkspace, IWorkspaceProvider } from 'vs/workbench/workbench.web.main'; - import { posix } from 'vs/base/common/path'; - import { ltrim } from 'vs/base/common/strings'; + import { InMemoryCredentialsProvider } from 'vs/platform/credentials/common/credentials'; + import { ILogService } from 'vs/platform/log/common/log'; +-import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; ++import { IServerEnvironmentService } from 'vs/server/node/serverEnvironmentService'; + import { IProductService } from 'vs/platform/product/common/productService'; + import { BaseCredentialsMainService, KeytarModule } from 'vs/platform/credentials/common/credentialsMainService'; ++import { generateUuid } from 'vs/base/common/uuid'; +import { equals as arrayEquals } from 'vs/base/common/arrays'; - - interface ICredential { - service: string; -@@ -24,6 +25,13 @@ interface ICredential { - password: string; - } - ++ +interface IToken { + accessToken: string + account?: { label: string } + id: string + scopes: string[] +} -+ - class LocalStorageCredentialsProvider implements ICredentialsProvider { - private static readonly CREDENTIALS_STORAGE_KEY = 'credentials.provider'; -@@ -51,6 +59,58 @@ class LocalStorageCredentialsProvider im - scopes, - accessToken: authSessionInfo!.accessToken - })))); -+ -+ // Add tokens for extensions to use. This works for extensions like the -+ // pull requests one or GitLens. -+ const extensionId = `vscode.${authSessionInfo.providerId}-authentication`; -+ const service = `${product.urlProtocol}${extensionId}`; -+ const account = `${authSessionInfo.providerId}.auth`; -+ // Oddly the scopes need to match exactly so we cannot just have one token -+ // with all the scopes, instead we have to duplicate the token for each -+ // expected set of scopes. -+ const tokens: IToken[] = authSessionInfo.scopes.map((scopes) => ({ -+ id: authSessionInfo!.id, -+ scopes: scopes.sort(), // Sort for comparing later. -+ accessToken: authSessionInfo!.accessToken, -+ })); -+ this.getPassword(service, account).then((raw) => { -+ let existing: { -+ content: IToken[] -+ } | undefined; -+ -+ if (raw) { -+ try { -+ const json = JSON.parse(raw); -+ json.content = JSON.parse(json.content); -+ existing = json; -+ } catch (error) { -+ console.log(error); -+ } -+ } -+ -+ // Keep tokens for account and scope combinations we do not have in case -+ // there is an extension that uses scopes we have not accounted for (in -+ // these cases the user will need to manually authenticate the extension -+ // through the UI) or the user has tokens for other accounts. -+ if (existing?.content) { -+ existing.content = existing.content.filter((existingToken) => { -+ const scopes = existingToken.scopes.sort(); -+ return !(tokens.find((token) => { -+ return arrayEquals(scopes, token.scopes) -+ && token.account?.label === existingToken.account?.label; -+ })) -+ }) -+ } -+ -+ return this.setPassword(service, account, JSON.stringify({ -+ extensionId, -+ ...(existing || {}), -+ content: JSON.stringify([ -+ ...tokens, -+ ...(existing?.content || []), -+ ]) -+ })); + export class CredentialsWebMainService extends BaseCredentialsMainService { + + constructor( + @ILogService logService: ILogService, +- @INativeEnvironmentService private readonly environmentMainService: INativeEnvironmentService, ++ @IServerEnvironmentService private readonly environmentMainService: IServerEnvironmentService, + @IProductService private readonly productService: IProductService, + ) { + super(logService); ++ if (this.environmentMainService.args["github-auth"]) { ++ this.storeGitHubToken(this.environmentMainService.args["github-auth"]).catch((error) => { ++ this.logService.error('Failed to store provided GitHub token', error) + }) - } ++ } } + // If the credentials service is running on the server, we add a suffix -server to differentiate from the location that the +@@ -45,4 +59,59 @@ export class CredentialsWebMainService e + } + return this._keytarCache; + } ++ ++ private async storeGitHubToken(githubToken: string): Promise { ++ const extensionId = 'vscode.github-authentication'; ++ const service = `${await this.getSecretStoragePrefix()}${extensionId}`; ++ const account = 'github.auth'; ++ const scopes = [['read:user', 'user:email', 'repo']] ++ ++ // Oddly the scopes need to match exactly so we cannot just have one token ++ // with all the scopes, instead we have to duplicate the token for each ++ // expected set of scopes. ++ const tokens: IToken[] = scopes.map((scopes) => ({ ++ id: generateUuid(), ++ scopes: scopes.sort(), // Sort for comparing later. ++ accessToken: githubToken, ++ })); ++ ++ const raw = await this.getPassword(service, account) ++ ++ let existing: { ++ content: IToken[] ++ } | undefined; ++ ++ if (raw) { ++ try { ++ const json = JSON.parse(raw); ++ json.content = JSON.parse(json.content); ++ existing = json; ++ } catch (error) { ++ this.logService.error('Failed to parse existing GitHub credentials', error) ++ } ++ } ++ ++ // Keep tokens for account and scope combinations we do not have in case ++ // there is an extension that uses scopes we have not accounted for (in ++ // these cases the user will need to manually authenticate the extension ++ // through the UI) or the user has tokens for other accounts. ++ if (existing?.content) { ++ existing.content = existing.content.filter((existingToken) => { ++ const scopes = existingToken.scopes.sort(); ++ return !(tokens.find((token) => { ++ return arrayEquals(scopes, token.scopes) ++ && token.account?.label === existingToken.account?.label; ++ })) ++ }) ++ } ++ ++ return this.setPassword(service, account, JSON.stringify({ ++ extensionId, ++ ...(existing || {}), ++ content: JSON.stringify([ ++ ...tokens, ++ ...(existing?.content || []), ++ ]) ++ })); ++ } + } diff --git a/patches/insecure-notification.diff b/patches/insecure-notification.diff index bc94e24b4..101836038 100644 --- a/patches/insecure-notification.diff +++ b/patches/insecure-notification.diff @@ -5,7 +5,12 @@ may think code-server is broken. Ideally there would be a notification at the point where these things are used instead of this though. To test access over something like an HTTP domain or an IP address (not -localhost). +localhost). For example: + +1. run code-server +2. use ngrok to expose code-server +3. access via HTTP +4. look for notification in bottom right Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts =================================================================== @@ -15,7 +20,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts import { Disposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; - + export class CodeServerClient extends Disposable { constructor ( + @INotificationService private notificationService: INotificationService, diff --git a/patches/integration.diff b/patches/integration.diff index d5348f06a..e8c197238 100644 --- a/patches/integration.diff +++ b/patches/integration.diff @@ -21,7 +21,7 @@ Index: code-server/lib/vscode/src/vs/server/node/server.main.ts import product from 'vs/platform/product/common/product'; import * as perf from 'vs/base/common/performance'; -@@ -33,37 +33,42 @@ const errorReporter: ErrorReporter = { +@@ -33,38 +33,43 @@ const errorReporter: ErrorReporter = { } }; @@ -34,6 +34,7 @@ Index: code-server/lib/vscode/src/vs/server/node/server.main.ts -const USER_DATA_PATH = join(REMOTE_DATA_FOLDER, 'data'); -const APP_SETTINGS_HOME = join(USER_DATA_PATH, 'User'); -const GLOBAL_STORAGE_HOME = join(APP_SETTINGS_HOME, 'globalStorage'); +-const LOCAL_HISTORY_HOME = join(APP_SETTINGS_HOME, 'History'); -const MACHINE_SETTINGS_HOME = join(USER_DATA_PATH, 'Machine'); -args['user-data-dir'] = USER_DATA_PATH; -const APP_ROOT = dirname(FileAccess.asFileUri('', require).fsPath); @@ -41,7 +42,7 @@ Index: code-server/lib/vscode/src/vs/server/node/server.main.ts -args['builtin-extensions-dir'] = BUILTIN_EXTENSIONS_FOLDER_PATH; -args['extensions-dir'] = args['extensions-dir'] || join(REMOTE_DATA_FOLDER, 'extensions'); - --[REMOTE_DATA_FOLDER, args['extensions-dir'], USER_DATA_PATH, APP_SETTINGS_HOME, MACHINE_SETTINGS_HOME, GLOBAL_STORAGE_HOME].forEach(f => { +-[REMOTE_DATA_FOLDER, args['extensions-dir'], USER_DATA_PATH, APP_SETTINGS_HOME, MACHINE_SETTINGS_HOME, GLOBAL_STORAGE_HOME, LOCAL_HISTORY_HOME].forEach(f => { - try { - if (!fs.existsSync(f)) { - fs.mkdirSync(f, { mode: 0o700 }); @@ -53,6 +54,7 @@ Index: code-server/lib/vscode/src/vs/server/node/server.main.ts + const USER_DATA_PATH = args['user-data-dir'] || join(REMOTE_DATA_FOLDER, 'data'); + const APP_SETTINGS_HOME = join(USER_DATA_PATH, 'User'); + const GLOBAL_STORAGE_HOME = join(APP_SETTINGS_HOME, 'globalStorage'); ++ const LOCAL_HISTORY_HOME = join(APP_SETTINGS_HOME, 'History'); + const MACHINE_SETTINGS_HOME = join(USER_DATA_PATH, 'Machine'); + args['user-data-dir'] = USER_DATA_PATH; + const APP_ROOT = dirname(FileAccess.asFileUri('', require).fsPath); @@ -60,14 +62,14 @@ Index: code-server/lib/vscode/src/vs/server/node/server.main.ts + args['builtin-extensions-dir'] = BUILTIN_EXTENSIONS_FOLDER_PATH; + args['extensions-dir'] = args['extensions-dir'] || join(REMOTE_DATA_FOLDER, 'extensions'); + -+ [REMOTE_DATA_FOLDER, args['extensions-dir'], USER_DATA_PATH, APP_SETTINGS_HOME, MACHINE_SETTINGS_HOME, GLOBAL_STORAGE_HOME].forEach(f => { ++ [REMOTE_DATA_FOLDER, args['extensions-dir'], USER_DATA_PATH, APP_SETTINGS_HOME, MACHINE_SETTINGS_HOME, GLOBAL_STORAGE_HOME, LOCAL_HISTORY_HOME].forEach(f => { + try { + if (!fs.existsSync(f)) { + fs.mkdirSync(f, { mode: 0o700 }); + } + } catch (err) { console.error(err); } + }); -+ return REMOTE_DATA_FOLDER ++ return REMOTE_DATA_FOLDER; +} /** @@ -261,9 +263,9 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -279,6 +279,7 @@ export class WebClientServer { - developmentOptions: { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined }, - settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, +@@ -285,6 +285,7 @@ export class WebClientServer { + folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']), + workspaceUri: resolveWorkspaceURI(this._environmentService.args['default-workspace']), productConfiguration: >{ + codeServerVersion: this._productService.codeServerVersion, embedderIdentifier: 'server-distro', diff --git a/patches/last-opened.diff b/patches/last-opened.diff deleted file mode 100644 index 71a1c9980..000000000 --- a/patches/last-opened.diff +++ /dev/null @@ -1,8 +0,0 @@ -Remove last opened functionality - -This conflicts with our own handling of the last opened workspace. If we wanted -to switch to this we would need to pass through the disable-last-opened flag and -respect it here then remove our own redirction code that handles this. - -Our version might be better anyway since it puts the workspace in the URL. - diff --git a/patches/local-storage.diff b/patches/local-storage.diff index 4c3c90da1..744540bbf 100644 --- a/patches/local-storage.diff +++ b/patches/local-storage.diff @@ -20,19 +20,19 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -289,6 +289,7 @@ export class WebClientServer { +@@ -292,6 +292,7 @@ export class WebClientServer { enableSmokeTestDriver: this._environmentService.driverHandle === 'web' ? true : undefined, logLevel: this._logService.getLevel(), }, + userDataPath: this._environmentService.userDataPath, settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, - productConfiguration: >{ - rootEndpoint: base, + enableWorkspaceTrust: !this._environmentService.args['disable-workspace-trust'], + folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']), Index: code-server/lib/vscode/src/vs/workbench/browser/web.api.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/browser/web.api.ts +++ code-server/lib/vscode/src/vs/workbench/browser/web.api.ts -@@ -205,6 +205,11 @@ export interface IWorkbenchConstructionO +@@ -210,6 +210,11 @@ export interface IWorkbenchConstructionO */ readonly configurationDefaults?: Record; @@ -52,7 +52,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/envi get logFile(): URI { return joinPath(this.logsHome, 'window.log'); } @memoize -- get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.userData }); } +- get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.vscodeUserData }); } + get userRoamingDataHome(): URI { return joinPath(URI.file(this.userDataPath).with({ scheme: Schemas.vscodeRemote }), 'User'); } + + get userDataPath(): string { diff --git a/patches/log-level.diff b/patches/log-level.diff index ce99f08be..8b4f125b5 100644 --- a/patches/log-level.diff +++ b/patches/log-level.diff @@ -7,7 +7,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -285,7 +285,10 @@ export class WebClientServer { +@@ -288,7 +288,10 @@ export class WebClientServer { remoteAuthority, webviewEndpoint: vscodeBase + '/static/out/vs/workbench/contrib/webview/browser/pre', _wrapWebWorkerExtHostInIframe, @@ -17,5 +17,5 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts + logLevel: this._logService.getLevel(), + }, settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, - productConfiguration: >{ - rootEndpoint: base, + enableWorkspaceTrust: !this._environmentService.args['disable-workspace-trust'], + folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']), diff --git a/patches/logout.diff b/patches/logout.diff index 47bb41002..1a8d0f005 100644 --- a/patches/logout.diff +++ b/patches/logout.diff @@ -28,7 +28,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts /* ----- server setup ----- */ -@@ -88,6 +89,7 @@ export const serverOptions: OptionDescri +@@ -92,6 +93,7 @@ export const serverOptions: OptionDescri export interface ServerParsedArgs { /* ----- code-server ----- */ 'disable-update-check'?: boolean; @@ -40,7 +40,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -287,6 +287,7 @@ export class WebClientServer { +@@ -293,6 +293,7 @@ export class WebClientServer { productConfiguration: >{ rootEndpoint: base, updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined, diff --git a/patches/marketplace.diff b/patches/marketplace.diff index 77f469f10..d6e799756 100644 --- a/patches/marketplace.diff +++ b/patches/marketplace.diff @@ -32,7 +32,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -287,14 +287,14 @@ export class WebClientServer { +@@ -293,14 +293,14 @@ export class WebClientServer { rootEndpoint: base, codeServerVersion: this._productService.codeServerVersion, embedderIdentifier: 'server-distro', diff --git a/patches/node-version.diff b/patches/node-version.diff deleted file mode 100644 index 9ee48e87f..000000000 --- a/patches/node-version.diff +++ /dev/null @@ -1,107 +0,0 @@ -Patch the Node version to use the current version of Node - -Previously it would use the yarnrc which results in builds that cannot run with -the version of Node they were built with because the native modules are -targeting the wrong version. - -One way test this is to build in a fresh Docker container, run the build, then -try opening the built-in terminal. - -Index: code-server/lib/vscode/build/gulpfile.reh.js -=================================================================== ---- code-server.orig/lib/vscode/build/gulpfile.reh.js -+++ code-server/lib/vscode/build/gulpfile.reh.js -@@ -124,9 +124,7 @@ const serverWithWebEntryPoints = [ - ]; - - function getNodeVersion() { -- const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); -- const target = /^target "(.*)"$/m.exec(yarnrc)[1]; -- return target; -+ return process.versions.node; - } - - const nodeVersion = getNodeVersion(); -Index: code-server/lib/vscode/build/lib/node.js -=================================================================== ---- code-server.orig/lib/vscode/build/lib/node.js -+++ code-server/lib/vscode/build/lib/node.js -@@ -7,9 +7,7 @@ Object.defineProperty(exports, "__esModu - const path = require("path"); - const fs = require("fs"); - const root = path.dirname(path.dirname(__dirname)); --const yarnrcPath = path.join(root, 'remote', '.yarnrc'); --const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); --const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)[1]; -+const version = process.versions.node; - const platform = process.platform; - const arch = platform === 'darwin' ? 'x64' : process.arch; - const node = platform === 'win32' ? 'node.exe' : 'node'; -Index: code-server/lib/vscode/build/lib/node.ts -=================================================================== ---- code-server.orig/lib/vscode/build/lib/node.ts -+++ code-server/lib/vscode/build/lib/node.ts -@@ -7,9 +7,7 @@ import * as path from 'path'; - import * as fs from 'fs'; - - const root = path.dirname(path.dirname(__dirname)); --const yarnrcPath = path.join(root, 'remote', '.yarnrc'); --const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); --const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)![1]; -+const version = process.versions.node; - - const platform = process.platform; - const arch = platform === 'darwin' ? 'x64' : process.arch; -Index: code-server/lib/vscode/build/lib/util.js -=================================================================== ---- code-server.orig/lib/vscode/build/lib/util.js -+++ code-server/lib/vscode/build/lib/util.js -@@ -298,9 +298,7 @@ function streamToPromise(stream) { - } - exports.streamToPromise = streamToPromise; - function getElectronVersion() { -- const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); -- const target = /^target "(.*)"$/m.exec(yarnrc)[1]; -- return target; -+ return process.versions.node; - } - exports.getElectronVersion = getElectronVersion; - function acquireWebNodePaths() { -Index: code-server/lib/vscode/build/lib/util.ts -=================================================================== ---- code-server.orig/lib/vscode/build/lib/util.ts -+++ code-server/lib/vscode/build/lib/util.ts -@@ -371,9 +371,7 @@ export function streamToPromise(stream: - } - - export function getElectronVersion(): string { -- const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); -- const target = /^target "(.*)"$/m.exec(yarnrc)![1]; -- return target; -+ return process.versions.node; - } - - export function acquireWebNodePaths() { -@@ -455,4 +453,3 @@ export function buildWebNodePaths(outDir - result.taskName = 'build-web-node-paths'; - return result; - } -- -Index: code-server/lib/vscode/remote/.yarnrc -=================================================================== ---- code-server.orig/lib/vscode/remote/.yarnrc -+++ /dev/null -@@ -1,4 +0,0 @@ --disturl "http://nodejs.org/dist" --target "14.16.0" --runtime "node" --build_from_source "true" -Index: code-server/lib/vscode/.yarnrc -=================================================================== ---- code-server.orig/lib/vscode/.yarnrc -+++ /dev/null -@@ -1,4 +0,0 @@ --disturl "https://electronjs.org/headers" --target "13.5.2" --runtime "electron" --build_from_source "true" diff --git a/patches/parent-origin.diff b/patches/parent-origin.diff new file mode 100644 index 000000000..e49382483 --- /dev/null +++ b/patches/parent-origin.diff @@ -0,0 +1,24 @@ +Remove parentOriginHash checko + +This fixes webviews from not working properly due to a change upstream. +Upstream added a check to ensure parent authority is encoded into the webview +origin. Since our webview origin is the parent authority, we can bypass this +check. + +Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js +=================================================================== +--- code-server.orig/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js ++++ code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js +@@ -317,6 +317,12 @@ const hostMessaging = new class HostMess + const id = searchParams.get('id'); + + const hostname = location.hostname; ++ ++ // It is safe to run if we are on the same host. ++ const parent = new URL(parentOrigin) ++ if (parent.hostname == location.hostname) { ++ return start(parentOrigin) ++ } + + if (!crypto.subtle) { + // cannot validate, not running in a secure context diff --git a/patches/post-install.diff b/patches/post-install.diff deleted file mode 100644 index dc8334e6e..000000000 --- a/patches/post-install.diff +++ /dev/null @@ -1,26 +0,0 @@ -Replace rimraf with fs.rmSync in postinstall - -The postinstall gets ran when you install with npm but rimraf is a development -dependency so it will not exist. - -Index: code-server/lib/vscode/extensions/postinstall.js -=================================================================== ---- code-server.orig/lib/vscode/extensions/postinstall.js -+++ code-server/lib/vscode/extensions/postinstall.js -@@ -8,7 +8,6 @@ - - const fs = require('fs'); - const path = require('path'); --const rimraf = require('rimraf'); - - const root = path.join(__dirname, 'node_modules', 'typescript'); - -@@ -21,7 +20,7 @@ function processRoot() { - if (!toKeep.has(name)) { - const filePath = path.join(root, name); - console.log(`Removed ${filePath}`); -- rimraf.sync(filePath); -+ fs.rmSync(filePath, { recursive: true }); - } - } - } diff --git a/patches/proposed-api.diff b/patches/proposed-api.diff index 5971d714e..ebd5deb57 100644 --- a/patches/proposed-api.diff +++ b/patches/proposed-api.diff @@ -9,7 +9,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/extensions/common/abstra =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ code-server/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts -@@ -1163,7 +1163,7 @@ class ProposedApiController { +@@ -1471,7 +1471,7 @@ class ProposedApiController { this._envEnabledExtensions = new Set((_environmentService.extensionEnabledProposedApi ?? []).map(id => ExtensionIdentifier.toKey(id))); @@ -22,7 +22,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/extensions/common/extens =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts +++ code-server/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts -@@ -134,10 +134,7 @@ export interface IExtensionHost { +@@ -163,10 +163,7 @@ export interface IExtensionHost { } export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean { diff --git a/patches/proxy-uri.diff b/patches/proxy-uri.diff index 1227dfaf9..b153b20df 100644 --- a/patches/proxy-uri.diff +++ b/patches/proxy-uri.diff @@ -68,7 +68,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -288,6 +288,7 @@ export class WebClientServer { +@@ -294,6 +294,7 @@ export class WebClientServer { rootEndpoint: base, updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined, logoutEndpoint: this._environmentService.args['auth'] ? base + '/logout' : undefined, @@ -93,7 +93,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalE =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ code-server/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts -@@ -390,7 +390,7 @@ export function createTerminalEnvironmen +@@ -388,7 +388,7 @@ export function createTerminalEnvironmen // Sanitize the environment, removing any undesirable VS Code and Electron environment // variables diff --git a/patches/series b/patches/series index 79da7efda..5801db6ae 100644 --- a/patches/series +++ b/patches/series @@ -1,9 +1,9 @@ integration.diff -node-version.diff base-path.diff proposed-api.diff marketplace.diff webview.diff +disable-builtin-ext-update.diff insecure-notification.diff update-check.diff logout.diff @@ -12,7 +12,6 @@ proxy-uri.diff display-language.diff github-auth.diff unique-db.diff -post-install.diff log-level.diff local-storage.diff service-worker.diff diff --git a/patches/service-worker.diff b/patches/service-worker.diff index ed12d5449..db2bacd22 100644 --- a/patches/service-worker.diff +++ b/patches/service-worker.diff @@ -21,7 +21,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -298,6 +298,10 @@ export class WebClientServer { +@@ -304,6 +304,10 @@ export class WebClientServer { proxyEndpointTemplate: base + '/proxy/{{port}}', codeServerVersion: this._productService.codeServerVersion, embedderIdentifier: 'server-distro', diff --git a/patches/sourcemaps.diff b/patches/sourcemaps.diff index cb2367e6a..03502650c 100644 --- a/patches/sourcemaps.diff +++ b/patches/sourcemaps.diff @@ -10,7 +10,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.js =================================================================== --- code-server.orig/lib/vscode/build/gulpfile.reh.js +++ code-server/lib/vscode/build/gulpfile.reh.js -@@ -197,8 +197,7 @@ function packageTask(type, platform, arc +@@ -191,8 +191,7 @@ function packageTask(type, platform, arc const src = gulp.src(sourceFolderName + '/**', { base: '.' }) .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); })) @@ -20,7 +20,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.js const workspaceExtensionPoints = ['debuggers', 'jsonValidation']; const isUIExtension = (manifest) => { -@@ -237,9 +236,9 @@ function packageTask(type, platform, arc +@@ -231,9 +230,9 @@ function packageTask(type, platform, arc .map(name => `.build/extensions/${name}/**`); const extensions = gulp.src(extensionPaths, { base: '.build', dot: true }); @@ -32,7 +32,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.js let version = packageJson.version; const quality = product.quality; -@@ -374,7 +373,7 @@ function tweakProductForServerWeb(produc +@@ -368,7 +367,7 @@ function tweakProductForServerWeb(produc const minifyTask = task.define(`minify-vscode-${type}`, task.series( optimizeTask, util.rimraf(`out-vscode-${type}-min`), diff --git a/patches/store-socket.diff b/patches/store-socket.diff index 2bc60652c..5aa40ec64 100644 --- a/patches/store-socket.diff +++ b/patches/store-socket.diff @@ -3,6 +3,12 @@ Store a static reference to the IPC socket This lets us use it to open files inside code-server from outside of code-server. +To test this: +1. run code-server +2. open file outside of code-server i.e. `code-server Application > Storage (top-level) +3. Click "Clear site data" +4. See update notification + Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/browser/client.ts @@ -14,7 +19,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/client.ts import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; - + export class CodeServerClient extends Disposable { constructor ( + @ILogService private logService: ILogService, @@ -93,15 +98,15 @@ Index: code-server/lib/vscode/src/vs/base/common/product.ts readonly codeServerVersion?: string readonly rootEndpoint?: string + readonly updateEndpoint?: string - + readonly version: string; readonly date?: string; Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -286,6 +286,7 @@ export class WebClientServer { - settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, +@@ -292,6 +292,7 @@ export class WebClientServer { + workspaceUri: resolveWorkspaceURI(this._environmentService.args['default-workspace']), productConfiguration: >{ rootEndpoint: base, + updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined, @@ -114,19 +119,19 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts +++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts @@ -11,6 +11,8 @@ import { refineServiceDecorator } from ' import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; - + export const serverOptions: OptionDescriptions = { + /* ----- code-server ----- */ + 'disable-update-check': { type: 'boolean' }, - + /* ----- server setup ----- */ - -@@ -84,6 +86,8 @@ export const serverOptions: OptionDescri + +@@ -88,6 +90,8 @@ export const serverOptions: OptionDescri }; - + export interface ServerParsedArgs { + /* ----- code-server ----- */ + 'disable-update-check'?: boolean; - + /* ----- server setup ----- */ - + diff --git a/patches/webview.diff b/patches/webview.diff index a4506b03b..c04847e1b 100644 --- a/patches/webview.diff +++ b/patches/webview.diff @@ -15,13 +15,16 @@ Since this code exists only for the authentication case we can just skip it when it is served from the current host as authentication is not a problem if the request is not cross-origin. +There is also an origin check we bypass (this seems to be related to how the +webview host is separate by default but we serve on the same host). + To test, open a few types of webviews (images, markdown, extension details, etc). Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts +++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts -@@ -176,7 +176,7 @@ export class BrowserWorkbenchEnvironment +@@ -179,7 +179,7 @@ export class BrowserWorkbenchEnvironment @memoize get webviewExternalEndpoint(): string { @@ -34,7 +37,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts +++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts -@@ -280,6 +280,7 @@ export class WebClientServer { +@@ -283,6 +283,7 @@ export class WebClientServer { const data = (await util.promisify(fs.readFile)(filePath)).toString() .replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({ remoteAuthority, @@ -46,7 +49,7 @@ Index: code-server/lib/vscode/src/vs/workbench/common/webview.ts =================================================================== --- code-server.orig/lib/vscode/src/vs/workbench/common/webview.ts +++ code-server/lib/vscode/src/vs/workbench/common/webview.ts -@@ -24,7 +24,7 @@ export const webviewResourceBaseHost = ' +@@ -22,7 +22,7 @@ export const webviewResourceBaseHost = ' export const webviewRootResourceAuthority = `vscode-resource.${webviewResourceBaseHost}`; @@ -74,3 +77,20 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/servi switch (event.request.method) { case 'GET': case 'HEAD': +Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js +=================================================================== +--- code-server.orig/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js ++++ code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/main.js +@@ -318,6 +318,12 @@ const hostMessaging = new class HostMess + + const hostname = location.hostname; + ++ // It is safe to run if we are on the same host. ++ const parent = new URL(parentOrigin) ++ if (parent.hostname === location.hostname) { ++ return start(parentOrigin) ++ } ++ + if (!crypto.subtle) { + // cannot validate, not running in a secure context + throw new Error(`Cannot validate in current context!`); diff --git a/src/node/socket.ts b/src/node/socket.ts index 1651046d0..a56d9566e 100644 --- a/src/node/socket.ts +++ b/src/node/socket.ts @@ -77,7 +77,7 @@ export class SocketProxyProvider { this.proxyPipe = pipe return Promise.all([ fs.mkdir(path.dirname(this.proxyPipe), { recursive: true }), - fs.rmdir(this.proxyPipe, { recursive: true }), + fs.rm(this.proxyPipe, { force: true, recursive: true }), ]) }) .then(() => { diff --git a/test/e2e/models/CodeServer.ts b/test/e2e/models/CodeServer.ts index 53e2208d2..8b3c4a4af 100644 --- a/test/e2e/models/CodeServer.ts +++ b/test/e2e/models/CodeServer.ts @@ -81,6 +81,9 @@ export class CodeServer { path.join(dir, "User/settings.json"), JSON.stringify({ "workbench.startupEditor": "none", + // NOTE@jsjoeio - needed to prevent Trust Policy prompt + // in end-to-end tests. + "security.workspace.trust.enabled": false, }), "utf8", ) diff --git a/test/unit/node/cli.test.ts b/test/unit/node/cli.test.ts index 76ebb610f..51e707001 100644 --- a/test/unit/node/cli.test.ts +++ b/test/unit/node/cli.test.ts @@ -458,7 +458,7 @@ describe("cli", () => { beforeEach(async () => { delete process.env.VSCODE_IPC_HOOK_CLI - await fs.rmdir(vscodeIpcPath, { recursive: true }) + await fs.rm(vscodeIpcPath, { force: true, recursive: true }) }) it("should use existing if inside code-server", async () => { diff --git a/test/unit/node/socket.test.ts b/test/unit/node/socket.test.ts index b79696572..167691f7b 100644 --- a/test/unit/node/socket.test.ts +++ b/test/unit/node/socket.test.ts @@ -53,7 +53,7 @@ describe("SocketProxyProvider", () => { await fs.mkdir(path.join(tmpdir, "tests"), { recursive: true }) const socketPath = await provider.findFreeSocketPath(path.join(tmpdir, "tests/tls-socket-proxy")) - await fs.rmdir(socketPath, { recursive: true }) + await fs.rm(socketPath, { force: true, recursive: true }) return new Promise((_resolve) => { const resolved: { [key: string]: boolean } = { client: false, server: false } diff --git a/test/utils/helpers.ts b/test/utils/helpers.ts index be8f3a90d..3f9399d4b 100644 --- a/test/utils/helpers.ts +++ b/test/utils/helpers.ts @@ -29,7 +29,7 @@ export function mockLogger() { */ export async function clean(testName: string): Promise { const dir = path.join(os.tmpdir(), `code-server/tests/${testName}`) - await fs.rmdir(dir, { recursive: true }) + await fs.rm(dir, { force: true, recursive: true }) } /**