mirror of
https://github.com/coder/code-server.git
synced 2026-11-02 22:09:11 +01:00
Compare commits
12 Commits
87cac20790
...
v4.143.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22ddf60dbc | ||
|
|
e777c1f963 | ||
|
|
279b5702aa | ||
|
|
27baccf843 | ||
|
|
8aab1b0d72 | ||
|
|
777c493a9b | ||
|
|
f07405cba3 | ||
|
|
c5fee2d2f9 | ||
|
|
83670e50c6 | ||
|
|
41cf6f7eaf | ||
|
|
78aad47ce6 | ||
|
|
8b41915d25 |
9
.github/workflows/release.yaml
vendored
9
.github/workflows/release.yaml
vendored
@@ -79,6 +79,9 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
with:
|
||||
submodules: true
|
||||
# When an update/ branch is merged, a release is automatically created
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
with:
|
||||
@@ -173,6 +176,9 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
with:
|
||||
submodules: true
|
||||
# When an update/ branch is merged, a release is automatically created
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
with:
|
||||
@@ -233,6 +239,9 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
with:
|
||||
submodules: true
|
||||
# When an update/ branch is merged, a release is automatically created
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
|
||||
# quilt has no windows build. The patches are ordinary -p1 diffs
|
||||
# against the repository root, so git applies them in series order.
|
||||
|
||||
@@ -1 +1 @@
|
||||
24.21.0
|
||||
24.22.1
|
||||
|
||||
47
CHANGELOG.md
47
CHANGELOG.md
@@ -22,6 +22,53 @@ Code v99.99.999
|
||||
|
||||
## Unreleased
|
||||
|
||||
Code v1.143.1
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to Code 1.143.1
|
||||
|
||||
## [4.141.1](https://github.com/coder/code-server/releases/tag/v4.141.1) - 2026-10-23
|
||||
|
||||
### Security
|
||||
|
||||
- Update bundled Node.js to 24.22.1 to fix a remote code execution bug in the
|
||||
Brotli decoder (CVE-2026-111497).
|
||||
- Reject compressed request bodies (`Content-Encoding: br`, `gzip`, or
|
||||
`deflate`) instead of decompressing them.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Boolean flags in the `--flag=false` form and in the config file now respect
|
||||
being set to false.
|
||||
|
||||
### Added
|
||||
|
||||
- Turkish locale.
|
||||
|
||||
### Changed
|
||||
|
||||
- Expand values from path options in the config file that start with a tilde.
|
||||
|
||||
## [4.141.0](https://github.com/coder/code-server/releases/tag/v4.141.0) - 2026-10-08
|
||||
|
||||
Code v1.141.0
|
||||
|
||||
### Added
|
||||
|
||||
- A new `--enable-remote-storage` flag can be used to make code-server persist
|
||||
workbench storage on the remote server instead of browser storage. Use this if
|
||||
you want to share storage between multiple devices.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The Typescript extension was trying to load as a browser extension even though
|
||||
we build the remote server version, causing it to fail to activate.
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to Code 1.141.0
|
||||
|
||||
## [4.140.0](https://github.com/coder/code-server/releases/tag/v4.140.0) - 2026-10-02
|
||||
|
||||
Code v1.140.0
|
||||
|
||||
@@ -58,10 +58,17 @@ main() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add the date, our name, links, enable telemetry (this just makes telemetry
|
||||
# available; telemetry can still be disabled by flag or setting), and
|
||||
# configure trusted extensions (since some, like github.copilot-chat, never
|
||||
# ask to be trusted and this is the only way to get auth working).
|
||||
# Modify the product.json:
|
||||
# - Add the date
|
||||
# - Set the code-server name.
|
||||
# - Add our links
|
||||
# - Enable telemetry (this just makes telemetry available; telemetry can still
|
||||
# be disabled by flag or setting)
|
||||
# - Configure trusted extensions (since some, like github.copilot-chat, never
|
||||
# ask to be trusted and this is the only way to get auth working).
|
||||
# - Make Typescript server plugins run in the workspace. We build the remote
|
||||
# server version, so there is no browser distribution, and this key is not
|
||||
# added automatically.
|
||||
#
|
||||
# This needs to be done before building as Code will read this file and embed
|
||||
# it into the client-side code.
|
||||
@@ -103,6 +110,9 @@ main() {
|
||||
],
|
||||
"aiConfig": {
|
||||
"ariaKey": "code-server"
|
||||
},
|
||||
"extensionPointExtensionKind": {
|
||||
"typescriptServerPlugins": ["workspace"]
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@@ -15,9 +15,9 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 3.55.0
|
||||
version: 3.56.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
appVersion: 4.140.0
|
||||
appVersion: 4.141.1
|
||||
|
||||
@@ -6,7 +6,7 @@ replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: codercom/code-server
|
||||
tag: '4.140.0'
|
||||
tag: '4.141.1'
|
||||
pullPolicy: Always
|
||||
|
||||
# Specifies one or more secrets to be used when pulling images from a
|
||||
|
||||
Submodule lib/vscode updated: 07f806f999...e646868227
12
package-lock.json
generated
12
package-lock.json
generated
@@ -1055,9 +1055,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "5.0.9",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
|
||||
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
|
||||
"version": "5.0.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
|
||||
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1779,9 +1779,9 @@
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
|
||||
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
|
||||
"version": "1.1.21",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
|
||||
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -48,8 +48,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
|
||||
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
|
||||
<style id="vscode-css-modules" type="text/css" media="screen"></style>
|
||||
|
||||
</head>
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script nonce="{{WORKBENCH_SCRIPT_NONCE}}">
|
||||
@@ -85,8 +85,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
|
||||
|
||||
</head>
|
||||
@@ -37,7 +37,7 @@
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script nonce="{{WORKBENCH_SCRIPT_NONCE}}">
|
||||
@@ -281,8 +281,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
-
|
||||
(function () {
|
||||
|
||||
// Find config by checking for DOM
|
||||
@@ -610,8 +600,8 @@ function readCookie(name: string): strin
|
||||
// This script running at all means the page scripts were not blocked or rewritten.
|
||||
@@ -614,8 +604,8 @@ function readCookie(name: string): strin
|
||||
if (!configElement || !configElementAttribute) {
|
||||
throw new Error('Missing web configuration element');
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ Index: code-server/lib/vscode/build/gulpfile.extensions.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/build/gulpfile.extensions.ts
|
||||
+++ code-server/lib/vscode/build/gulpfile.extensions.ts
|
||||
@@ -291,6 +291,29 @@ export const compileCopilotExtensionBuil
|
||||
@@ -294,6 +294,29 @@ export const compileCopilotExtensionBuil
|
||||
task.task(compileCopilotExtensionBuildTask);
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,8 +6,8 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
- content="default-src 'none'; script-src 'sha256-FFQoOVVa2tOE3uqUvirwaMNT20TZmrHcL2aaOjJ8BUo=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
|
||||
+ content="default-src 'none'; script-src 'sha256-24QqbpzqcqSyIGvg/ZwFRy5pPlhmVBa8CkUREEIUnBw=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
|
||||
- content="default-src 'none'; script-src 'sha256-7cKy9iQfWRXcgRS74x6I4q5cRDkv8nQz51jecqMmQ5w=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
|
||||
+ content="default-src 'none'; script-src 'sha256-FYdHnaDkSHwSK3TmWDrs/tT+X4bK+aaoa9yy432BONk=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
|
||||
|
||||
<!-- Disable pinch zooming -->
|
||||
<meta name="viewport"
|
||||
|
||||
@@ -7,7 +7,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
===================================================================
|
||||
--- 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
|
||||
@@ -343,6 +343,10 @@ export class Extension implements IExten
|
||||
@@ -344,6 +344,10 @@ export class Extension implements IExten
|
||||
if (this.type === ExtensionType.System && this.productService.quality === 'stable' && !this.productService.builtInExtensionsEnabledWithAutoUpdates?.some(id => id.toLowerCase() === this.identifier.id.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
import { ProtocolConstants } from '../../base/parts/ipc/common/ipc.net.js';
|
||||
import { createRandomIPCHandle } from '../../base/parts/ipc/node/ipc.net.js';
|
||||
import { IConfigurationService } from '../../platform/configuration/common/configuration.js';
|
||||
@@ -418,6 +418,9 @@ export async function setupServerService
|
||||
@@ -444,6 +444,9 @@ export async function setupServerService
|
||||
|
||||
socketServer.registerChannel('mcpManagement', new McpManagementChannel(mcpManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority)));
|
||||
|
||||
@@ -272,7 +272,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
|
||||
@@ -475,9 +475,6 @@ export class InstallAction extends Exten
|
||||
@@ -479,9 +479,6 @@ export class InstallAction extends Exten
|
||||
if (this.extension.isBuiltin) {
|
||||
return;
|
||||
}
|
||||
@@ -282,7 +282,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
if (this.extension.state !== ExtensionState.Uninstalled) {
|
||||
return;
|
||||
}
|
||||
@@ -782,7 +779,7 @@ export abstract class InstallInOtherServ
|
||||
@@ -786,7 +783,7 @@ export abstract class InstallInOtherServ
|
||||
}
|
||||
|
||||
if (isLanguagePackExtension(this.extension.local.manifest)) {
|
||||
@@ -291,7 +291,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
}
|
||||
|
||||
// Prefers to run on UI
|
||||
@@ -2281,17 +2278,6 @@ export class SetLanguageAction extends E
|
||||
@@ -2285,17 +2282,6 @@ export class SetLanguageAction extends E
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = SetLanguageAction.DisabledClass;
|
||||
@@ -309,7 +309,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
}
|
||||
|
||||
override async run(): Promise<any> {
|
||||
@@ -2308,7 +2294,6 @@ export class ClearLanguageAction extends
|
||||
@@ -2312,7 +2298,6 @@ export class ClearLanguageAction extends
|
||||
private static readonly DisabledClass = `${this.EnabledClass} disabled`;
|
||||
|
||||
constructor(
|
||||
@@ -317,7 +317,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
@ILocaleService private readonly localeService: ILocaleService,
|
||||
) {
|
||||
super(ClearLanguageAction.ID, ClearLanguageAction.TITLE.value, ClearLanguageAction.DisabledClass, false);
|
||||
@@ -2318,17 +2303,6 @@ export class ClearLanguageAction extends
|
||||
@@ -2322,17 +2307,6 @@ export class ClearLanguageAction extends
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = ClearLanguageAction.DisabledClass;
|
||||
|
||||
@@ -282,7 +282,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/views/explo
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts
|
||||
@@ -65,6 +65,7 @@ import { timeout } from '../../../../../
|
||||
@@ -62,6 +62,7 @@ import { defaultCountBadgeStyles } from
|
||||
import { IFilesConfigurationService } from '../../../../services/filesConfiguration/common/filesConfigurationService.js';
|
||||
import { mainWindow } from '../../../../../base/browser/window.js';
|
||||
import { IExplorerFileContribution, explorerFileContribRegistry } from '../explorerFileContrib.js';
|
||||
@@ -290,7 +290,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/views/explo
|
||||
import { WorkbenchCompressibleAsyncDataTree } from '../../../../../platform/list/browser/listService.js';
|
||||
import { ISearchService, QueryType, getExcludes, ISearchConfiguration, ISearchComplete, IFileQuery } from '../../../../services/search/common/search.js';
|
||||
import { CancellationToken } from '../../../../../base/common/cancellation.js';
|
||||
@@ -1587,7 +1588,8 @@ export class FileDragAndDrop implements
|
||||
@@ -1515,7 +1516,8 @@ export class FileDragAndDrop implements
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
|
||||
@@ -300,7 +300,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/views/explo
|
||||
) {
|
||||
const updateDropEnablement = (e: IConfigurationChangeEvent | undefined) => {
|
||||
if (!e || e.affectsConfiguration('explorer.enableDragAndDrop')) {
|
||||
@@ -1812,15 +1814,17 @@ export class FileDragAndDrop implements
|
||||
@@ -1740,15 +1742,17 @@ export class FileDragAndDrop implements
|
||||
|
||||
// External file DND (Import/Upload file)
|
||||
if (data instanceof NativeDragAndDropData) {
|
||||
|
||||
@@ -115,7 +115,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/bro
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css
|
||||
@@ -60,6 +60,15 @@
|
||||
@@ -63,6 +63,15 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ Index: code-server/lib/vscode/src/vs/server/node/server.main.ts
|
||||
-delete process.env[agentHostBridgeConnectionTokenEnvironmentVariable];
|
||||
-
|
||||
-const REMOTE_DATA_FOLDER = args['server-data-dir'] || process.env['VSCODE_AGENT_FOLDER'] || join(os.homedir(), product.serverDataFolderName || '.vscode-remote');
|
||||
-const USER_DATA_PATH = join(REMOTE_DATA_FOLDER, 'data');
|
||||
-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');
|
||||
@@ -225,7 +225,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
|
||||
+ <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||
<style id="vscode-css-modules" type="text/css" media="screen"></style>
|
||||
|
||||
</head>
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
@@ -251,7 +251,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
+ <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
|
||||
|
||||
</head>
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
|
||||
@@ -110,7 +110,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
import type { IURLCallbackProvider } from '../../../workbench/services/url/browser/urlService.js';
|
||||
import { create } from '../../../workbench/workbench.web.main.internal.js';
|
||||
|
||||
@@ -612,6 +613,44 @@ class WorkspaceProvider implements IWork
|
||||
@@ -616,6 +617,44 @@ class WorkspaceProvider implements IWork
|
||||
settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined,
|
||||
workspaceProvider: WorkspaceProvider.create(config),
|
||||
urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute),
|
||||
@@ -159,7 +159,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExpl
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
|
||||
@@ -99,8 +99,8 @@ export class ForwardedPortsView extends
|
||||
@@ -100,8 +100,8 @@ export class ForwardedPortsView extends
|
||||
private async enableForwardedPortsFeatures() {
|
||||
this.contextKeyListener.clear();
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
+++ code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
@@ -139,8 +139,13 @@ export class BaseSecretStorageService ex
|
||||
@@ -144,8 +144,13 @@ export class BaseSecretStorageService ex
|
||||
return await readEncryptedSecret(
|
||||
key,
|
||||
(fullKey) => this.getValueFromStorage(key, fullKey, storageService),
|
||||
(fullKey) => this.getValueFromStorage(key, fullKey, storageService),
|
||||
- // If the storage service is in-memory, we don't need to decrypt
|
||||
- this._type === 'in-memory' ? (v) => Promise.resolve(v) : (v) => this._encryptionService.decrypt(v),
|
||||
+ // Don't decrypt if storage is in-memory or if encryption service is not available
|
||||
@@ -19,10 +19,10 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
this._logService,
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -160,8 +165,13 @@ export class BaseSecretStorageService ex
|
||||
@@ -168,8 +173,13 @@ export class BaseSecretStorageService ex
|
||||
key,
|
||||
value,
|
||||
(fullKey, encrypted) => this.setValueInStorage(key, fullKey, encrypted, storageService),
|
||||
(fullKey, encrypted) => this.setValueInStorage(key, fullKey, encrypted, storageService),
|
||||
- // If the storage service is in-memory, we don't need to encrypt
|
||||
- this._type === 'in-memory' ? (v) => Promise.resolve(v) : (v) => this._encryptionService.encrypt(v),
|
||||
+ // Don't encrypt if storage is in-memory or if encryption service is not available
|
||||
@@ -35,7 +35,7 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
this._logService,
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -194,8 +204,9 @@ export class BaseSecretStorageService ex
|
||||
@@ -224,8 +234,9 @@ export class BaseSecretStorageService ex
|
||||
|
||||
private async initialize(): Promise<IStorageService> {
|
||||
let storageService;
|
||||
@@ -47,7 +47,7 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
this._type = 'persisted';
|
||||
storageService = this._storageService;
|
||||
} else {
|
||||
@@ -203,7 +214,7 @@ export class BaseSecretStorageService ex
|
||||
@@ -233,7 +244,7 @@ export class BaseSecretStorageService ex
|
||||
if (this._type === 'in-memory') {
|
||||
return this._storageService;
|
||||
}
|
||||
@@ -77,10 +77,14 @@ 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
|
||||
@@ -625,2 +625,2 @@
|
||||
@@ -655,8 +655,8 @@ class WorkspaceProvider implements IWork
|
||||
})
|
||||
}
|
||||
},
|
||||
- secretStorageProvider: config.remoteAuthority && !secretStorageKeyPath
|
||||
- ? undefined /* with a remote without embedder-preferred storage, store on the remote */
|
||||
+ secretStorageProvider: config.remoteStorageEnabled || (config.remoteAuthority && !secretStorageKeyPath)
|
||||
+ ? undefined /* with remote storage enabled, or without embedder-prefered storage, store on the remote */
|
||||
: new LocalStorageSecretStorageProvider(secretStorageCrypto),
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
Reuse VS Code's Electron storage service for remote persistence
|
||||
|
||||
Index: code-server/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
|
||||
+++ code-server/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
|
||||
@@ -14 +14,6 @@
|
||||
@@ -11,7 +11,12 @@ import { IStorage } from '../../../base/
|
||||
import { INativeEnvironmentService } from '../../environment/common/environment.js';
|
||||
import { IFileService } from '../../files/common/files.js';
|
||||
import { createDecorator } from '../../instantiation/common/instantiation.js';
|
||||
-import { ILifecycleMainService, LifecycleMainPhase, ShutdownReason } from '../../lifecycle/electron-main/lifecycleMainService.js';
|
||||
+import type { ILifecycleMainService, ShutdownReason } from '../../lifecycle/electron-main/lifecycleMainService.js';
|
||||
+
|
||||
@@ -10,44 +15,110 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
+// that module imports Electron, which is not present in the code-server server image.
|
||||
+const LIFECYCLE_MAIN_PHASE_AFTER_WINDOW_OPEN = 3;
|
||||
+const SHUTDOWN_REASON_KILL = 2;
|
||||
@@ -101 +101 @@
|
||||
import { ILogService } from '../../log/common/log.js';
|
||||
import { AbstractStorageService, isProfileUsingDefaultStorage, IStorageService, StorageScope, StorageTarget } from '../common/storage.js';
|
||||
import { ApplicationStorageMain, ApplicationSharedStorageMain, ProfileStorageMain, InMemoryStorageMain, IStorageMain, IStorageMainOptions, WorkspaceStorageMain, IStorageChangeEvent } from './storageMain.js';
|
||||
@@ -92,7 +97,7 @@ export class StorageMainService extends
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@IUserDataProfilesMainService private readonly userDataProfilesService: IUserDataProfilesMainService,
|
||||
- @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
+ private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@@ -117 +117 @@
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
|
||||
) {
|
||||
@@ -114,7 +119,7 @@ export class StorageMainService extends
|
||||
|
||||
// Application Storage: Warmup when any window opens
|
||||
(async () => {
|
||||
- await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen);
|
||||
+ await this.lifecycleMainService.when(LIFECYCLE_MAIN_PHASE_AFTER_WINDOW_OPEN);
|
||||
@@ -256 +256 @@
|
||||
|
||||
this.applicationStorage.init();
|
||||
this.applicationSharedStorage.init();
|
||||
@@ -253,7 +258,7 @@ export class StorageMainService extends
|
||||
}
|
||||
|
||||
private createProfileStorage(profile: IUserDataProfile): IStorageMain {
|
||||
- if (this.shutdownReason === ShutdownReason.KILL) {
|
||||
+ if (this.shutdownReason === SHUTDOWN_REASON_KILL) {
|
||||
@@ -295 +295 @@
|
||||
|
||||
// Workaround for native crashes that we see when
|
||||
// SQLite DBs are being created even after shutdown
|
||||
@@ -292,7 +297,7 @@ export class StorageMainService extends
|
||||
}
|
||||
|
||||
private createWorkspaceStorage(workspace: IAnyWorkspaceIdentifier): IStorageMain {
|
||||
- if (this.shutdownReason === ShutdownReason.KILL) {
|
||||
+ if (this.shutdownReason === SHUTDOWN_REASON_KILL) {
|
||||
|
||||
|
||||
// Workaround for native crashes that we see when
|
||||
// SQLite DBs are being created even after shutdown
|
||||
Index: code-server/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
|
||||
@@ -6 +6 @@
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
-import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';
|
||||
+import { IRemoteService } from '../../../../platform/ipc/common/services.js';
|
||||
@@ -22 +22 @@
|
||||
import { IStorage, Storage, MigratingStorage } from '../../../../base/parts/storage/common/storage.js';
|
||||
import { RemoteStorageService } from '../../../../platform/storage/common/storageService.js';
|
||||
import { FallbackApplicationStorageDatabaseClient, ApplicationSharedStorageDatabaseClient } from '../../../../platform/storage/common/storageIpc.js';
|
||||
@@ -19,10 +19,10 @@ export class NativeWorkbenchStorageServi
|
||||
workspace: IAnyWorkspaceIdentifier | undefined,
|
||||
private readonly userDataProfileService: IUserDataProfileService,
|
||||
userDataProfilesService: IUserDataProfilesService,
|
||||
- mainProcessService: IMainProcessService,
|
||||
+ remoteService: Pick<IRemoteService, 'getChannel'>,
|
||||
@@ -25 +25 @@
|
||||
private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
) {
|
||||
- super(workspace, { currentProfile: userDataProfileService.currentProfile, defaultProfile: userDataProfilesService.defaultProfile }, mainProcessService, workbenchEnvironmentService);
|
||||
+ super(workspace, { currentProfile: userDataProfileService.currentProfile, defaultProfile: userDataProfilesService.defaultProfile }, remoteService as IRemoteService, workbenchEnvironmentService);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
|
||||
@@ -68,0 +69 @@
|
||||
@@ -66,6 +66,7 @@ export const serverOptions: OptionDescri
|
||||
'disable-experiments': OPTIONS['disable-experiments'],
|
||||
'disable-workspace-trust': OPTIONS['disable-workspace-trust'],
|
||||
'file-watcher-polling': { type: 'string', deprecates: ['fileWatcherPolling'] },
|
||||
+ 'enable-remote-storage': { type: 'boolean', cat: 'o', description: nls.localize('enable-remote-storage', 'Persist browser storage (settings, state, etc.) on the server instead of browser IndexedDB. Enables state portability across browsers/devices.') },
|
||||
@@ -214,0 +216 @@
|
||||
'log': OPTIONS['log'],
|
||||
'logsPath': OPTIONS['logsPath'],
|
||||
'force-disable-user-env': OPTIONS['force-disable-user-env'],
|
||||
@@ -212,6 +213,7 @@ export interface ServerParsedArgs {
|
||||
'logsPath'?: string;
|
||||
|
||||
'force-disable-user-env'?: boolean;
|
||||
+ 'enable-remote-storage'?: boolean;
|
||||
'enable-proposed-api'?: string[];
|
||||
|
||||
/* ----- vs code web options ----- */
|
||||
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
|
||||
@@ -107,0 +108,4 @@
|
||||
@@ -106,6 +106,10 @@ import { McpManagementChannel } from '..
|
||||
import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js';
|
||||
import { IMcpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifest.js';
|
||||
import { McpGalleryManifestIPCService } from '../../platform/mcp/common/mcpGalleryManifestServiceIpc.js';
|
||||
+import { StorageDatabaseChannel } from '../../platform/storage/electron-main/storageIpc.js';
|
||||
+import { StorageMainService } from '../../platform/storage/electron-main/storageMainService.js';
|
||||
+import type { ILifecycleMainService } from '../../platform/lifecycle/electron-main/lifecycleMainService.js';
|
||||
+import type { IUserDataProfilesMainService } from '../../platform/userDataProfile/electron-main/userDataProfile.js';
|
||||
@@ -240,0 +245,15 @@
|
||||
import { SANDBOX_HELPER_CHANNEL_NAME, SandboxHelperChannel } from '../../platform/sandbox/common/sandboxHelperIpc.js';
|
||||
import { SandboxHelperService } from '../../platform/sandbox/node/sandboxHelper.js';
|
||||
|
||||
@@ -244,6 +248,21 @@ export async function setupServerService
|
||||
services.set(IMcpGatewayService, new SyncDescriptor(McpGatewayService));
|
||||
|
||||
const instantiationService: IInstantiationService = new InstantiationService(services);
|
||||
+ // Reuse the Electron storage service on the remote. The server has no
|
||||
+ // windows, so its lifecycle is always ready and never loads a window.
|
||||
+ const storageMainService = disposables.add(new StorageMainService(
|
||||
@@ -63,7 +134,10 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
+ uriIdentityService,
|
||||
+ ));
|
||||
+
|
||||
@@ -419,6 +439,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
|
||||
services.set(ILanguagePackService, instantiationService.createInstance(NativeLanguagePackService));
|
||||
|
||||
const ptyHostStarter = instantiationService.createInstance(
|
||||
@@ -446,6 +465,7 @@ export async function setupServerService
|
||||
|
||||
const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService), disposables);
|
||||
socketServer.registerChannel('languagePacks', languagePackChannel);
|
||||
@@ -71,28 +145,61 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
|
||||
// clean up extensions folder
|
||||
remoteExtensionsScanner.whenExtensionsReady().then(() => extensionManagementService.cleanUp());
|
||||
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
|
||||
@@ -411 +411,2 @@
|
||||
@@ -451,7 +451,8 @@ export class WebClientServer {
|
||||
folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']),
|
||||
workspaceUri: resolveWorkspaceURI(this._environmentService.args['default-workspace']),
|
||||
productConfiguration,
|
||||
- callbackRoute: callbackRoute
|
||||
+ callbackRoute: callbackRoute,
|
||||
+ remoteStorageEnabled: this._environmentService.args['enable-remote-storage'] ? true : undefined
|
||||
};
|
||||
|
||||
const cookies = cookie.parse(req.headers.cookie || '');
|
||||
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
|
||||
@@ -413,0 +414,5 @@
|
||||
@@ -411,6 +411,11 @@ export interface IWorkbenchConstructionO
|
||||
readonly authenticationProviders?: readonly IAuthenticationProvider[];
|
||||
|
||||
//#endregion
|
||||
+ /**
|
||||
+ * Persist workbench storage on the remote server instead of browser IndexedDB.
|
||||
+ */
|
||||
+ readonly remoteStorageEnabled?: boolean;
|
||||
+
|
||||
|
||||
//#region Development options
|
||||
|
||||
Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
@@ -35,0 +36 @@
|
||||
@@ -33,6 +33,7 @@ import { ISignService } from '../../plat
|
||||
import { SignService } from '../../platform/sign/browser/signService.js';
|
||||
import { IWorkbenchConstructionOptions, IWorkbench, IWorkspace, ITunnel } from './web.api.js';
|
||||
import { BrowserStorageService } from '../services/storage/browser/storageService.js';
|
||||
+import { NativeWorkbenchStorageService } from '../services/storage/electron-browser/storageService.js';
|
||||
@@ -479 +480 @@
|
||||
import { IStorageService } from '../../platform/storage/common/storage.js';
|
||||
import { toLocalISOString } from '../../base/common/date.js';
|
||||
import { isWorkspaceToOpen, isFolderToOpen } from '../../platform/window/common/window.js';
|
||||
@@ -482,7 +483,7 @@ export class BrowserMain extends Disposa
|
||||
serviceCollection.set(IWorkbenchConfigurationService, service);
|
||||
return service;
|
||||
}),
|
||||
- this.createStorageService(workspace, logService, userDataProfileService).then(service => {
|
||||
+ this.createStorageService(workspace, environmentService, logService, userDataProfileService, userDataProfilesService, remoteAgentService).then(service => {
|
||||
@@ -601 +602,15 @@
|
||||
serviceCollection.set(IStorageService, service);
|
||||
return service;
|
||||
})
|
||||
@@ -604,7 +605,21 @@ export class BrowserMain extends Disposa
|
||||
}));
|
||||
}
|
||||
|
||||
- protected async createStorageService(workspace: IAnyWorkspaceIdentifier, logService: ILogService, userDataProfileService: IUserDataProfileService): Promise<IStorageService> {
|
||||
+ protected async createStorageService(workspace: IAnyWorkspaceIdentifier, environmentService: IBrowserWorkbenchEnvironmentService, logService: ILogService, userDataProfileService: IUserDataProfileService, userDataProfilesService: IUserDataProfilesService, remoteAgentService: IRemoteAgentService): Promise<IStorageService> {
|
||||
+ const connection = remoteAgentService.getConnection();
|
||||
@@ -109,14 +216,31 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
const storageService = new BrowserStorageService(workspace, userDataProfileService, logService);
|
||||
|
||||
try {
|
||||
Index: code-server/lib/vscode/src/vs/sessions/browser/web.main.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/sessions/browser/web.main.ts
|
||||
+++ code-server/lib/vscode/src/vs/sessions/browser/web.main.ts
|
||||
@@ -42 +42 @@
|
||||
@@ -39,9 +39,9 @@ export class SessionsBrowserMain extends
|
||||
_workspace: IAnyWorkspaceIdentifier,
|
||||
environmentService: IBrowserWorkbenchEnvironmentService,
|
||||
userDataProfileService: IUserDataProfileService,
|
||||
- _userDataProfilesService: BrowserUserDataProfilesService,
|
||||
+ userDataProfilesService: BrowserUserDataProfilesService,
|
||||
@@ -44 +44 @@
|
||||
fileService: FileService,
|
||||
- _remoteAgentService: IRemoteAgentService,
|
||||
+ remoteAgentService: IRemoteAgentService,
|
||||
@@ -85 +85 @@
|
||||
uriIdentityService: IUriIdentityService,
|
||||
policyService: IPolicyService,
|
||||
logService: ILogService,
|
||||
@@ -82,7 +82,7 @@ export class SessionsBrowserMain extends
|
||||
serviceCollection.set(IWorkbenchConfigurationService, configurationService);
|
||||
|
||||
// Storage
|
||||
- const storageService = await this.createStorageService(workspaceIdentifier, logService, userDataProfileService);
|
||||
+ const storageService = await this.createStorageService(workspaceIdentifier, environmentService, logService, userDataProfileService, userDataProfilesService, remoteAgentService);
|
||||
serviceCollection.set(IStorageService, storageService);
|
||||
|
||||
// Workspace Trust Service
|
||||
|
||||
@@ -24,6 +24,6 @@ trusted-domains.diff
|
||||
signature-verification.diff
|
||||
copilot.diff
|
||||
app-name.diff
|
||||
csp-hashes.diff
|
||||
remote-storage.diff
|
||||
remote-secret-storage.diff
|
||||
csp-hashes.diff
|
||||
|
||||
@@ -20,7 +20,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
import { NullPolicyService } from '../../platform/policy/common/policy.js';
|
||||
import { OneDataSystemAppender } from '../../platform/telemetry/node/1dsAppender.js';
|
||||
import { LoggerService } from '../../platform/log/node/loggerService.js';
|
||||
@@ -179,11 +180,23 @@ export async function setupServerService
|
||||
@@ -184,11 +185,23 @@ export async function setupServerService
|
||||
const requestService = new RequestService('remote', configurationService, environmentService, logService);
|
||||
services.set(IRequestService, requestService);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/storage/browser/storageS
|
||||
|
||||
export class BrowserStorageService extends AbstractStorageService {
|
||||
|
||||
@@ -354,7 +355,11 @@ export class IndexedDBStorageDatabase ex
|
||||
@@ -365,7 +366,11 @@ export class IndexedDBStorageDatabase ex
|
||||
}
|
||||
|
||||
static async createWorkspaceStorage(workspaceId: string, logService: ILogService): Promise<IIndexedDBStorageDatabase> {
|
||||
|
||||
@@ -53,7 +53,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index.html
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index.html
|
||||
@@ -253,7 +253,7 @@
|
||||
@@ -266,7 +266,7 @@
|
||||
}
|
||||
|
||||
const swPath = encodeURI(`service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}&platform=${searchParams.get('platform')}`);
|
||||
@@ -62,7 +62,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index
|
||||
.then(async registration => {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// A previous SW is already controlling. Force an update
|
||||
@@ -332,6 +332,12 @@
|
||||
@@ -345,6 +345,12 @@
|
||||
|
||||
const hostname = location.hostname;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as crypto from "crypto"
|
||||
import { promises as fs } from "fs"
|
||||
import { load } from "js-yaml"
|
||||
import * as path from "path"
|
||||
import { generateCertificate, generatePassword, paths, splitOnFirstEquals } from "./util"
|
||||
import { expandTilde, generateCertificate, generatePassword, paths, splitOnFirstEquals } from "./util"
|
||||
import { EditorSessionManagerClient } from "./vscodeSocket"
|
||||
|
||||
export enum Feature {
|
||||
@@ -436,7 +436,11 @@ export const parse = (
|
||||
|
||||
const option = options[key]
|
||||
if (option.type === "boolean") {
|
||||
;(args[key] as boolean) = true
|
||||
// Booleans set to false (for example `--flag=false`, which is also how
|
||||
// false values from the config file are passed in) are ignored.
|
||||
if (value !== "false") {
|
||||
;(args[key] as boolean) = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -462,7 +466,7 @@ export const parse = (
|
||||
}
|
||||
|
||||
if (option.path) {
|
||||
value = path.resolve(value)
|
||||
value = path.resolve(expandTilde(value))
|
||||
}
|
||||
|
||||
switch (option.type) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import i18next, { init } from "i18next"
|
||||
import * as en from "./locales/en.json"
|
||||
import * as ja from "./locales/ja.json"
|
||||
import * as th from "./locales/th.json"
|
||||
import * as tr from "./locales/tr.json"
|
||||
import * as ur from "./locales/ur.json"
|
||||
import * as zhCn from "./locales/zh-cn.json"
|
||||
|
||||
@@ -16,6 +17,9 @@ const defaultResources = {
|
||||
th: {
|
||||
translation: th,
|
||||
},
|
||||
tr: {
|
||||
translation: tr,
|
||||
},
|
||||
ja: {
|
||||
translation: ja,
|
||||
},
|
||||
|
||||
13
src/node/i18n/locales/tr.json
Normal file
13
src/node/i18n/locales/tr.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"LOGIN_TITLE": "{{app}} girişi",
|
||||
"LOGIN_BELOW": "Lütfen aşağıdan giriş yapın.",
|
||||
"WELCOME": "{{app}} uygulamasına hoş geldiniz",
|
||||
"LOGIN_PASSWORD": "Parola için yapılandırma dosyasını kontrol edin.",
|
||||
"LOGIN_USING_ENV_PASSWORD": "Parola $PASSWORD ortam değişkeninden ayarlandı.",
|
||||
"LOGIN_USING_HASHED_PASSWORD": "Parola $HASHED_PASSWORD ortam değişkeninden ayarlandı.",
|
||||
"SUBMIT": "GÖNDER",
|
||||
"PASSWORD_PLACEHOLDER": "PAROLA",
|
||||
"LOGIN_RATE_LIMIT": "Giriş denemesi sınırına ulaşıldı!",
|
||||
"MISS_PASSWORD": "Parola eksik",
|
||||
"INCORRECT_PASSWORD": "Parola yanlış."
|
||||
}
|
||||
@@ -132,8 +132,10 @@ export const register = async (
|
||||
})
|
||||
})
|
||||
|
||||
app.router.use(express.json())
|
||||
app.router.use(express.urlencoded({ extended: true }))
|
||||
// Reject compressed request bodies so unauthenticated requests cannot reach
|
||||
// the zlib/Brotli decoders. Browsers never compress request bodies.
|
||||
app.router.use(express.json({ inflate: false }))
|
||||
app.router.use(express.urlencoded({ extended: true, inflate: false }))
|
||||
|
||||
app.router.use(
|
||||
"/_static",
|
||||
|
||||
@@ -511,3 +511,18 @@ export function splitOnFirstEquals(str: string): [string, string | undefined] {
|
||||
const split = str.split(/=(.+)?/, 2)
|
||||
return [split[0], split[1]]
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand a leading `~` to the home directory. The shell does this for
|
||||
* command-line arguments but values from the config file are not expanded.
|
||||
* `~user` forms are left alone.
|
||||
*/
|
||||
export function expandTilde(p: string): string {
|
||||
if (p === "~") {
|
||||
return os.homedir()
|
||||
}
|
||||
if (p.startsWith("~/") || p.startsWith(`~${path.sep}`)) {
|
||||
return path.join(os.homedir(), p.slice(2))
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function makeEditorSessionManagerServer(
|
||||
): Promise<http.Server> {
|
||||
const router = express()
|
||||
|
||||
router.use(express.json())
|
||||
router.use(express.json({ inflate: false }))
|
||||
|
||||
router.get<{}, GetSessionResponse | string | unknown, undefined, { filePath?: string }>(
|
||||
"/session",
|
||||
|
||||
@@ -2,7 +2,8 @@ import * as vscode from "vscode"
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
vscode.window.showInformationMessage("test extension loaded")
|
||||
// Test extension
|
||||
|
||||
// Prints the current proxy URI into a notification.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.proxyUri", () => {
|
||||
if (process.env.VSCODE_PROXY_URI) {
|
||||
@@ -13,7 +14,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}),
|
||||
)
|
||||
|
||||
// asExternalUri extension
|
||||
// Asks for a URI, then runs it through asExternalUri and prints the result
|
||||
// into a notification.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.asExternalUri", async () => {
|
||||
const input = await vscode.window.showInputBox({
|
||||
@@ -28,4 +30,29 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const secretKey = "code-server-test-secret"
|
||||
|
||||
// Asks for a string, then stores it as a secret.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.setSecret", async () => {
|
||||
const input = await vscode.window.showInputBox({
|
||||
prompt: "Secret to store",
|
||||
})
|
||||
|
||||
if (input) {
|
||||
await context.secrets.store(secretKey, input)
|
||||
vscode.window.showInformationMessage(`set secret: ${input}`)
|
||||
} else {
|
||||
vscode.window.showErrorMessage(`Failed to run test case. No input provided.`)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
// Prints the current secret, if any.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.getSecret", async () => {
|
||||
vscode.window.showInformationMessage(`get secret: ${await context.secrets.get(secretKey)}`)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
"command": "codeServerTest.asExternalUri",
|
||||
"title": "asExternalUri test",
|
||||
"category": "code-server"
|
||||
},
|
||||
{
|
||||
"command": "codeServerTest.setSecret",
|
||||
"title": "Set test secret",
|
||||
"category": "code-server"
|
||||
},
|
||||
{
|
||||
"command": "codeServerTest.getSecret",
|
||||
"title": "Get test secret",
|
||||
"category": "code-server"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -363,13 +363,14 @@ export class CodeServerPage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the test extension loaded
|
||||
* Checks if the test extension loaded by waiting for its notification. Once
|
||||
* it appears, dismiss the notification.
|
||||
*/
|
||||
async waitForTestExtensionLoaded(): Promise<void> {
|
||||
const selector = "text=test extension loaded"
|
||||
this.codeServer.logger.debug("Waiting for test extension to load...")
|
||||
|
||||
await this.page.waitForSelector(selector)
|
||||
const locator = this.page.getByRole("dialog", { name: "Info: test extension loaded" })
|
||||
await locator.hover()
|
||||
await locator.getByLabel("Clear Notification (Del)").click()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { clean } from "../utils/helpers"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
|
||||
61
test/e2e/storage.test.ts
Normal file
61
test/e2e/storage.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
const tests = [
|
||||
{
|
||||
name: "browser storage",
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
name: "remote storage",
|
||||
args: ["--enable-remote-storage"],
|
||||
},
|
||||
]
|
||||
|
||||
for (const tc of tests) {
|
||||
const args = ["--disable-workspace-trust", "--extensions-dir", path.join(__dirname, "./extensions"), ...tc.args]
|
||||
describe(tc.name, args, {}, () => {
|
||||
test("should store workbench state and secrets", async ({ codeServerPage }) => {
|
||||
// Create and open a file.
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const file = path.join(dir, "foo")
|
||||
await fs.writeFile(file, "bar")
|
||||
await codeServerPage.openFile(file)
|
||||
|
||||
// Store a secret.
|
||||
const secret = "foo-bar-baz"
|
||||
await codeServerPage.waitForTestExtensionLoaded()
|
||||
await codeServerPage.executeCommandViaMenus("code-server: Set test secret")
|
||||
await codeServerPage.page.waitForSelector(".quick-input-widget:focus-within")
|
||||
await codeServerPage.page.keyboard.type(secret)
|
||||
await codeServerPage.page.keyboard.press("Enter")
|
||||
await expect(codeServerPage.page.getByText(`Info: set secret: ${secret}`)).toBeVisible()
|
||||
|
||||
// There should be a workspace storage directory.
|
||||
const userDir = path.join(dir, "User/workspaceStorage")
|
||||
const dirs = await fs.readdir(userDir)
|
||||
expect(dirs.length).toBe(1)
|
||||
|
||||
const storageFile = path.join(userDir, dirs[0], "state.vscdb")
|
||||
if (tc.args.includes("--enable-remote-storage")) {
|
||||
// The sqlite database should exist.
|
||||
fs.stat(storageFile)
|
||||
} else {
|
||||
// But no sqlite database.
|
||||
expect(() => fs.stat(storageFile)).rejects.toThrow("ENOENT")
|
||||
}
|
||||
|
||||
// Reload using a command so it has a chance to flush storage.
|
||||
await codeServerPage.executeCommandViaMenus("Developer: Reload Window")
|
||||
await codeServerPage.waitForTestExtensionLoaded()
|
||||
|
||||
// Should see the same file.
|
||||
await codeServerPage.waitForTab(file)
|
||||
|
||||
// Should be able to retrieve the secret.
|
||||
await codeServerPage.executeCommandViaMenus("code-server: Get test secret")
|
||||
await expect(codeServerPage.page.getByText(`Info: get secret: ${secret}`)).toBeVisible()
|
||||
})
|
||||
})
|
||||
}
|
||||
19
test/e2e/typescript.test.ts
Normal file
19
test/e2e/typescript.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
const args = ["--disable-workspace-trust"]
|
||||
|
||||
describe("typescript extension", args, {}, () => {
|
||||
test("should load as a workspace extension", async ({ codeServerPage }) => {
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const file = path.join(dir, "foo.ts")
|
||||
await fs.writeFile(file, 'const n: number = "x"')
|
||||
await codeServerPage.openFile(file)
|
||||
|
||||
await codeServerPage.executeCommandViaMenus("Developer: Show Running Extensions")
|
||||
await expect(
|
||||
codeServerPage.page.getByLabel("typescript-language-features").getByText(/localhost:\d+/),
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Level, logger } from "@coder/logger"
|
||||
import { promises as fs } from "fs"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import {
|
||||
UserProvidedArgs,
|
||||
@@ -575,9 +576,33 @@ describe("parser", () => {
|
||||
"install-extension": ["extension.number1", "extension.number2"],
|
||||
})
|
||||
})
|
||||
it("should expand ~ in path options from the config file", () => {
|
||||
const configContents = `
|
||||
user-data-dir: ~/.config/code-server-data
|
||||
extensions-dir: ~/extensions
|
||||
`
|
||||
expect(parseConfigFile(configContents, "/fake-config-path")).toEqual({
|
||||
config: "/fake-config-path",
|
||||
"user-data-dir": path.join(os.homedir(), ".config/code-server-data"),
|
||||
"extensions-dir": path.join(os.homedir(), "extensions"),
|
||||
})
|
||||
})
|
||||
it("should ignore optional strings set to false", async () => {
|
||||
expect(parse(["--cert=false"])).toEqual({})
|
||||
})
|
||||
it("should ignore booleans set to false", async () => {
|
||||
expect(parse(["--disable-telemetry=false"])).toEqual({})
|
||||
})
|
||||
it("should parse booleans set to false in the config file", () => {
|
||||
const configContents = `
|
||||
disable-telemetry: false
|
||||
disable-update-check: true
|
||||
`
|
||||
expect(parseConfigFile(configContents, "/fake-config-path")).toEqual({
|
||||
config: "/fake-config-path",
|
||||
"disable-update-check": true,
|
||||
})
|
||||
})
|
||||
it("should use last flag", async () => {
|
||||
expect(parse(["--port", "8081", "--port", "8082"])).toEqual({
|
||||
port: 8082,
|
||||
|
||||
@@ -75,6 +75,17 @@ describe("login", () => {
|
||||
expect(htmlContent).toContain("Missing password")
|
||||
})
|
||||
|
||||
it("should reject compressed request bodies", async () => {
|
||||
for (const encoding of ["br", "gzip", "deflate"]) {
|
||||
const resp = await codeServer().fetch("/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Encoding": encoding },
|
||||
body: "password=test",
|
||||
})
|
||||
expect(resp.status).toBe(415)
|
||||
}
|
||||
})
|
||||
|
||||
it("should return HTML with 'Incorrect password' message", async () => {
|
||||
const params = new URLSearchParams()
|
||||
params.append("password", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as cp from "child_process"
|
||||
import { promises as fs } from "fs"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import { generateUuid } from "../../../src/common/util"
|
||||
import { tmpdir } from "../../../src/node/constants"
|
||||
@@ -623,3 +624,18 @@ describe("splitOnFirstEquals", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("expandTilde", () => {
|
||||
it("should expand a bare ~", () => {
|
||||
expect(util.expandTilde("~")).toBe(os.homedir())
|
||||
})
|
||||
it("should expand a leading ~/", () => {
|
||||
expect(util.expandTilde("~/.config/code-server")).toBe(path.join(os.homedir(), ".config/code-server"))
|
||||
})
|
||||
it("should leave other paths alone", () => {
|
||||
expect(util.expandTilde("/tmp/~/data")).toBe("/tmp/~/data")
|
||||
expect(util.expandTilde("relative/~")).toBe("relative/~")
|
||||
expect(util.expandTilde("~user/data")).toBe("~user/data")
|
||||
expect(util.expandTilde("")).toBe("")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user