Compare commits

...

5 Commits

Author SHA1 Message Date
Asher
a5c1b6a196 Use inputs instead of github.event.inputs
Just to be consistent with the other workflow.  They are the same except
inputs treats booleans as booleans instead of strings, which seems like
it might be better anyway.
2026-03-26 12:04:11 -08:00
dagecko
2743655ab5 Pin actions and extract expressions to env vars (#7719) 2026-03-26 12:01:48 -08:00
Olivier Benz
8d9a44a024 Update Code to 1.113.0 (#7716)
* Update Code to 1.113.0

* Use CI build targets

The target we have been using has started throwing all sorts of errors
during the build (even without any of our patches).  After checking the
VS Code repo I think these are the ones we should actually be using.
They are way faster, too.

---------

Co-authored-by: Asher <ash@coder.com>
2026-03-26 11:39:40 -08:00
Tianyi Cui
ada3489acf feat: expose --reconnection-grace-time CLI flag (#7678)
* feat: expose --reconnection-grace-time CLI flag

Pass through VS Code Server's --reconnection-grace-time argument,
allowing users to configure how long the server waits for a
disconnected client to reconnect before cleaning up the session.

This is useful for users whose client machines sleep overnight, causing
the default 3-hour grace period to expire and forcing a "Reload Window"
on wake. The flag can also be set via CODE_SERVER_RECONNECTION_GRACE_TIME
env var or in config.yaml.
2026-03-25 11:47:58 -08:00
Abdulsattar Mohammed
4d615f18a9 feat: add wildcard support to trusted-origins (#7697) 2026-03-25 11:04:06 -08:00
23 changed files with 155 additions and 88 deletions

View File

@@ -34,7 +34,7 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v6
- name: Check changed files
uses: dorny/paths-filter@v3
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
id: filter
with:
filters: |
@@ -98,7 +98,7 @@ jobs:
if: needs.changes.outputs.helm == 'true'
steps:
- uses: actions/checkout@v6
- uses: azure/setup-helm@v4
- uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- run: helm plugin install https://github.com/instrumenta/helm-kubeval
@@ -151,7 +151,7 @@ jobs:
test/package-lock.json
- run: SKIP_SUBMODULE_DEPS=1 npm ci
- run: npm run test:unit
- uses: codecov/codecov-action@v5
- uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
if: success()
with:
token: ${{ secrets.CODECOV_TOKEN }}
@@ -167,7 +167,7 @@ jobs:
with:
submodules: true
- run: sudo apt update && sudo apt install -y libkrb5-dev
- uses: awalsh128/cache-apt-pkgs-action@latest
- uses: awalsh128/cache-apt-pkgs-action@2c09a5e66da6c8016428a2172bd76e5e4f14bb17 # latest
with:
packages: quilt
version: 1.0

View File

@@ -33,19 +33,20 @@ jobs:
node-version-file: .node-version
- name: Download npm package from release artifacts
uses: robinraju/release-downloader@v1.12
uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
with:
repository: "coder/code-server"
tag: ${{ github.event.inputs.version || github.ref_name }}
tag: ${{ inputs.version || github.ref_name }}
fileName: "package.tar.gz"
out-file-path: "release-npm-package"
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- run: npm run publish:npm
env:
VERSION: ${{ env.VERSION }}
@@ -88,11 +89,12 @@ jobs:
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- name: Validate package
uses: heyhusen/archlinux-package-action@v3.0.0
uses: heyhusen/archlinux-package-action@c9f94059ccbebe8710d31d582f33ef4e84fe575c # v3.0.0
env:
VERSION: ${{ env.VERSION }}
with:
@@ -119,19 +121,19 @@ jobs:
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -140,11 +142,12 @@ jobs:
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- name: Download deb artifacts
uses: robinraju/release-downloader@v1.12
uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
@@ -152,7 +155,7 @@ jobs:
out-file-path: "release-packages"
- name: Download rpm artifacts
uses: robinraju/release-downloader@v1.12
uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}

View File

@@ -111,14 +111,15 @@ jobs:
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- env:
VERSION: ${{ env.VERSION }}
run: npm run package $PKG_ARCH
- uses: softprops/action-gh-release@v1
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
draft: true
discussion_category_name: "📣 Announcements"
@@ -171,15 +172,16 @@ jobs:
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- name: Build packages with nfpm
env:
VERSION: ${{ env.VERSION }}
run: npm run package
- uses: softprops/action-gh-release@v1
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
draft: true
discussion_category_name: "📣 Announcements"
@@ -232,15 +234,16 @@ jobs:
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- name: Build packages with nfpm
env:
VERSION: ${{ env.VERSION }}
run: npm run package
- uses: softprops/action-gh-release@v1
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
draft: true
discussion_category_name: "📣 Announcements"
@@ -257,7 +260,7 @@ jobs:
with:
name: npm-release-package
- uses: softprops/action-gh-release@v1
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
draft: true
discussion_category_name: "📣 Announcements"
@@ -269,7 +272,7 @@ jobs:
timeout-minutes: 15
steps:
- name: Download artifacts
uses: dawidd6/action-download-artifact@v16
uses: dawidd6/action-download-artifact@2536c51d3d126276eb39f74d6bc9c72ac6ef30d3 # v16
id: download
with:
branch: ${{ github.ref }}
@@ -284,9 +287,10 @@ jobs:
# Strip out the v (v4.9.1 -> 4.9.1).
- name: Get and set VERSION
run: |
TAG="${{ inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
env:
TAG: ${{ inputs.version || github.ref_name }}
- name: Modify version
env:
VERSION: ${{ env.VERSION }}

View File

@@ -1 +1 @@
22.22.0
22.22.1

View File

@@ -112,9 +112,8 @@ EOF
# this because we have an NPM package that could be installed on any platform.
# The correct platform dependencies and scripts will be installed as part of
# the post-install during `npm install` or when building a standalone release.
node --max-old-space-size=16384 --optimize-for-size \
./node_modules/gulp/bin/gulp.js \
"vscode-reh-web-linux-x64${MINIFY:+-min}"
npm run gulp core-ci
npm run gulp "vscode-reh-web-linux-x64${MINIFY:+-min}-ci"
# Reset so if you develop after building you will not be stuck with the wrong
# commit (the dev client will use `oss-dev` but the dev server will still use

View File

@@ -22,6 +22,7 @@
- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
- [What is the healthz endpoint?](#what-is-the-healthz-endpoint)
- [What is the heartbeat file?](#what-is-the-heartbeat-file)
- [How do I change the reconnection grace time?](#how-do-i-change-the-reconnection-grace-time)
- [How do I change the password?](#how-do-i-change-the-password)
- [Can I store my password hashed?](#can-i-store-my-password-hashed)
- [Is multi-tenancy possible?](#is-multi-tenancy-possible)
@@ -326,6 +327,16 @@ If you want to shutdown code-server if there hasn't been an active connection
after a predetermined amount of time, you can use the --idle-timeout-seconds flag
or set an `CODE_SERVER_IDLE_TIMEOUT_SECONDS` environment variable.
## How do I change the reconnection grace time?
Pass `--reconnection-grace-time <seconds>` to `code-server`, set
`CODE_SERVER_RECONNECTION_GRACE_TIME=<seconds>`, or add
`reconnection-grace-time: <seconds>` to
`~/.config/code-server/config.yaml`.
The default is `10800` (3 hours). If a client stays disconnected longer than
this, it must reload the window.
## How do I change the password?
Edit the `password` field in the code-server config file at

View File

@@ -78,7 +78,7 @@ Index: code-server/lib/vscode/src/vs/platform/environment/common/argv.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/environment/common/argv.ts
+++ code-server/lib/vscode/src/vs/platform/environment/common/argv.ts
@@ -139,6 +139,7 @@ export interface NativeParsedArgs {
@@ -143,6 +143,7 @@ export interface NativeParsedArgs {
'disable-chromium-sandbox'?: boolean;
sandbox?: boolean;
'enable-coi'?: boolean;
@@ -90,7 +90,7 @@ Index: code-server/lib/vscode/src/vs/platform/environment/node/argv.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/environment/node/argv.ts
+++ code-server/lib/vscode/src/vs/platform/environment/node/argv.ts
@@ -106,6 +106,7 @@ export const OPTIONS: OptionDescriptions
@@ -115,6 +115,7 @@ export const OPTIONS: OptionDescriptions
'user-data-dir': { type: 'string', cat: 'o', args: 'dir', description: localize('userDataDir', "Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.") },
'profile': { type: 'string', 'cat': 'o', args: 'profileName', description: localize('profileName', "Opens the provided folder or workspace with the given profile and associates the profile with the workspace. If the profile does not exist, a new empty one is created.") },
'help': { type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") },

View File

@@ -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 { IConfigurationService } from '../../platform/configuration/common/configuration.js';
import { ConfigurationService } from '../../platform/configuration/common/configurationService.js';
@@ -277,6 +277,9 @@ export async function setupServerService
@@ -297,6 +297,9 @@ export async function setupServerService
socketServer.registerChannel('mcpManagement', new McpManagementChannel(mcpManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority)));
@@ -198,7 +198,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -113,6 +114,7 @@ export interface ServerParsedArgs {
@@ -116,6 +117,7 @@ export interface ServerParsedArgs {
'disable-file-downloads'?: boolean;
'disable-file-uploads'?: boolean;
'disable-getting-started-override'?: boolean,

View File

@@ -99,7 +99,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -107,6 +109,8 @@ export interface ServerParsedArgs {
@@ -110,6 +112,8 @@ export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;
'auth'?: string;
@@ -230,7 +230,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFi
import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js';
import { IContextKeyService, IContextKey, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
import { equalsIgnoreCase, format, startsWithIgnoreCase } from '../../../../base/common/strings.js';
@@ -144,7 +144,7 @@ export class SimpleFileDialog extends Di
@@ -152,7 +152,7 @@ export class SimpleFileDialog extends Di
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@IModelService private readonly modelService: IModelService,
@ILanguageService private readonly languageService: ILanguageService,
@@ -239,7 +239,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFi
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@IPathService protected readonly pathService: IPathService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@@ -322,21 +322,23 @@ export class SimpleFileDialog extends Di
@@ -362,21 +362,23 @@ export class SimpleFileDialog extends Di
this.filePickBox.placeholder = nls.localize('remoteFileDialog.placeholder', "Folder path");
this.filePickBox.ok = true;
this.filePickBox.okLabel = typeof this.options.openLabel === 'string' ? this.options.openLabel : this.options.openLabel?.withoutMnemonic;

View File

@@ -1,38 +0,0 @@
Fix protected field error
The mangler is reporting this error:
WARN: 'setEditorVisible' from lib/vscode/src/vs/workbench/browser/parts/editor/editorPane.ts:160 became PUBLIC because of: lib/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEditor.ts:304
ERROR: Protected fields have been made PUBLIC. This hurts minification and is therefore not allowed. Review the WARN messages further above
No idea how VS Code is dealing with this in their own builds.
Additionally, in CI the build keeps getting terminated, possibly from running
out of memory (there is no error message, it simply says it was canceled).
Index: code-server/lib/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEditor.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEditor.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEditor.ts
@@ -299,7 +299,7 @@ export class ChatDebugEditor extends Edi
}
}
- override setEditorVisible(visible: boolean): void {
+ protected override setEditorVisible(visible: boolean): void {
super.setEditorVisible(visible);
if (visible) {
this.telemetryService.publicLog2<{}, ChatDebugPanelOpenedClassification>('chatDebugPanelOpened');
Index: code-server/lib/vscode/build/lib/mangle/index.ts
===================================================================
--- code-server.orig/lib/vscode/build/lib/mangle/index.ts
+++ code-server/lib/vscode/build/lib/mangle/index.ts
@@ -430,7 +430,7 @@ export class Mangler {
this.config = config;
this.renameWorkerPool = workerpool.pool(path.join(import.meta.dirname, 'renameWorker.ts'), {
- maxWorkers: 4,
+ maxWorkers: 2,
minWorkers: 'max'
});
}

View File

@@ -189,7 +189,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -111,6 +112,7 @@ export interface ServerParsedArgs {
@@ -114,6 +115,7 @@ export interface ServerParsedArgs {
'auth'?: string;
'disable-file-downloads'?: boolean;
'disable-file-uploads'?: boolean;

View File

@@ -28,7 +28,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -105,6 +106,7 @@ export const serverOptions: OptionDescri
@@ -108,6 +109,7 @@ export const serverOptions: OptionDescri
export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;

View File

@@ -17,7 +17,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/extensions/common/extens
- if (!extension.enabledApiProposals) {
- return false;
- }
- return extension.enabledApiProposals.includes(proposal);
- return true;// extension.enabledApiProposals.includes(proposal);
+ return true
}

View File

@@ -22,4 +22,3 @@ clipboard.diff
display-language.diff
trusted-domains.diff
signature-verification.diff
fix-build.diff

View File

@@ -10,7 +10,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.ts
===================================================================
--- code-server.orig/lib/vscode/build/gulpfile.reh.ts
+++ code-server/lib/vscode/build/gulpfile.reh.ts
@@ -262,8 +262,7 @@ function packageTask(type: string, platf
@@ -263,8 +263,7 @@ function packageTask(type: string, platf
return () => {
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.ts
const workspaceExtensionPoints = ['debuggers', 'jsonValidation'];
const isUIExtension = (manifest: { extensionKind?: string; main?: string; contributes?: Record<string, unknown> }) => {
@@ -303,9 +302,9 @@ function packageTask(type: string, platf
@@ -304,9 +303,9 @@ function packageTask(type: string, platf
.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.ts
let version = packageJson.version;
const quality = (product as typeof product & { quality?: string }).quality;
@@ -492,7 +491,7 @@ function tweakProductForServerWeb(produc
@@ -501,7 +500,7 @@ function tweakProductForServerWeb(produc
const minifyTask = task.define(`minify-vscode-${type}`, task.series(
bundleTask,
util.rimraf(`out-vscode-${type}-min`),

View File

@@ -28,7 +28,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';
@@ -169,11 +171,23 @@ export async function setupServerService
@@ -172,11 +174,23 @@ export async function setupServerService
const requestService = new RequestService('remote', configurationService, environmentService, logService);
services.set(IRequestService, requestService);

View File

@@ -12,7 +12,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -115,6 +116,7 @@ export interface ServerParsedArgs {
@@ -118,6 +119,7 @@ export interface ServerParsedArgs {
'disable-file-uploads'?: boolean;
'disable-getting-started-override'?: boolean,
'locale'?: string

View File

@@ -101,7 +101,7 @@ Index: code-server/lib/vscode/src/vs/base/common/product.ts
readonly version: string;
readonly date?: string;
@@ -114,6 +115,7 @@ export interface IProductConfiguration {
@@ -115,6 +116,7 @@ export interface IProductConfiguration {
readonly resourceUrlTemplate: string;
readonly nlsBaseUrl: string;
readonly accessSKUs?: string[];
@@ -134,7 +134,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -101,6 +103,8 @@ export const serverOptions: OptionDescri
@@ -104,6 +106,8 @@ export const serverOptions: OptionDescri
};
export interface ServerParsedArgs {

View File

@@ -52,6 +52,7 @@ export interface UserProvidedCodeArgs {
"disable-workspace-trust"?: boolean
"disable-getting-started-override"?: boolean
"disable-proxy"?: boolean
"reconnection-grace-time"?: string
"session-socket"?: string
"cookie-suffix"?: string
"link-protection-trusted-domains"?: string[]
@@ -315,6 +316,12 @@ export const options: Options<Required<UserProvidedArgs>> = {
type: "number",
description: "Timeout in seconds to wait before shutting down when idle.",
},
"reconnection-grace-time": {
type: "string",
description:
"Override the reconnection grace time in seconds. Clients who disconnect for longer than this duration will need to \n" +
"reload the window. Defaults to 10800 (3 hours).",
},
}
export const optionDescriptions = (opts: Partial<Options<Required<UserProvidedArgs>>> = options): string[] => {
@@ -632,6 +639,10 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
args["github-auth"] = process.env.GITHUB_TOKEN
}
if (process.env.CODE_SERVER_RECONNECTION_GRACE_TIME) {
args["reconnection-grace-time"] = process.env.CODE_SERVER_RECONNECTION_GRACE_TIME
}
if (process.env.CODE_SERVER_IDLE_TIMEOUT_SECONDS) {
if (isNaN(Number(process.env.CODE_SERVER_IDLE_TIMEOUT_SECONDS))) {
logger.info("CODE_SERVER_IDLE_TIMEOUT_SECONDS must be a number")

View File

@@ -351,6 +351,25 @@ export function ensureOrigin(req: express.Request, _?: express.Response, next?:
}
}
/**
* Return true if the origin matches any trusted origin. Entries are matched
* as exact strings, the special wildcard `"*"`, or `*.example.com`-style
* domain wildcards (same as --proxy-domain).
*/
export function isTrustedOrigin(origin: string, trustedOrigins: string[]): boolean {
return trustedOrigins.some((trusted) => {
if (trusted === "*" || trusted === origin) {
return true
}
// *.example.com style: match origin if it is the domain or a subdomain
if (trusted.startsWith("*.")) {
const domain = trusted.slice(2).toLowerCase()
return origin === domain || origin.endsWith("." + domain)
}
return false
})
}
/**
* Authenticate the request origin against the host. Throw if invalid.
*/
@@ -370,7 +389,7 @@ export function authenticateOrigin(req: express.Request): void {
}
const trustedOrigins = req.args["trusted-origins"] || []
if (trustedOrigins.includes(origin) || trustedOrigins.includes("*")) {
if (isTrustedOrigin(origin, trustedOrigins)) {
return
}

View File

@@ -48,6 +48,7 @@ describe("parser", () => {
delete process.env.PASSWORD
delete process.env.CS_DISABLE_FILE_DOWNLOADS
delete process.env.CS_DISABLE_GETTING_STARTED_OVERRIDE
delete process.env.CODE_SERVER_RECONNECTION_GRACE_TIME
delete process.env.VSCODE_PROXY_URI
delete process.env.CS_DISABLE_PROXY
console.log = jest.fn()
@@ -115,6 +116,8 @@ describe("parser", () => {
["--session-socket", "/tmp/override-code-server-ipc-socket"],
["--reconnection-grace-time", "86400"],
["--host", "0.0.0.0"],
"4",
"--",
@@ -151,6 +154,7 @@ describe("parser", () => {
version: true,
"bind-addr": "192.169.0.1:8080",
"session-socket": "/tmp/override-code-server-ipc-socket",
"reconnection-grace-time": "86400",
"abs-proxy-base-path": "/codeserver/app1",
"skip-auth-preflight": true,
})
@@ -457,6 +461,19 @@ describe("parser", () => {
})
})
it("should use env var CODE_SERVER_RECONNECTION_GRACE_TIME for reconnection grace time", async () => {
process.env.CODE_SERVER_RECONNECTION_GRACE_TIME = "86400"
const args = parse([])
expect(args).toEqual({})
const defaultArgs = await setDefaults(args)
expect(defaultArgs).toEqual({
...defaults,
"reconnection-grace-time": "86400",
})
delete process.env.CODE_SERVER_RECONNECTION_GRACE_TIME
})
it("should error if password passed in", () => {
expect(() => parse(["--password", "supersecret123"])).toThrowError(
"--password can only be set in the config file or passed in via $PASSWORD",

View File

@@ -19,6 +19,30 @@ describe("http", () => {
expect(http.relativeRoot("/foo/bar/")).toStrictEqual("./../..")
})
describe("isTrustedOrigin", () => {
it("should match exact origins", () => {
expect(http.isTrustedOrigin("localhost:8080", ["localhost:8080"])).toBe(true)
expect(http.isTrustedOrigin("example.com", ["example.com"])).toBe(true)
expect(http.isTrustedOrigin("example.com", ["other.com"])).toBe(false)
})
it("should match the wildcard *", () => {
expect(http.isTrustedOrigin("anything.example.com", ["*"])).toBe(true)
expect(http.isTrustedOrigin("localhost:8080", ["*"])).toBe(true)
})
it("should match *.example.com wildcard (same style as --proxy-domain)", () => {
expect(http.isTrustedOrigin("sub.example.com", ["*.example.com"])).toBe(true)
expect(http.isTrustedOrigin("example.com", ["*.example.com"])).toBe(true)
expect(http.isTrustedOrigin("evil.com", ["*.example.com"])).toBe(false)
expect(http.isTrustedOrigin("example.com.evil.com", ["*.example.com"])).toBe(false)
})
it("should return false for an empty trusted origins list", () => {
expect(http.isTrustedOrigin("example.com", [])).toBe(false)
})
})
describe("origin", () => {
;[
{
@@ -54,6 +78,22 @@ describe("http", () => {
host: "localhost:8080",
expected: "malformed", // Parsing fails completely.
},
{
origin: "http://sub.example.com",
host: "other.com",
trustedOrigins: ["*.example.com"],
},
{
origin: "http://evil.com",
host: "other.com",
trustedOrigins: ["*.example.com"],
expected: "does not match",
},
{
origin: "http://sub.example.com",
host: "other.com",
trustedOrigins: ["*"],
},
].forEach((test) => {
;[
["host", test.host],
@@ -70,7 +110,9 @@ describe("http", () => {
origin: test.origin,
[key]: value,
},
args: {},
args: {
"trusted-origins": (test as { trustedOrigins?: string[] }).trustedOrigins,
},
})
if (typeof test.expected === "string") {
expect(() => http.authenticateOrigin(req)).toThrow(test.expected)