mirror of
https://github.com/coder/code-server.git
synced 2026-09-03 00:42:58 +02:00
Compare commits
6 Commits
9c0c52cde3
...
90427af5d8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90427af5d8 | ||
|
|
313bf0359b | ||
|
|
41cbd28c44 | ||
|
|
208c81a072 | ||
|
|
f836314954 | ||
|
|
1a370bb606 |
12
CHANGELOG.md
12
CHANGELOG.md
@@ -22,6 +22,18 @@ Code v99.99.999
|
||||
|
||||
## Unreleased
|
||||
|
||||
Code v1.132.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to Code 1.132.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- When proxying, cookies were being decoded and re-encoded, which could cause
|
||||
issues for applications that encode differently. Cookies are now passed
|
||||
through unchanged (aside from stripping out code-server's session token).
|
||||
|
||||
## [4.131.0](https://github.com/coder/code-server/releases/tag/v4.131.0) - 2026-07-30
|
||||
|
||||
Code v1.131.0
|
||||
|
||||
Submodule lib/vscode updated: 3a03d6f72d...df53daabb1
24
package-lock.json
generated
24
package-lock.json
generated
@@ -44,7 +44,7 @@
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/http-proxy": "1.17.7",
|
||||
"@types/js-yaml": "^4.0.6",
|
||||
"@types/node": "22.x",
|
||||
"@types/node": "24.x",
|
||||
"@types/pem": "^1.14.1",
|
||||
"@types/proxy-from-env": "^1.0.1",
|
||||
"@types/safe-compare": "^1.1.0",
|
||||
@@ -65,7 +65,7 @@
|
||||
"typescript-eslint": "^8.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "22"
|
||||
"node": "24"
|
||||
}
|
||||
},
|
||||
"node_modules/@coder/logger": {
|
||||
@@ -675,13 +675,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz",
|
||||
"integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==",
|
||||
"version": "24.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
|
||||
"integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
"undici-types": "~7.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pem": {
|
||||
@@ -3683,9 +3683,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
|
||||
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz",
|
||||
"integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
@@ -6329,9 +6329,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/http-proxy": "1.17.7",
|
||||
"@types/js-yaml": "^4.0.6",
|
||||
"@types/node": "22.x",
|
||||
"@types/node": "24.x",
|
||||
"@types/pem": "^1.14.1",
|
||||
"@types/proxy-from-env": "^1.0.1",
|
||||
"@types/safe-compare": "^1.1.0",
|
||||
@@ -88,7 +88,7 @@
|
||||
"xdg-basedir": "^4.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "22.x"
|
||||
"@types/node": "24.x"
|
||||
},
|
||||
"bin": {
|
||||
"code-server": "out/node/entry.js"
|
||||
@@ -103,7 +103,7 @@
|
||||
"remote-development"
|
||||
],
|
||||
"engines": {
|
||||
"node": "22"
|
||||
"node": "24"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
|
||||
@@ -146,7 +146,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
embedderIdentifier: 'server-distro',
|
||||
voiceWsUrl: this._productService.voiceWsUrl,
|
||||
extensionsGallery: this._webExtensionResourceUrlTemplate && this._productService.extensionsGallery ? {
|
||||
@@ -402,7 +409,9 @@ export class WebClientServer {
|
||||
@@ -403,7 +410,9 @@ export class WebClientServer {
|
||||
WORKBENCH_AUTH_SESSION: authSessionInfo ? asJSON(authSessionInfo) : '',
|
||||
WORKBENCH_WEB_BASE_URL: staticRoute,
|
||||
WORKBENCH_NLS_URL,
|
||||
@@ -157,7 +157,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
};
|
||||
|
||||
// DEV ---------------------------------------------------------------------------------------
|
||||
@@ -439,7 +448,7 @@ export class WebClientServer {
|
||||
@@ -440,7 +449,7 @@ export class WebClientServer {
|
||||
'default-src \'self\';',
|
||||
'img-src \'self\' https: data: blob:;',
|
||||
'media-src \'self\';',
|
||||
@@ -166,7 +166,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
'child-src \'self\';',
|
||||
`frame-src 'self' https://*.vscode-cdn.net data:;`,
|
||||
'worker-src \'self\' data: blob:;',
|
||||
@@ -512,3 +521,70 @@ export class WebClientServer {
|
||||
@@ -513,3 +522,70 @@ export class WebClientServer {
|
||||
return void res.end(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
import { CharCode } from '../../base/common/charCode.js';
|
||||
import { IExtensionManifest } from '../../platform/extensions/common/extensions.js';
|
||||
import { ICSSDevelopmentService } from '../../platform/cssDev/node/cssDevService.js';
|
||||
@@ -400,14 +401,22 @@ export class WebClientServer {
|
||||
@@ -401,14 +402,22 @@ export class WebClientServer {
|
||||
};
|
||||
|
||||
const cookies = cookie.parse(req.headers.cookie || '');
|
||||
@@ -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
|
||||
@@ -474,9 +474,6 @@ export class InstallAction extends Exten
|
||||
@@ -475,9 +475,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;
|
||||
}
|
||||
@@ -781,7 +778,7 @@ export abstract class InstallInOtherServ
|
||||
@@ -782,7 +779,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
|
||||
@@ -2282,17 +2279,6 @@ export class SetLanguageAction extends E
|
||||
@@ -2281,17 +2278,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> {
|
||||
@@ -2309,7 +2295,6 @@ export class ClearLanguageAction extends
|
||||
@@ -2308,7 +2294,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);
|
||||
@@ -2319,17 +2304,6 @@ export class ClearLanguageAction extends
|
||||
@@ -2318,17 +2303,6 @@ export class ClearLanguageAction extends
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = ClearLanguageAction.DisabledClass;
|
||||
|
||||
@@ -27,7 +27,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
|
||||
@@ -312,6 +312,16 @@ export interface IWorkbenchConstructionO
|
||||
@@ -319,6 +319,16 @@ export interface IWorkbenchConstructionO
|
||||
*/
|
||||
readonly userDataPath?: string
|
||||
|
||||
@@ -166,12 +166,12 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions
|
||||
import { AutoSaveAfterShortDelayContext } from '../../../services/filesConfiguration/common/filesConfigurationService.js';
|
||||
import { WorkbenchListDoubleSelection } from '../../../../platform/list/browser/listService.js';
|
||||
import { Schemas } from '../../../../base/common/network.js';
|
||||
-import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsSessionsWindowContext, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext, MultipleEditorsSelectedInGroupContext, TwoEditorsSelectedInGroupContext, SelectedEditorsInGroupFileOrUntitledResourceContextKey } from '../../../common/contextkeys.js';
|
||||
+import { IsEnabledFileDownloads, IsEnabledFileUploads, DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsSessionsWindowContext, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext, MultipleEditorsSelectedInGroupContext, TwoEditorsSelectedInGroupContext, SelectedEditorsInGroupFileOrUntitledResourceContextKey } from '../../../common/contextkeys.js';
|
||||
-import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsSessionsWindowContext, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ActiveEditorDirtyContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext, MultipleEditorsSelectedInGroupContext, TwoEditorsSelectedInGroupContext, SelectedEditorsInGroupFileOrUntitledResourceContextKey } from '../../../common/contextkeys.js';
|
||||
+import { IsEnabledFileDownloads, IsEnabledFileUploads, DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsSessionsWindowContext, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ActiveEditorDirtyContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext, MultipleEditorsSelectedInGroupContext, TwoEditorsSelectedInGroupContext, SelectedEditorsInGroupFileOrUntitledResourceContextKey } from '../../../common/contextkeys.js';
|
||||
import { IsWebContext } from '../../../../platform/contextkey/common/contextkeys.js';
|
||||
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { ThemeIcon } from '../../../../base/common/themables.js';
|
||||
@@ -571,13 +571,16 @@ MenuRegistry.appendMenuItem(MenuId.Explo
|
||||
@@ -573,13 +573,16 @@ MenuRegistry.appendMenuItem(MenuId.Explo
|
||||
id: DOWNLOAD_COMMAND_ID,
|
||||
title: DOWNLOAD_LABEL
|
||||
},
|
||||
@@ -195,7 +195,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions
|
||||
)
|
||||
}));
|
||||
|
||||
@@ -589,6 +592,7 @@ MenuRegistry.appendMenuItem(MenuId.Explo
|
||||
@@ -591,6 +594,7 @@ MenuRegistry.appendMenuItem(MenuId.Explo
|
||||
title: UPLOAD_LABEL,
|
||||
},
|
||||
when: ContextKeyExpr.and(
|
||||
|
||||
@@ -135,7 +135,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
|
||||
@@ -322,6 +322,11 @@ export interface IWorkbenchConstructionO
|
||||
@@ -329,6 +329,11 @@ export interface IWorkbenchConstructionO
|
||||
*/
|
||||
readonly isEnabledFileUploads?: boolean
|
||||
|
||||
|
||||
@@ -30,7 +30,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
|
||||
@@ -307,6 +307,11 @@ export interface IWorkbenchConstructionO
|
||||
@@ -314,6 +314,11 @@ export interface IWorkbenchConstructionO
|
||||
*/
|
||||
readonly configurationDefaults?: Record<string, unknown>;
|
||||
|
||||
|
||||
@@ -148,7 +148,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
|
||||
@@ -84,8 +84,8 @@ export class ForwardedPortsView extends
|
||||
@@ -99,8 +99,8 @@ export class ForwardedPortsView extends
|
||||
private async enableForwardedPortsFeatures() {
|
||||
this.contextKeyListener.clear();
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/envi
|
||||
===================================================================
|
||||
--- 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
|
||||
@@ -226,7 +226,7 @@ export class BrowserWorkbenchEnvironment
|
||||
@@ -234,7 +234,7 @@ export class BrowserWorkbenchEnvironment
|
||||
|
||||
@memoize
|
||||
get webviewExternalEndpoint(): string {
|
||||
|
||||
@@ -20,17 +20,31 @@ proxy.on("error", (error, _, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
function identity<T>(val: T): T {
|
||||
return val
|
||||
}
|
||||
|
||||
// Strip the code-server cookie if it exists to avoid transmitting the cookie
|
||||
// to potentially malicious local ports.
|
||||
proxy.on("proxyReq", (preq, req) => {
|
||||
const cookieSessionName = getCookieSessionName((req as Request).args["cookie-suffix"])
|
||||
preq.setHeader(
|
||||
"Cookie",
|
||||
cookie.stringifyCookie({
|
||||
...(req as Request).cookies,
|
||||
[cookieSessionName]: undefined,
|
||||
}),
|
||||
)
|
||||
if (req.headers.cookie) {
|
||||
const cookieSessionName = getCookieSessionName((req as Request).args["cookie-suffix"])
|
||||
// Encoding and decoding are no-ops; we just want to remove the token
|
||||
// without changing anything else about the cookies because not all
|
||||
// applications encode/decode the same way `cookie` here does.
|
||||
preq.setHeader(
|
||||
"Cookie",
|
||||
cookie.stringifyCookie(
|
||||
{
|
||||
...cookie.parseCookie(req.headers.cookie, { decode: identity }),
|
||||
[cookieSessionName]: undefined,
|
||||
},
|
||||
{
|
||||
encode: identity,
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
// Intercept the response to rewrite absolute redirects against the base path.
|
||||
|
||||
@@ -298,25 +298,44 @@ describe("proxy", () => {
|
||||
process.env.HASHED_PASSWORD = token
|
||||
codeServer = await integration.setup(["--auth=password"])
|
||||
|
||||
// Set up a listener that just prints the cookies it got.
|
||||
e.get("/wsup/cookies", (req, res) => {
|
||||
res.writeHead(HttpCode.Ok, { "Content-Type": "text/plain" })
|
||||
res.end(req.headers.cookie)
|
||||
})
|
||||
|
||||
// Send the token along with other cookies which should be preserved.
|
||||
// Encode one to make sure they are being re-encoded properly.
|
||||
const value = "hello=there"
|
||||
const encodedValue = encodeURIComponent(value)
|
||||
const resp = await codeServer.fetch(proxyPath + "/cookies", {
|
||||
headers: {
|
||||
cookie: `cookie1=${encodedValue}; code-server-session=${token}; cookie2=hello;`,
|
||||
},
|
||||
const cookies = [
|
||||
"cookie2=hello",
|
||||
// Cookies should pass through unchanged, neither encoded nor decoded.
|
||||
`cookie1=${encodeURIComponent("hello=there")}`,
|
||||
"cookie3=foo|bar",
|
||||
`cookie4=${encodeURIComponent("foo|bar")}`,
|
||||
`cookie5=${encodeURIComponent("bar;baz")}`,
|
||||
]
|
||||
|
||||
// Test each slot to ensure the token is found anywhere.
|
||||
for (let i = 0; i <= cookies.length; ++i) {
|
||||
const left = cookies.slice(0, i)
|
||||
const right = cookies.slice(i)
|
||||
const resp = await codeServer.fetch(proxyPath + "/cookies", {
|
||||
headers: {
|
||||
cookie: [...left, `code-server-session=${token}`, ...right].join("; "),
|
||||
},
|
||||
})
|
||||
expect(resp.status).toBe(200)
|
||||
expect(await resp.text()).toBe(cookies.join("; "))
|
||||
}
|
||||
})
|
||||
|
||||
it("should proxy when no cookies", async () => {
|
||||
codeServer = await integration.setup(["--auth=none"])
|
||||
|
||||
e.get("/wsup/cookies", (req, res) => {
|
||||
res.writeHead(HttpCode.Ok, { "Content-Type": "text/plain" })
|
||||
res.end(req.headers.cookie || "no cookies")
|
||||
})
|
||||
|
||||
// The proxied listener should not have printed the code-server token.
|
||||
const resp = await codeServer.fetch(proxyPath + "/cookies")
|
||||
expect(resp.status).toBe(200)
|
||||
const text = await resp.text()
|
||||
expect(text).toBe(`cookie1=${encodedValue}; cookie2=hello`)
|
||||
expect(await resp.text()).toBe("no cookies")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("vscode", () => {
|
||||
|
||||
it("should require auth", async () => {
|
||||
codeServer = await integration.setup(["--auth=password"], "")
|
||||
let resp = await codeServer.fetch("/mint-key", { method: "POST" })
|
||||
const resp = await codeServer.fetch("/mint-key", { method: "POST" })
|
||||
expect(resp.status).toBe(401)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user