mirror of
https://github.com/coder/code-server.git
synced 2026-11-03 06:19:13 +01:00
Compare commits
37 Commits
a1acc25dc3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0a7057ff4 | ||
|
|
7c77a28768 | ||
|
|
74c1e34fe2 | ||
|
|
fd571e6c61 | ||
|
|
d4d1288212 | ||
|
|
79d2c29c49 | ||
|
|
ee16a40e41 | ||
|
|
e73622adaf | ||
|
|
734cdc9947 | ||
|
|
1c435fa2f5 | ||
|
|
74d06e2e36 | ||
|
|
f65b229eab | ||
|
|
973937ecf2 | ||
|
|
739bda2970 | ||
|
|
c88b56cddc | ||
|
|
cad47a78f1 | ||
|
|
b4725f8be9 | ||
|
|
68d5f022a5 | ||
|
|
68810a6bd6 | ||
|
|
ee31cdbe02 | ||
|
|
27808460b1 | ||
|
|
70fc911358 | ||
|
|
761b0d2a19 | ||
|
|
09012065c9 | ||
|
|
e999549684 | ||
|
|
9d0eee156e | ||
|
|
b87ae88bc6 | ||
|
|
89cba83cb4 | ||
|
|
b45f29491d | ||
|
|
4677c9d865 | ||
|
|
22ddf60dbc | ||
|
|
e777c1f963 | ||
|
|
279b5702aa | ||
|
|
27baccf843 | ||
|
|
8aab1b0d72 | ||
|
|
777c493a9b | ||
|
|
f07405cba3 |
4
.github/dependabot.yaml
vendored
4
.github/dependabot.yaml
vendored
@@ -9,6 +9,10 @@ updates:
|
||||
cooldown:
|
||||
default-days: 7
|
||||
labels: []
|
||||
groups:
|
||||
codeql-action:
|
||||
patterns:
|
||||
- "github/codeql-action/*"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
|
||||
24
.github/workflows/build.yaml
vendored
24
.github/workflows/build.yaml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
if: needs.changes.outputs.docs == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
if: needs.changes.outputs.code == 'true' || needs.changes.outputs.ci == 'true' || needs.changes.outputs.npm == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
if: needs.changes.outputs.code == 'true' || needs.changes.outputs.npm == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -217,7 +217,7 @@ jobs:
|
||||
# Push up an artifact containing the linux-x64 release.
|
||||
- run: KEEP_MODULES=1 npm run release
|
||||
- run: tar -czf package.tar.gz release
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: linux-x64-package
|
||||
path: ./package.tar.gz
|
||||
@@ -232,7 +232,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -245,13 +245,13 @@ jobs:
|
||||
./test/node_modules/.bin/playwright install-deps
|
||||
./test/node_modules/.bin/playwright install
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: linux-x64-package
|
||||
- run: tar -xzf package.tar.gz
|
||||
|
||||
- run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
if: always()
|
||||
with:
|
||||
name: failed-test-videos
|
||||
@@ -282,7 +282,7 @@ jobs:
|
||||
tar -xzf caddy_2.5.2_linux_amd64.tar.gz --directory ~/.cache/caddy
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -295,7 +295,7 @@ jobs:
|
||||
./test/node_modules/.bin/playwright install-deps
|
||||
./test/node_modules/.bin/playwright install
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: linux-x64-package
|
||||
- run: tar -xzf package.tar.gz
|
||||
@@ -304,7 +304,7 @@ jobs:
|
||||
- run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e:proxy
|
||||
- run: ~/.cache/caddy/caddy stop --config ./ci/Caddyfile
|
||||
if: always()
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
if: always()
|
||||
with:
|
||||
name: failed-test-videos-proxy
|
||||
|
||||
8
.github/workflows/publish.yaml
vendored
8
.github/workflows/publish.yaml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
|
||||
@@ -109,14 +109,14 @@ jobs:
|
||||
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
- uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4.3.0
|
||||
- uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||
- uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||
- uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
8
.github/workflows/release.yaml
vendored
8
.github/workflows/release.yaml
vendored
@@ -83,7 +83,7 @@ jobs:
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -253,7 +253,7 @@ jobs:
|
||||
git apply --whitespace=nowarn "patches/$patch"
|
||||
done < patches/series
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -347,7 +347,7 @@ jobs:
|
||||
esac
|
||||
npm run package
|
||||
|
||||
- uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
|
||||
- uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
||||
with:
|
||||
draft: true
|
||||
discussion_category_name: "📣 Announcements"
|
||||
|
||||
12
.github/workflows/security.yaml
vendored
12
.github/workflows/security.yaml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run Trivy vulnerability scanner in repo mode
|
||||
uses: aquasecurity/trivy-action@d2a0b60797ff03db6132bd4e2b293f9b37081297 # latest
|
||||
uses: aquasecurity/trivy-action@8f28faec26515256b6d22074d1d2a8986f4cbd87 # latest
|
||||
with:
|
||||
scan-type: "fs"
|
||||
scan-ref: "."
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
severity: "HIGH,CRITICAL"
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
|
||||
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
with:
|
||||
sarif_file: "trivy-repo-results.sarif"
|
||||
|
||||
@@ -80,13 +80,13 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
with:
|
||||
config-file: ./.github/codeql-config.yml
|
||||
languages: javascript
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
uses: github/codeql-action/autobuild@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
|
||||
4
.github/workflows/trivy-docker.yaml
vendored
4
.github/workflows/trivy-docker.yaml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
|
||||
- name: Run Trivy vulnerability scanner in image mode
|
||||
uses: aquasecurity/trivy-action@d2a0b60797ff03db6132bd4e2b293f9b37081297 # latest
|
||||
uses: aquasecurity/trivy-action@8f28faec26515256b6d22074d1d2a8986f4cbd87 # latest
|
||||
with:
|
||||
image-ref: "docker.io/codercom/code-server:latest"
|
||||
ignore-unfixed: true
|
||||
@@ -58,6 +58,6 @@ jobs:
|
||||
severity: "HIGH,CRITICAL"
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
|
||||
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4
|
||||
with:
|
||||
sarif_file: "trivy-image-results.sarif"
|
||||
|
||||
@@ -1 +1 @@
|
||||
24.21.0
|
||||
24.22.1
|
||||
|
||||
59
CHANGELOG.md
59
CHANGELOG.md
@@ -22,6 +22,65 @@ Code v99.99.999
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- `--disable-file-cache` keeps workspace files out of the browser cache. It
|
||||
stops the webview service worker from storing them in Cache Storage and
|
||||
serves them from `/vscode-remote-resource` with `Cache-Control: no-store`.
|
||||
Extension files stay cached.
|
||||
|
||||
## [4.144.0](https://github.com/coder/code-server/releases/tag/v4.144.0) - 2026-10-29
|
||||
|
||||
Code v1.144.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to Code 1.144.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- `--socket-fd` now works: the inherited socket is passed on to the process
|
||||
that listens, and the address is logged as `fd:<n>`. Previously code-server
|
||||
failed with `listen EEXIST` or `Server has no address`.
|
||||
- The cookie domain was not being set against the shared root host of proxy
|
||||
domains when proxy domains contained template variables like `{{port}}`,
|
||||
resulting in having to sign in multiple times per domain instead of only once
|
||||
as originally intended.
|
||||
- When doing the web socket origin check, if the host does not already contain a
|
||||
port, fall back to `X-Forwarded-Port`.
|
||||
- Fix default ports not matching in the web socket origin check (for example
|
||||
`https://coder.com` will now match `https://coder.com:443`).
|
||||
|
||||
## [4.143.1](https://github.com/coder/code-server/releases/tag/v4.143.1) - 2026-10-23
|
||||
|
||||
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
|
||||
|
||||
@@ -101,6 +101,14 @@ function update_csp() {
|
||||
echo "Calculated hash as $hash"
|
||||
# Use octothorpe as a delimiter since the hash may contain a slash.
|
||||
sed -i.bak "s#'sha256-[^']\+'#'sha256-$hash'#" "$file"
|
||||
# For the web worker extension host iframe, there is a matching sha in the
|
||||
# web server.
|
||||
if [[ $file == */webWorkerExtensionHostIframe.html ]] ; then
|
||||
quilt add ./lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
sed -i.bak \
|
||||
"s#webWorkerExtensionHostIframeScriptSHA = 'sha256-[^']\+'#webWorkerExtensionHostIframeScriptSHA = 'sha256-$hash'#" \
|
||||
./lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
fi
|
||||
done
|
||||
|
||||
quilt refresh
|
||||
|
||||
@@ -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.56.0
|
||||
version: 3.58.0
|
||||
|
||||
# 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.141.0
|
||||
appVersion: 4.144.0
|
||||
|
||||
@@ -4,8 +4,13 @@ metadata:
|
||||
name: {{ include "code-server.fullname" . }}
|
||||
labels:
|
||||
{{- include "code-server.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- with .Values.service.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
loadBalancerClass: {{ .Values.service.loadBalancerClass }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
|
||||
@@ -6,7 +6,7 @@ replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: codercom/code-server
|
||||
tag: '4.141.0'
|
||||
tag: '4.144.0'
|
||||
pullPolicy: Always
|
||||
|
||||
# Specifies one or more secrets to be used when pulling images from a
|
||||
@@ -48,6 +48,8 @@ priorityClassName: ""
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
loadBalancerClass: null
|
||||
annotations: {}
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
Submodule lib/vscode updated: 2a59476c9b...2c33b50b16
280
package-lock.json
generated
280
package-lock.json
generated
@@ -11,7 +11,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@coder/logger": "^3.0.1",
|
||||
"argon2": "^0.44.0",
|
||||
"argon2": "^0.45.1",
|
||||
"compression": "^1.7.4",
|
||||
"cookie": "^1.1.1",
|
||||
"cookie-parser": "^1.4.6",
|
||||
@@ -35,7 +35,7 @@
|
||||
"code-server": "out/node/entry.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.0",
|
||||
"@eslint/compat": "^2.1.1",
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.12.0",
|
||||
"@types/compression": "^1.7.3",
|
||||
@@ -170,19 +170,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/compat": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.1.tgz",
|
||||
"integrity": "sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.1.1.tgz",
|
||||
"integrity": "sha512-rMcy8GSrwNzcISX/BlTDY/GLB4eCopEuy9woIls3To+15OLxykZrxxq+WUcylCPCQ6F4MujjBM1DX5V1aqI3Vw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.17.0"
|
||||
"@eslint/core": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.40 || 9"
|
||||
"eslint": "^8.40 || 9 || 10"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"eslint": {
|
||||
@@ -190,6 +190,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/compat/node_modules/@eslint/core": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
|
||||
"integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
|
||||
@@ -269,9 +282,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
|
||||
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
|
||||
"integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -754,13 +767,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
|
||||
"integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
|
||||
"version": "24.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.2.tgz",
|
||||
"integrity": "sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.18.0"
|
||||
"undici-types": ">=7.24.0 <7.24.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pem": {
|
||||
@@ -857,17 +870,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz",
|
||||
"integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.72.1.tgz",
|
||||
"integrity": "sha512-5CokTWXpmbylfFabsbvHC0CAw3XLaGnoa+nFJX5FR592h/LoZsENUE6p/rg5xvkKrFEXz6pYmgI29AgXc2N3BQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@typescript-eslint/scope-manager": "8.69.0",
|
||||
"@typescript-eslint/type-utils": "8.69.0",
|
||||
"@typescript-eslint/utils": "8.69.0",
|
||||
"@typescript-eslint/visitor-keys": "8.69.0",
|
||||
"@typescript-eslint/scope-manager": "8.72.1",
|
||||
"@typescript-eslint/type-utils": "8.72.1",
|
||||
"@typescript-eslint/utils": "8.72.1",
|
||||
"@typescript-eslint/visitor-keys": "8.72.1",
|
||||
"ignore": "^7.0.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
@@ -880,15 +893,15 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.69.0",
|
||||
"@typescript-eslint/parser": "^8.72.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
|
||||
"version": "7.0.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz",
|
||||
"integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==",
|
||||
"version": "7.0.14",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.14.tgz",
|
||||
"integrity": "sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -896,16 +909,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz",
|
||||
"integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.72.1.tgz",
|
||||
"integrity": "sha512-ZGwZP4OCfyA0AQTpEAMWz+rtX01DRhQWW5hB0ucKDEIX5U7jdmPSaMx94rQfaPAQzIYz2BimOgKOJtjfpRFQ9g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.69.0",
|
||||
"@typescript-eslint/types": "8.69.0",
|
||||
"@typescript-eslint/typescript-estree": "8.69.0",
|
||||
"@typescript-eslint/visitor-keys": "8.69.0",
|
||||
"@typescript-eslint/scope-manager": "8.72.1",
|
||||
"@typescript-eslint/types": "8.72.1",
|
||||
"@typescript-eslint/typescript-estree": "8.72.1",
|
||||
"@typescript-eslint/visitor-keys": "8.72.1",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -921,14 +934,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz",
|
||||
"integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.72.1.tgz",
|
||||
"integrity": "sha512-fAuVMkwdO/huI8nyo/WKnNKf6Gag93S56Rh3Ts5mGcavwSdaN8tRg1gCeIGX8PF+nzp1BjGfO4gHhGzW1J6jTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.69.0",
|
||||
"@typescript-eslint/types": "^8.69.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.72.1",
|
||||
"@typescript-eslint/types": "^8.72.1",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -943,14 +956,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz",
|
||||
"integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.72.1.tgz",
|
||||
"integrity": "sha512-lC/t6eMCZZQAAKZEYGL6RDVSuFehpdmMT6h+nJIjIa6oylN/PwDgDVtEIbB7O9xFfZYtZAYLoLlDNWKJhtF+uQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.69.0",
|
||||
"@typescript-eslint/visitor-keys": "8.69.0"
|
||||
"@typescript-eslint/types": "8.72.1",
|
||||
"@typescript-eslint/visitor-keys": "8.72.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -961,9 +974,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz",
|
||||
"integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.72.1.tgz",
|
||||
"integrity": "sha512-e4D5R5vpeAEPBxT2BAzsFQL3sbwyeeeo5+aczgNSRK1V734jE7pTqaGFU+fXapWEQwnZbpFaTn32+Z8DwS6OTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -978,15 +991,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz",
|
||||
"integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.72.1.tgz",
|
||||
"integrity": "sha512-iY2wlmyrXJmx4yxUGP3aYCFF3cA/6ShddOKmLU2dx7LnEykbAM8WThlxZEfd1NddqceF6eJmZUayxx9oKIYNlg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.69.0",
|
||||
"@typescript-eslint/typescript-estree": "8.69.0",
|
||||
"@typescript-eslint/utils": "8.69.0",
|
||||
"@typescript-eslint/types": "8.72.1",
|
||||
"@typescript-eslint/typescript-estree": "8.72.1",
|
||||
"@typescript-eslint/utils": "8.72.1",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
@@ -1003,9 +1016,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz",
|
||||
"integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.72.1.tgz",
|
||||
"integrity": "sha512-LmE5IhQet1BWOWEXqBrVtBPsMAOQ6Nzk35d+WLh3mk4EUF33sqlfxjio1MdYeSvKSG5skactKKuixBIKXhL4Rw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1017,16 +1030,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz",
|
||||
"integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.72.1.tgz",
|
||||
"integrity": "sha512-DAlUoUV93hIvrtIQLwCbmZQYVZwOMhiHJrOVUUIWicFZaIYjTRqlY3I/NZevfkLmSqkNHRu2qYDcq9lrn16oOQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.69.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.69.0",
|
||||
"@typescript-eslint/types": "8.69.0",
|
||||
"@typescript-eslint/visitor-keys": "8.69.0",
|
||||
"@typescript-eslint/project-service": "8.72.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.72.1",
|
||||
"@typescript-eslint/types": "8.72.1",
|
||||
"@typescript-eslint/visitor-keys": "8.72.1",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
@@ -1084,16 +1097,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz",
|
||||
"integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.72.1.tgz",
|
||||
"integrity": "sha512-5v5liypurJBFHCBNqh/RjsymAD+VWcE0djuGY/BUqp5fC3Qn+luWDEksjuTtWjPn6i5zQlUtkZCRG/CYG0yCkA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.69.0",
|
||||
"@typescript-eslint/types": "8.69.0",
|
||||
"@typescript-eslint/typescript-estree": "8.69.0"
|
||||
"@typescript-eslint/scope-manager": "8.72.1",
|
||||
"@typescript-eslint/types": "8.72.1",
|
||||
"@typescript-eslint/typescript-estree": "8.72.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1108,13 +1121,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz",
|
||||
"integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.72.1.tgz",
|
||||
"integrity": "sha512-SB8xqipSzZHUePCCLNeYxqnxq83X61/qzNhjQGbTfjxGZIeOEP7tBgWYX05Tcd6CgE02WdTJnh5b8kMZJ/+bnQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.69.0",
|
||||
"@typescript-eslint/types": "8.72.1",
|
||||
"eslint-visitor-keys": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1526,15 +1539,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argon2": {
|
||||
"version": "0.44.0",
|
||||
"resolved": "https://registry.npmjs.org/argon2/-/argon2-0.44.0.tgz",
|
||||
"integrity": "sha512-zHPGN3S55sihSQo0dBbK0A5qpi2R31z7HZDZnry3ifOyj8bZZnpZND2gpmhnRGO1V/d555RwBqIK5W4Mrmv3ig==",
|
||||
"version": "0.45.1",
|
||||
"resolved": "https://registry.npmjs.org/argon2/-/argon2-0.45.1.tgz",
|
||||
"integrity": "sha512-skm+/WCjkGqCQxF7FG1LuZXM5yvbFjgbfiCGsud2oLgaDhh6b6dbH0b1EkghbM+xx4Bj8Ape+KKgixoIlWZicQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@phc/format": "^1.0.0",
|
||||
"cross-env": "^10.0.0",
|
||||
"node-addon-api": "^8.5.0",
|
||||
"cross-env": "^10.1.0",
|
||||
"node-addon-api": "^8.9.0",
|
||||
"node-gyp-build": "^4.8.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1545,6 +1558,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/array-buffer-byte-length": {
|
||||
@@ -1726,27 +1740,27 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/basic-ftp": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz",
|
||||
"integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-6.2.3.tgz",
|
||||
"integrity": "sha512-T7GYtQ2eKJUN5YORG7A8u2WfB9JMN0a4/wl3MI64qq2qTRfa3FXzoNq0DDojZDkDyStcL+TkfKsz4JHEZx5kGQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
|
||||
"integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz",
|
||||
"integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "^3.1.2",
|
||||
"content-type": "^2.0.0",
|
||||
"content-type": "^2.1.0",
|
||||
"debug": "^4.4.3",
|
||||
"http-errors": "^2.0.1",
|
||||
"iconv-lite": "^0.7.2",
|
||||
"iconv-lite": "^0.7.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"qs": "^6.15.2",
|
||||
"qs": "^6.16.1",
|
||||
"raw-body": "^3.0.2",
|
||||
"type-is": "^2.1.0"
|
||||
},
|
||||
@@ -1759,9 +1773,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/content-type": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
|
||||
"integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
|
||||
"integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -3245,9 +3259,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.2.tgz",
|
||||
"integrity": "sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -3453,9 +3467,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "17.6.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz",
|
||||
"integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==",
|
||||
"version": "17.13.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz",
|
||||
"integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3675,9 +3689,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "26.3.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.1.tgz",
|
||||
"integrity": "sha512-txQqd5EULsqEh9OJqRH15aCaOuy/nLJyhw5EHCSKLKJE1aBbb3Zve2+uQIxgWhPm1QqUQoWyQBm2kfmmIrzkcQ==",
|
||||
"version": "26.5.11",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.5.11.tgz",
|
||||
"integrity": "sha512-Wc0klBPKxqZ2tL2qdAnF8xvvnWgr1IMGSY2ikTiAvaFVbz7xiFARtkoU4RidBDw1SyziGROp0qxu6qnJ7l2Wug==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -3694,7 +3708,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"typescript": "^5 || ^6"
|
||||
"typescript": "^5 || ^6 || ^7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
@@ -3703,9 +3717,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
||||
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
|
||||
"integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
@@ -3777,9 +3791,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.7.2",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz",
|
||||
"integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==",
|
||||
"version": "10.7.5",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.5.tgz",
|
||||
"integrity": "sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
@@ -4270,9 +4284,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.1.tgz",
|
||||
"integrity": "sha512-28R/k+NAjeuf7+CKlTxWZVExJGwVVLwY06DgEnOMz2gEpfNkDcD7QvyiVPT0xy0XXhU8vHsd4Ot42OOPdJG7dQ==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.5.0.tgz",
|
||||
"integrity": "sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -4285,12 +4299,28 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
"argparse": "^3.0.3"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-yaml/node_modules/argparse": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.4.tgz",
|
||||
"integrity": "sha512-fwWK3Zq22l4XJJjx5mcBHGikIk+hJqO+32dPm0Jur7+rtG5x1scOjSfdT9ZKeWHPpsya/l0HHK4tDImBkTrtvA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/puzrin"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nodeca"
|
||||
}
|
||||
],
|
||||
"license": "PSF-2.0"
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
@@ -4885,9 +4915,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz",
|
||||
"integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==",
|
||||
"version": "8.9.2",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.9.2.tgz",
|
||||
"integrity": "sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
@@ -5366,9 +5396,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.16.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz",
|
||||
"integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==",
|
||||
"version": "6.16.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.16.1.tgz",
|
||||
"integrity": "sha512-5Px6J7rfHBAGUhNQ3es4YzcOdBBw0SDcVtThJml4RdnKw4tKs2epA0kPZ+K8X+WiHktT93RHVcQ/3ym5aTCgtg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.1",
|
||||
@@ -6373,16 +6403,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.69.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.69.0.tgz",
|
||||
"integrity": "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==",
|
||||
"version": "8.72.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.72.1.tgz",
|
||||
"integrity": "sha512-3Li9FfPmQp45nxEtFD1ZCrYFI3cYK5kpyNtmm1H7lMagm8u9sy6PTjy3ytwQZs7KNukOyKFHAZ6z6GjYFeaeXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.69.0",
|
||||
"@typescript-eslint/parser": "8.69.0",
|
||||
"@typescript-eslint/typescript-estree": "8.69.0",
|
||||
"@typescript-eslint/utils": "8.69.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.72.1",
|
||||
"@typescript-eslint/parser": "8.72.1",
|
||||
"@typescript-eslint/typescript-estree": "8.72.1",
|
||||
"@typescript-eslint/utils": "8.72.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -6416,9 +6446,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||
"version": "7.24.6",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
|
||||
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"main": "out/node/entry.js",
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.0",
|
||||
"@eslint/compat": "^2.1.1",
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.12.0",
|
||||
"@types/compression": "^1.7.3",
|
||||
@@ -67,7 +67,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@coder/logger": "^3.0.1",
|
||||
"argon2": "^0.44.0",
|
||||
"argon2": "^0.45.1",
|
||||
"compression": "^1.7.4",
|
||||
"cookie": "^1.1.1",
|
||||
"cookie-parser": "^1.4.6",
|
||||
@@ -90,6 +90,9 @@
|
||||
"resolutions": {
|
||||
"@types/node": "24.x"
|
||||
},
|
||||
"overrides": {
|
||||
"basic-ftp": "^6.2.1"
|
||||
},
|
||||
"bin": {
|
||||
"code-server": "out/node/entry.js"
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ Index: code-server/lib/vscode/src/vs/base/common/network.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/base/common/network.ts
|
||||
+++ code-server/lib/vscode/src/vs/base/common/network.ts
|
||||
@@ -256,7 +256,9 @@ class RemoteAuthoritiesImpl {
|
||||
@@ -262,7 +262,9 @@ class RemoteAuthoritiesImpl {
|
||||
return URI.from({
|
||||
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
|
||||
authority: `${host}:${port}`,
|
||||
|
||||
@@ -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
|
||||
@@ -283,6 +283,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-Q3Tfcw0dGu/YD4dGBrRqBeOnmRMAH8HbKxArK4YSXBc=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
|
||||
+ content="default-src 'none'; script-src 'sha256-BmcTt6YZr75RujSQ3gF/UQL77e1RrOx62jNeikpwtxc=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
|
||||
|
||||
<!-- Disable pinch zooming -->
|
||||
<meta name="viewport"
|
||||
@@ -24,3 +24,16 @@ Index: code-server/lib/vscode/src/vs/workbench/services/extensions/worker/webWor
|
||||
connect-src 'self' https: wss: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*;"/>
|
||||
</head>
|
||||
<body>
|
||||
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
|
||||
@@ -114,7 +114,7 @@ const APP_ROOT = dirname(FileAccess.asFi
|
||||
const STATIC_PATH = `/static`;
|
||||
const CALLBACK_PATH = `/callback`;
|
||||
const WEB_EXTENSION_PATH = `/web-extension-resource`;
|
||||
-const webWorkerExtensionHostIframeScriptSHA = 'sha256-daEgfo2VIXpx2Np71KqCCbkeQwv+68vPrx54XRcbdcs=';
|
||||
+const webWorkerExtensionHostIframeScriptSHA = 'sha256-gfjiOVjAlxqrivZAfTq2d83mOaz0fnAxbGaFpj5IjD8=';
|
||||
|
||||
/**
|
||||
* Substitutes the `{{...}}` placeholders of a workbench template. Placeholders must only ever
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
188
patches/disable-file-cache.diff
Normal file
188
patches/disable-file-cache.diff
Normal file
@@ -0,0 +1,188 @@
|
||||
Add option to keep workspace files out of the browser cache
|
||||
|
||||
This patch adds support for a new CLI flag called `--disable-file-cache`. When
|
||||
set, workspace files are not stored on the client disk through two caches:
|
||||
|
||||
- The webview resource loader sends no ETag for a resource outside the
|
||||
webview's own extension, and the webview service worker only stores responses
|
||||
that have an ETag, so these resources stay out of Cache Storage.
|
||||
- `/vscode-remote-resource` responds with `Cache-Control: no-store` for files
|
||||
outside the extension directories.
|
||||
|
||||
Extension resources keep their ETags so webviews still load extension code from
|
||||
the cache. The default value for this is `false`.
|
||||
|
||||
To test, start code-server with `--disable-file-cache`, open a Markdown file
|
||||
that embeds an image from the workspace, and open the preview. In the browser
|
||||
dev tools, the `vscode-resource-cache-*` Cache Storage of the webview service
|
||||
worker should have no entry for the image, and a request to
|
||||
`/vscode-remote-resource?path=<image>` should respond with
|
||||
`Cache-Control: no-store`.
|
||||
|
||||
Index: code-server/lib/vscode/src/vs/server/node/remoteExtensionHostAgentServer.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/remoteExtensionHostAgentServer.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/remoteExtensionHostAgentServer.ts
|
||||
@@ -177,15 +177,14 @@ class RemoteExtensionHostAgentServer ext
|
||||
|
||||
const requestOrigin = req.headers['origin'];
|
||||
const responseHeaders = getRemoteResourceResponseHeaders(requestOrigin, origin => this._webEndpointOriginChecker.matches(origin));
|
||||
- if (this._environmentService.isBuilt) {
|
||||
- if (isEqualOrParent(filePath, this._environmentService.builtinExtensionsPath, !platform.isLinux)
|
||||
- || isEqualOrParent(filePath, this._environmentService.extensionsPath, !platform.isLinux)
|
||||
- ) {
|
||||
- responseHeaders['Cache-Control'] = 'public, max-age=31536000';
|
||||
- }
|
||||
+ const isExtensionFile = isEqualOrParent(filePath, this._environmentService.builtinExtensionsPath, !platform.isLinux)
|
||||
+ || isEqualOrParent(filePath, this._environmentService.extensionsPath, !platform.isLinux);
|
||||
+ if (this._environmentService.isBuilt && isExtensionFile) {
|
||||
+ responseHeaders['Cache-Control'] = 'public, max-age=31536000';
|
||||
}
|
||||
|
||||
- return serveFile(filePath, CacheControl.ETAG, this._logService, req, res, responseHeaders);
|
||||
+ const cacheControl = this._environmentService.args['disable-file-cache'] && !isExtensionFile ? CacheControl.NO_CACHING : CacheControl.ETAG;
|
||||
+ return serveFile(filePath, cacheControl, this._logService, req, res, responseHeaders);
|
||||
}
|
||||
|
||||
// workbench web UI
|
||||
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
|
||||
@@ -37,6 +37,7 @@ export const serverOptions: OptionDescri
|
||||
'auth': { type: 'string' },
|
||||
'disable-file-downloads': { type: 'boolean' },
|
||||
'disable-file-uploads': { type: 'boolean' },
|
||||
+ 'disable-file-cache': { type: 'boolean' },
|
||||
'disable-getting-started-override': { type: 'boolean' },
|
||||
'locale': { type: 'string' },
|
||||
'link-protection-trusted-domains': { type: 'string[]' },
|
||||
@@ -139,6 +140,7 @@ export interface ServerParsedArgs {
|
||||
'auth'?: string;
|
||||
'disable-file-downloads'?: boolean;
|
||||
'disable-file-uploads'?: boolean;
|
||||
+ 'disable-file-cache'?: boolean;
|
||||
'disable-getting-started-override'?: boolean,
|
||||
'locale'?: string
|
||||
'link-protection-trusted-domains'?: string[],
|
||||
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
@@ -442,6 +442,7 @@ export class WebClientServer {
|
||||
userDataPath: this._environmentService.userDataPath,
|
||||
isEnabledFileDownloads: !this._environmentService.args['disable-file-downloads'],
|
||||
isEnabledFileUploads: !this._environmentService.args['disable-file-uploads'],
|
||||
+ isEnabledFileCache: !this._environmentService.args['disable-file-cache'],
|
||||
isEnabledCoderGettingStarted: !this._environmentService.args['disable-getting-started-override'],
|
||||
_wrapWebWorkerExtHostInIframe,
|
||||
developmentOptions: { enableSmokeTestDriver: this._environmentService.args['enable-smoke-test-driver'] ? true : undefined, logLevel: this._logService.getLevel() },
|
||||
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
|
||||
@@ -330,6 +330,11 @@ export interface IWorkbenchConstructionO
|
||||
readonly isEnabledFileUploads?: boolean
|
||||
|
||||
/**
|
||||
+ * Whether the browser may cache workspace files.
|
||||
+ */
|
||||
+ readonly isEnabledFileCache?: boolean
|
||||
+
|
||||
+ /**
|
||||
* Whether to use Coder's custom Getting Started text.
|
||||
*/
|
||||
readonly isEnabledCoderGettingStarted?: boolean
|
||||
Index: code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
||||
@@ -15,7 +15,7 @@ import { Lazy } from '../../../../base/c
|
||||
import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { COI, Schemas } from '../../../../base/common/network.js';
|
||||
import { observableValue } from '../../../../base/common/observable.js';
|
||||
-import { isEqualAuthority } from '../../../../base/common/resources.js';
|
||||
+import { isEqualAuthority, isEqualOrParent } from '../../../../base/common/resources.js';
|
||||
import { listenStream } from '../../../../base/common/stream.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
@@ -32,6 +32,7 @@ import { INotificationService } from '..
|
||||
import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js';
|
||||
import { ITunnelService } from '../../../../platform/tunnel/common/tunnel.js';
|
||||
import { WebviewPortMappingManager } from '../../../../platform/webview/common/webviewPortMapping.js';
|
||||
+import { IBrowserWorkbenchEnvironmentService } from '../../../services/environment/browser/environmentService.js';
|
||||
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js';
|
||||
import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js';
|
||||
import { decodeAuthority, webviewGenericCspSource, webviewRootResourceAuthority } from '../common/webview.js';
|
||||
@@ -864,6 +865,8 @@ export class WebviewElement extends Disp
|
||||
const rangeHeader = range
|
||||
? `bytes ${range.start}-${rangeEnd}/${result.size}`
|
||||
: undefined;
|
||||
+ // The service worker only stores responses that have an etag.
|
||||
+ const etag = this._isFileCacheAllowed(uri) ? result.etag : undefined;
|
||||
if (WebviewElement._supportsTransferableStreams.value) {
|
||||
let controller: ReadableStreamDefaultController<Uint8Array<ArrayBuffer>> | undefined;
|
||||
let closed = false;
|
||||
@@ -915,7 +918,7 @@ export class WebviewElement extends Disp
|
||||
status: range ? 206 : 200,
|
||||
path: uri.path,
|
||||
mime: result.mimeType,
|
||||
- etag: result.etag,
|
||||
+ etag,
|
||||
mtime: result.mtime,
|
||||
range: rangeHeader,
|
||||
stream,
|
||||
@@ -927,7 +930,7 @@ export class WebviewElement extends Disp
|
||||
status: range ? 206 : 200,
|
||||
path: uri.path,
|
||||
mime: result.mimeType,
|
||||
- etag: result.etag,
|
||||
+ etag,
|
||||
mtime: result.mtime,
|
||||
range: rangeHeader,
|
||||
});
|
||||
@@ -984,6 +987,14 @@ export class WebviewElement extends Disp
|
||||
});
|
||||
}
|
||||
|
||||
+ private _isFileCacheAllowed(uri: URI): boolean {
|
||||
+ if ((this._environmentService as IBrowserWorkbenchEnvironmentService).isEnabledFileCache) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ const extensionLocation = this.extension?.location;
|
||||
+ return !!extensionLocation && isEqualOrParent(uri, extensionLocation);
|
||||
+ }
|
||||
+
|
||||
private async localLocalhost(id: string, origin: string) {
|
||||
const authority = this._environmentService.remoteAuthority;
|
||||
const resolveAuthority = authority ? await this._remoteAuthorityResolverService.resolveAuthority(authority) : undefined;
|
||||
Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
|
||||
@@ -49,6 +49,11 @@ export interface IBrowserWorkbenchEnviro
|
||||
readonly isEnabledFileUploads?: boolean;
|
||||
|
||||
/**
|
||||
+ * Allow the browser to cache workspace files.
|
||||
+ */
|
||||
+ readonly isEnabledFileCache?: boolean;
|
||||
+
|
||||
+ /**
|
||||
* Enable Coder's custom getting started text.
|
||||
*/
|
||||
readonly isEnabledCoderGettingStarted?: boolean;
|
||||
@@ -145,6 +150,13 @@ export class BrowserWorkbenchEnvironment
|
||||
return this.options.isEnabledFileUploads;
|
||||
}
|
||||
|
||||
+ get isEnabledFileCache(): boolean {
|
||||
+ if (typeof this.options.isEnabledFileCache === "undefined") {
|
||||
+ throw new Error('isEnabledFileCache was not provided to the browser');
|
||||
+ }
|
||||
+ return this.options.isEnabledFileCache;
|
||||
+ }
|
||||
+
|
||||
get isEnabledCoderGettingStarted(): boolean {
|
||||
if (typeof this.options.isEnabledCoderGettingStarted === "undefined") {
|
||||
throw new Error('isEnabledCoderGettingStarted was not provided to the browser');
|
||||
@@ -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)));
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -19,7 +19,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/bro
|
||||
import { renderFormattedText } from '../../../../base/browser/formattedTextRenderer.js';
|
||||
import { status } from '../../../../base/browser/ui/aria/aria.js';
|
||||
import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js';
|
||||
@@ -55,7 +55,7 @@ import { IRecentFolder, IRecentWorkspace
|
||||
@@ -56,7 +56,7 @@ import { IRecentFolder, IRecentWorkspace
|
||||
import { OpenRecentAction } from '../../../browser/actions/windowActions.js';
|
||||
import { OpenFileFolderAction, OpenFolderAction, OpenFolderViaWorkspaceAction } from '../../../browser/actions/workspaceActions.js';
|
||||
import { EditorPane } from '../../../browser/parts/editor/editorPane.js';
|
||||
@@ -28,7 +28,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/bro
|
||||
import { IEditorOpenContext, IEditorSerializer } from '../../../common/editor.js';
|
||||
import { IWebviewElement, IWebviewService } from '../../webview/browser/webview.js';
|
||||
import './gettingStartedColors.js';
|
||||
@@ -930,6 +930,72 @@ export class GettingStartedPage extends
|
||||
@@ -944,6 +944,72 @@ export class GettingStartedPage extends
|
||||
$('p.subtitle.description', {}, localize({ key: 'gettingStarted.editingEvolved', comment: ['Shown as subtitle on the Welcome page.'] }, "Editing evolved"))
|
||||
);
|
||||
|
||||
@@ -101,7 +101,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/bro
|
||||
const leftColumn = $('.categories-column.categories-column-left', {},);
|
||||
const rightColumn = $('.categories-column.categories-column-right', {},);
|
||||
|
||||
@@ -980,6 +1046,9 @@ export class GettingStartedPage extends
|
||||
@@ -1000,6 +1066,9 @@ export class GettingStartedPage extends
|
||||
recentList.setLimit(5);
|
||||
reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
|
||||
}
|
||||
@@ -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');
|
||||
@@ -169,7 +169,7 @@ 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
|
||||
@@ -64,6 +64,7 @@ import { IOpenerService } from '../../pl
|
||||
@@ -65,6 +65,7 @@ import { IOpenerService } from '../../pl
|
||||
import { mixin, safeStringify } from '../../base/common/objects.js';
|
||||
import { IndexedDB } from '../../base/browser/indexedDB.js';
|
||||
import { WebFileSystemAccess } from '../../platform/files/browser/webFileSystemAccess.js';
|
||||
@@ -177,7 +177,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
import { IProgressService } from '../../platform/progress/common/progress.js';
|
||||
import { DelayedLogChannel } from '../services/output/common/delayedLogChannel.js';
|
||||
import { dirname, joinPath } from '../../base/common/resources.js';
|
||||
@@ -140,6 +141,9 @@ export class BrowserMain extends Disposa
|
||||
@@ -141,6 +142,9 @@ export class BrowserMain extends Disposa
|
||||
// Startup
|
||||
const instantiationService = workbench.startup();
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Index: code-server/lib/vscode/src/vs/platform/extensionResourceLoader/common/ext
|
||||
import { TargetPlatform } from '../../extensions/common/extensions.js';
|
||||
import { ExtensionGalleryResourceType, getExtensionGalleryManifestResourceUri, IExtensionGalleryManifest, IExtensionGalleryManifestService } from '../../extensionManagement/common/extensionGalleryManifest.js';
|
||||
import { ILogService } from '../../log/common/log.js';
|
||||
@@ -163,9 +162,9 @@ export abstract class AbstractExtensionR
|
||||
@@ -167,9 +166,9 @@ export abstract class AbstractExtensionR
|
||||
}
|
||||
|
||||
protected _isWebExtensionResourceEndPoint(uri: URI): boolean {
|
||||
|
||||
@@ -10,7 +10,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/extensions/common/extens
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts
|
||||
@@ -321,6 +321,10 @@ function extensionDescriptionArrayToMap(
|
||||
@@ -324,6 +324,10 @@ function extensionDescriptionArrayToMap(
|
||||
}
|
||||
|
||||
export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {
|
||||
|
||||
@@ -104,7 +104,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
@@ -105,6 +105,10 @@ import { McpManagementChannel } from '..
|
||||
@@ -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';
|
||||
@@ -115,7 +115,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
import { SANDBOX_HELPER_CHANNEL_NAME, SandboxHelperChannel } from '../../platform/sandbox/common/sandboxHelperIpc.js';
|
||||
import { SandboxHelperService } from '../../platform/sandbox/node/sandboxHelper.js';
|
||||
|
||||
@@ -238,6 +242,21 @@ export async function setupServerService
|
||||
@@ -244,6 +248,21 @@ export async function setupServerService
|
||||
services.set(IMcpGatewayService, new SyncDescriptor(McpGatewayService));
|
||||
|
||||
const instantiationService: IInstantiationService = new InstantiationService(services);
|
||||
@@ -137,7 +137,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
services.set(ILanguagePackService, instantiationService.createInstance(NativeLanguagePackService));
|
||||
|
||||
const ptyHostStarter = instantiationService.createInstance(
|
||||
@@ -420,6 +439,7 @@ export async function setupServerService
|
||||
@@ -446,6 +465,7 @@ export async function setupServerService
|
||||
|
||||
const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService), disposables);
|
||||
socketServer.registerChannel('languagePacks', languagePackChannel);
|
||||
@@ -179,7 +179,7 @@ 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
|
||||
@@ -33,6 +33,7 @@ import { ISignService } from '../../plat
|
||||
@@ -34,6 +34,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';
|
||||
@@ -187,7 +187,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
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
|
||||
@@ -488,7 +489,7 @@ export class BrowserMain extends Disposa
|
||||
serviceCollection.set(IWorkbenchConfigurationService, service);
|
||||
return service;
|
||||
}),
|
||||
@@ -196,7 +196,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
serviceCollection.set(IStorageService, service);
|
||||
return service;
|
||||
})
|
||||
@@ -604,7 +605,21 @@ export class BrowserMain extends Disposa
|
||||
@@ -610,7 +611,21 @@ export class BrowserMain extends Disposa
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,3 +27,4 @@ app-name.diff
|
||||
remote-storage.diff
|
||||
remote-secret-storage.diff
|
||||
csp-hashes.diff
|
||||
disable-file-cache.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;
|
||||
|
||||
|
||||
@@ -111,9 +111,14 @@ export const createApp = async (args: DefaultedArgs): Promise<App> => {
|
||||
*
|
||||
* The address might be a URL or it might be a pipe or socket path.
|
||||
*/
|
||||
export const ensureAddress = (server: http.Server, protocol: string): URL | string => {
|
||||
export const ensureAddress = (server: http.Server, protocol: string, socketFd?: number): URL | string => {
|
||||
const addr = server.address()
|
||||
|
||||
// Node reports no address for a Unix socket adopted by fd.
|
||||
if (!addr && typeof socketFd === "number") {
|
||||
return `fd:${socketFd}`
|
||||
}
|
||||
|
||||
if (!addr) {
|
||||
throw new Error("Server has no address")
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -51,6 +51,7 @@ export interface UserProvidedCodeArgs {
|
||||
"disable-update-check"?: boolean
|
||||
"disable-file-downloads"?: boolean
|
||||
"disable-file-uploads"?: boolean
|
||||
"disable-file-cache"?: boolean
|
||||
"disable-workspace-trust"?: boolean
|
||||
"disable-getting-started-override"?: boolean
|
||||
"disable-proxy"?: boolean
|
||||
@@ -193,6 +194,10 @@ export const options: Options<Required<UserProvidedArgs>> = {
|
||||
type: "boolean",
|
||||
description: "Disable file uploads.",
|
||||
},
|
||||
"disable-file-cache": {
|
||||
type: "boolean",
|
||||
description: "Keep workspace files out of the browser cache.",
|
||||
},
|
||||
"disable-workspace-trust": {
|
||||
type: "boolean",
|
||||
description: "Disable Workspace Trust feature. This switch only affects the current session.",
|
||||
@@ -466,7 +471,7 @@ export const parse = (
|
||||
}
|
||||
|
||||
if (option.path) {
|
||||
value = path.resolve(value)
|
||||
value = path.resolve(expandTilde(value))
|
||||
}
|
||||
|
||||
switch (option.type) {
|
||||
|
||||
@@ -235,7 +235,16 @@ export const getCookieDomain = (host: string, proxyDomains: string[]): string |
|
||||
return undefined
|
||||
}
|
||||
|
||||
proxyDomains.forEach((domain) => {
|
||||
proxyDomains.forEach((proxyDomain) => {
|
||||
// Proxy domains are patterns like `{{port}}.domain.tld` or
|
||||
// `prefix-{{port}}-suffix.domain.tld` so use the part after the label that
|
||||
// contains the port.
|
||||
const portIndex = proxyDomain.indexOf("{{port}}")
|
||||
const domain = portIndex === -1 ? proxyDomain : proxyDomain.substring(proxyDomain.indexOf(".", portIndex) + 1)
|
||||
// Skip patterns we cannot turn into a domain, like `{{port}}.{{host}}`.
|
||||
if (!domain || domain.includes("{{")) {
|
||||
return
|
||||
}
|
||||
if (host.endsWith(domain) && domain.length < host.length) {
|
||||
host = domain
|
||||
}
|
||||
@@ -381,19 +390,20 @@ export function authenticateOrigin(req: express.Request): void {
|
||||
return
|
||||
}
|
||||
|
||||
let origin: string
|
||||
let originUrl: URL
|
||||
try {
|
||||
origin = new URL(originRaw).host.trim().toLowerCase()
|
||||
originUrl = new URL(originRaw)
|
||||
} catch (error) {
|
||||
throw new Error(`unable to parse malformed origin "${originRaw}"`)
|
||||
}
|
||||
const origin = originUrl.host.trim().toLowerCase()
|
||||
|
||||
const trustedOrigins = req.args["trusted-origins"] || []
|
||||
if (isTrustedOrigin(origin, trustedOrigins)) {
|
||||
return
|
||||
}
|
||||
|
||||
const host = getHost(req)
|
||||
const host = getHost(req, true)
|
||||
if (typeof host === "undefined") {
|
||||
// A missing host likely means the reverse proxy has not been configured to
|
||||
// forward the host which means we cannot perform the check. Emit an error
|
||||
@@ -403,15 +413,64 @@ export function authenticateOrigin(req: express.Request): void {
|
||||
throw new Error("no host headers found")
|
||||
}
|
||||
|
||||
if (host !== origin) {
|
||||
if (!hostMatchesOrigin(host, originUrl)) {
|
||||
throw new Error(`host "${host}" does not match origin "${origin}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const defaultPorts: { [protocol: string]: string } = {
|
||||
"http:": "80",
|
||||
"https:": "443",
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a host like `example.com:8080` or `[::1]:8080`. A non-special scheme
|
||||
* keeps the port as written instead of dropping default ports.
|
||||
*/
|
||||
function parseHost(host: string): URL | undefined {
|
||||
try {
|
||||
return new URL(`host://${host}`)
|
||||
} catch (error) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the host from the request headers matches the origin.
|
||||
*
|
||||
* This is an exact match, except that a default port (80 for http, 443 for
|
||||
* https) is the same as no port, since `example.com:443` and
|
||||
* `https://example.com` are the same origin.
|
||||
*/
|
||||
export function hostMatchesOrigin(host: string, origin: URL): boolean {
|
||||
const parsed = parseHost(host)
|
||||
if (!parsed) {
|
||||
return false
|
||||
}
|
||||
const port = parsed.port === defaultPorts[origin.protocol] ? "" : parsed.port
|
||||
return parsed.hostname === origin.hostname.toLowerCase() && port === origin.port
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the port from X-Forwarded-Port to a host that does not have one. Some
|
||||
* reverse proxies (for example nginx with `$host`) forward the host without
|
||||
* the port and send the port separately.
|
||||
*/
|
||||
function addForwardedPort(req: express.Request, host: string): string {
|
||||
const port = getFirstHeader(req, "x-forwarded-port")?.split(",")[0].trim()
|
||||
if (!port || !/^\d+$/.test(port) || parseHost(host)?.port !== "") {
|
||||
return host
|
||||
}
|
||||
return `${host}:${port}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host from headers. It will be trimmed and lowercased.
|
||||
*
|
||||
* If `withForwardedPort` is set and the host comes from X-Forwarded-Host
|
||||
* without a port, the port from X-Forwarded-Port is added.
|
||||
*/
|
||||
export function getHost(req: express.Request): string | undefined {
|
||||
export function getHost(req: express.Request, withForwardedPort = false): string | undefined {
|
||||
// Honor Forwarded if present.
|
||||
const forwardedRaw = getFirstHeader(req, "forwarded")
|
||||
if (forwardedRaw) {
|
||||
@@ -430,7 +489,8 @@ export function getHost(req: express.Request): string | undefined {
|
||||
if (xHost) {
|
||||
const firstXHost = xHost.split(",")[0]
|
||||
if (firstXHost) {
|
||||
return firstXHost.trim().toLowerCase()
|
||||
const host = firstXHost.trim().toLowerCase()
|
||||
return withForwardedPort ? addForwardedPort(req, host) : host
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ export const runCodeServer = async (
|
||||
|
||||
const app = await createApp(args)
|
||||
const protocol = args.cert ? "https" : "http"
|
||||
const serverAddress = ensureAddress(app.server, protocol)
|
||||
const serverAddress = ensureAddress(app.server, protocol, args["socket-fd"])
|
||||
const { disposeRoutes, heart } = await register(app, args)
|
||||
|
||||
logger.info(`Using config file ${args.config}`)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -8,6 +8,9 @@ import { paths } from "./util"
|
||||
|
||||
const timeoutInterval = 10000 // 10s, matches VS Code's timeouts.
|
||||
|
||||
// Fd 3 in the child is the IPC channel, so the inherited socket goes to fd 4.
|
||||
const CHILD_SOCKET_FD = 4
|
||||
|
||||
/**
|
||||
* Listen to a single message from a process. Reject if the process errors,
|
||||
* exits, or times out.
|
||||
@@ -334,13 +337,14 @@ export class ParentProcess extends Process {
|
||||
}
|
||||
|
||||
private spawn(): cp.ChildProcess {
|
||||
const socketFd = this.args?.["socket-fd"]
|
||||
return cp.fork(path.join(__dirname, "entry"), {
|
||||
env: {
|
||||
...process.env,
|
||||
CODE_SERVER_PARENT_PID: process.pid.toString(),
|
||||
NODE_EXEC_PATH: process.execPath,
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
||||
stdio: typeof socketFd === "number" ? ["pipe", "pipe", "pipe", "ipc", socketFd] : ["pipe", "pipe", "pipe", "ipc"],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -359,7 +363,8 @@ export class ParentProcess extends Process {
|
||||
this.logger,
|
||||
)
|
||||
this.logger.debug("got message", field("message", message))
|
||||
this.send(child, { type: "handshake", args: this.args })
|
||||
const args = typeof this.args["socket-fd"] === "number" ? { ...this.args, "socket-fd": CHILD_SOCKET_FD } : this.args
|
||||
this.send(child, { type: "handshake", args })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
132
test/e2e/fileCache.test.ts
Normal file
132
test/e2e/fileCache.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { Page } from "playwright"
|
||||
import { clean, getMaybeProxiedCodeServer } from "../utils/helpers"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
import { CodeServerPage } from "./models/CodeServer"
|
||||
|
||||
// A 1x1 PNG.
|
||||
const png = Buffer.from(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==",
|
||||
"base64",
|
||||
)
|
||||
|
||||
/**
|
||||
* Open a Markdown preview that embeds a PNG from the workspace and wait for
|
||||
* the image to render.
|
||||
*/
|
||||
async function previewMarkdownWithImage(codeServerPage: CodeServerPage, imageName: string): Promise<Page> {
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
await fs.writeFile(path.join(dir, imageName), png)
|
||||
const markdown = path.join(dir, `${imageName}.md`)
|
||||
await fs.writeFile(markdown, `# Preview\n\n\n`)
|
||||
await codeServerPage.openFile(markdown)
|
||||
await codeServerPage.executeCommandViaMenus("Markdown: Open Preview to the Side")
|
||||
await codeServerPage.waitForTab(`Preview ${markdown}`)
|
||||
|
||||
const image = codeServerPage.page
|
||||
.frameLocator("iframe.webview.ready")
|
||||
.frameLocator("#active-frame")
|
||||
.locator(`img[alt="workspace image"]`)
|
||||
await expect.poll(() => image.evaluate((img: HTMLImageElement) => img.naturalWidth)).toBeGreaterThan(0)
|
||||
return codeServerPage.page
|
||||
}
|
||||
|
||||
/**
|
||||
* URLs in the webview service worker's Cache Storage.
|
||||
*/
|
||||
async function cachedWebviewUrls(page: Page): Promise<string[]> {
|
||||
const frame = await (await page.locator("iframe.webview.ready").elementHandle())?.contentFrame()
|
||||
if (!frame) {
|
||||
throw new Error("webview frame not found")
|
||||
}
|
||||
return frame.evaluate(async () => {
|
||||
const urls: string[] = []
|
||||
for (const name of await caches.keys()) {
|
||||
if (name.startsWith("vscode-resource-cache-")) {
|
||||
for (const request of await (await caches.open(name)).keys()) {
|
||||
urls.push(request.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
return urls
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchRemoteResource(codeServerPage: CodeServerPage, file: string) {
|
||||
const address = await getMaybeProxiedCodeServer(codeServerPage)
|
||||
const url = new URL(`vscode-remote-resource?path=${encodeURIComponent(file)}`, address)
|
||||
return codeServerPage.page.request.get(url.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a workspace file and a file in the user extensions directory.
|
||||
*/
|
||||
async function writeResourceFiles(codeServerPage: CodeServerPage, name: string) {
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const workspaceFile = path.join(dir, `${name}-workspace.txt`)
|
||||
const extensionDir = path.join(dir, "extensions", `${name}-extension`)
|
||||
const extensionFile = path.join(extensionDir, "resource.txt")
|
||||
await fs.writeFile(workspaceFile, "workspace")
|
||||
await fs.mkdir(extensionDir, { recursive: true })
|
||||
await fs.writeFile(extensionFile, "extension")
|
||||
return { workspaceFile, extensionFile }
|
||||
}
|
||||
|
||||
describe("File cache (enabled)", ["--disable-workspace-trust"], {}, async () => {
|
||||
const testName = "file-cache-enabled"
|
||||
test.beforeAll(async () => {
|
||||
await clean(testName)
|
||||
})
|
||||
|
||||
test("should cache workspace files in the webview Cache Storage", async ({ codeServerPage }) => {
|
||||
const page = await previewMarkdownWithImage(codeServerPage, "cache-enabled.png")
|
||||
await expect
|
||||
.poll(async () => (await cachedWebviewUrls(page)).filter((url) => url.includes("cache-enabled.png")))
|
||||
.toHaveLength(1)
|
||||
})
|
||||
|
||||
test("should serve /vscode-remote-resource with an ETag and without no-store", async ({ codeServerPage }) => {
|
||||
const { workspaceFile, extensionFile } = await writeResourceFiles(codeServerPage, "enabled")
|
||||
for (const file of [workspaceFile, extensionFile]) {
|
||||
const response = await fetchRemoteResource(codeServerPage, file)
|
||||
expect(response.status()).toBe(200)
|
||||
expect(response.headers()["etag"]).toBeTruthy()
|
||||
expect(response.headers()["cache-control"] ?? "").not.toContain("no-store")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("File cache (disabled)", ["--disable-workspace-trust", "--disable-file-cache"], {}, async () => {
|
||||
const testName = "file-cache-disabled"
|
||||
test.beforeAll(async () => {
|
||||
await clean(testName)
|
||||
})
|
||||
|
||||
test("should keep workspace files out of the webview Cache Storage but cache extension files", async ({
|
||||
codeServerPage,
|
||||
}) => {
|
||||
const page = await previewMarkdownWithImage(codeServerPage, "cache-disabled.png")
|
||||
// Cached extension files show that the flag, not a cache failure, keeps the image out.
|
||||
await expect
|
||||
.poll(async () => (await cachedWebviewUrls(page)).filter((url) => url.includes("markdown-language-features")))
|
||||
.not.toHaveLength(0)
|
||||
expect((await cachedWebviewUrls(page)).filter((url) => url.includes("cache-disabled.png"))).toHaveLength(0)
|
||||
})
|
||||
|
||||
test("should serve /vscode-remote-resource with no-store for workspace files and an ETag for extension files", async ({
|
||||
codeServerPage,
|
||||
}) => {
|
||||
const { workspaceFile, extensionFile } = await writeResourceFiles(codeServerPage, "disabled")
|
||||
|
||||
const workspaceResponse = await fetchRemoteResource(codeServerPage, workspaceFile)
|
||||
expect(workspaceResponse.status()).toBe(200)
|
||||
expect(workspaceResponse.headers()["cache-control"]).toBe("no-store")
|
||||
expect(workspaceResponse.headers()["etag"]).toBeUndefined()
|
||||
|
||||
const extensionResponse = await fetchRemoteResource(codeServerPage, extensionFile)
|
||||
expect(extensionResponse.status()).toBe(200)
|
||||
expect(extensionResponse.headers()["etag"]).toBeTruthy()
|
||||
expect(extensionResponse.headers()["cache-control"] ?? "").not.toContain("no-store")
|
||||
})
|
||||
})
|
||||
80
test/integration/socketFd.test.ts
Normal file
80
test/integration/socketFd.test.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { ChildProcess, spawn } from "child_process"
|
||||
import { promises as fs } from "fs"
|
||||
import * as http from "http"
|
||||
import * as net from "net"
|
||||
import * as path from "path"
|
||||
import { clean, tmpdir } from "../utils/helpers"
|
||||
|
||||
describe("--socket-fd", () => {
|
||||
const testName = "socketFd"
|
||||
const codeServerPath = process.env.CODE_SERVER_PATH || path.resolve("../../release-standalone/bin/code-server")
|
||||
let tempDir: string
|
||||
let socketDir: string | undefined
|
||||
let child: ChildProcess | undefined
|
||||
|
||||
beforeEach(async () => {
|
||||
await clean(testName)
|
||||
tempDir = await tmpdir(testName)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
if (child?.pid && child.exitCode === null) {
|
||||
// Kill the process group so that the wrapper's inner process also stops.
|
||||
process.kill(-child.pid, "SIGKILL")
|
||||
}
|
||||
if (socketDir) {
|
||||
await fs.rm(socketDir, { force: true, recursive: true })
|
||||
socketDir = undefined
|
||||
}
|
||||
})
|
||||
|
||||
// Give the listener to code-server as fd 3, as systemd socket activation does.
|
||||
const getHealthzThroughFd = async (server: net.Server, target: http.RequestOptions): Promise<number> => {
|
||||
const fd: number = (server as any)._handle.fd
|
||||
let output = ""
|
||||
child = spawn(
|
||||
codeServerPath,
|
||||
[
|
||||
"--socket-fd=3",
|
||||
"--auth=none",
|
||||
`--user-data-dir=${path.join(tempDir, "data")}`,
|
||||
`--config=${path.join(tempDir, "config.yaml")}`,
|
||||
],
|
||||
{ detached: true, stdio: ["ignore", "pipe", "pipe", fd] },
|
||||
)
|
||||
child.stdout?.on("data", (chunk) => (output += chunk))
|
||||
child.stderr?.on("data", (chunk) => (output += chunk))
|
||||
await new Promise((resolve) => server.close(resolve))
|
||||
|
||||
const exited = new Promise<never>((_, reject) => {
|
||||
child?.once("exit", (code) => reject(new Error(`code-server exited with code ${code}:\n${output}`)))
|
||||
})
|
||||
const status = new Promise<number>((resolve, reject) => {
|
||||
http
|
||||
.get({ ...target, path: "/healthz" }, (res) => {
|
||||
res.resume()
|
||||
resolve(res.statusCode ?? 0)
|
||||
})
|
||||
.once("error", (error) => reject(new Error(`${error.message}:\n${output}`)))
|
||||
})
|
||||
return Promise.race([status, exited])
|
||||
}
|
||||
|
||||
it("should serve requests on a Unix socket passed as a file descriptor", async () => {
|
||||
// macOS limits socket paths to 104 bytes, and os.tmpdir() can be too long.
|
||||
socketDir = await fs.mkdtemp("/tmp/cs-fd-")
|
||||
const server = net.createServer()
|
||||
await new Promise<void>((resolve) => server.listen(path.join(socketDir!, "listen.sock"), resolve))
|
||||
// server.close() unlinks the socket path, so connect through a hard link.
|
||||
const socketPath = path.join(socketDir, "connect.sock")
|
||||
await fs.link(path.join(socketDir, "listen.sock"), socketPath)
|
||||
expect(await getHealthzThroughFd(server, { socketPath })).toBe(200)
|
||||
}, 60000)
|
||||
|
||||
it("should serve requests on a TCP socket passed as a file descriptor", async () => {
|
||||
const server = net.createServer()
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve))
|
||||
const { port } = server.address() as net.AddressInfo
|
||||
expect(await getHealthzThroughFd(server, { host: "127.0.0.1", port })).toBe(200)
|
||||
}, 60000)
|
||||
})
|
||||
@@ -152,6 +152,9 @@ describe("ensureAddress", () => {
|
||||
it("should throw and error if no address", () => {
|
||||
expect(() => ensureAddress(mockServer, "http")).toThrow("Server has no address")
|
||||
})
|
||||
it("should describe a --socket-fd listener by its fd when node reports no address", () => {
|
||||
expect(ensureAddress(mockServer, "http", 4)).toBe("fd:4")
|
||||
})
|
||||
it("should return the address if it's a string", async () => {
|
||||
mockServer.address = () => "/path/to/unix.sock"
|
||||
const address = ensureAddress(mockServer, "http")
|
||||
|
||||
@@ -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,
|
||||
@@ -108,6 +109,8 @@ describe("parser", () => {
|
||||
|
||||
"--disable-file-downloads",
|
||||
|
||||
"--disable-file-cache",
|
||||
|
||||
"--disable-getting-started-override",
|
||||
|
||||
"--disable-proxy",
|
||||
@@ -136,6 +139,7 @@ describe("parser", () => {
|
||||
cert: {
|
||||
value: path.resolve("path/to/cert"),
|
||||
},
|
||||
"disable-file-cache": true,
|
||||
"disable-file-downloads": true,
|
||||
"disable-getting-started-override": true,
|
||||
"disable-proxy": true,
|
||||
@@ -575,6 +579,17 @@ 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({})
|
||||
})
|
||||
|
||||
@@ -68,6 +68,43 @@ describe("http", () => {
|
||||
host: "localhost:8081",
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "https://example.com",
|
||||
host: "example.com:443", // Explicit default port.
|
||||
},
|
||||
{
|
||||
origin: "http://example.com",
|
||||
host: "example.com:80",
|
||||
},
|
||||
{
|
||||
origin: "https://example.com",
|
||||
host: "example.com:80", // Default port of the other protocol.
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
host: "example.com", // Missing port is not ignored.
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "https://example.com",
|
||||
host: "example.com:8443",
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "http://example.com:8080",
|
||||
host: "other.com",
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "http://[::1]:8080",
|
||||
host: "[::1]:8080",
|
||||
},
|
||||
{
|
||||
origin: "http://[::1]:8080",
|
||||
host: "[::1]:8081",
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "localhost:8080",
|
||||
host: "localhost:8080",
|
||||
@@ -122,6 +159,104 @@ describe("http", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("x-forwarded-port", () => {
|
||||
;[
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { "x-forwarded-host": "example.com", "x-forwarded-port": "8080" },
|
||||
},
|
||||
{
|
||||
origin: "https://example.com",
|
||||
headers: { "x-forwarded-host": "example.com", "x-forwarded-port": "443" },
|
||||
},
|
||||
{
|
||||
origin: "http://[::1]:8080",
|
||||
headers: { "x-forwarded-host": "[::1]", "x-forwarded-port": "8080" },
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { "x-forwarded-host": "example.com", "x-forwarded-port": "8080, 443" },
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { "x-forwarded-host": "example.com", "x-forwarded-port": "8081" },
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { "x-forwarded-host": "example.com:8081", "x-forwarded-port": "8080" },
|
||||
expected: "does not match", // The port in the host wins.
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { "x-forwarded-host": "example.com", "x-forwarded-port": "foo" },
|
||||
expected: "does not match",
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { host: "example.com", "x-forwarded-port": "8080" },
|
||||
expected: "does not match", // Only used with X-Forwarded-Host.
|
||||
},
|
||||
{
|
||||
origin: "https://example.com:8080",
|
||||
headers: { forwarded: "host=example.com", "x-forwarded-port": "8080" },
|
||||
expected: "does not match",
|
||||
},
|
||||
].forEach((test) => {
|
||||
it(`${test.origin} -> ${JSON.stringify(test.headers)}`, () => {
|
||||
const req = getMockReq({
|
||||
originalUrl: "localhost:8080",
|
||||
headers: {
|
||||
origin: test.origin,
|
||||
...test.headers,
|
||||
},
|
||||
args: {},
|
||||
})
|
||||
if (typeof test.expected === "string") {
|
||||
expect(() => http.authenticateOrigin(req)).toThrow(test.expected)
|
||||
} else {
|
||||
expect(() => http.authenticateOrigin(req)).not.toThrow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("should not add the port to the host for other uses", () => {
|
||||
const req = getMockReq({
|
||||
headers: { "x-forwarded-host": "code-8080.example.com", "x-forwarded-port": "443" },
|
||||
})
|
||||
expect(http.getHost(req)).toBe("code-8080.example.com")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getCookieDomain", () => {
|
||||
it("should use the proxy domain for the cookie", () => {
|
||||
const proxyDomains = ["{{port}}.example.com", "code-{{port}}.test.com"]
|
||||
expect(http.getCookieDomain("example.com", proxyDomains)).toBe("example.com")
|
||||
expect(http.getCookieDomain("8080.example.com", proxyDomains)).toBe("example.com")
|
||||
expect(http.getCookieDomain("8080.example.com:443", proxyDomains)).toBe("example.com")
|
||||
expect(http.getCookieDomain("code-8080.test.com", proxyDomains)).toBe("test.com")
|
||||
})
|
||||
|
||||
it("should use the highest level proxy domain", () => {
|
||||
const proxyDomains = ["{{port}}.test.example.com", "{{port}}.example.com"]
|
||||
expect(http.getCookieDomain("test.example.com", proxyDomains)).toBe("example.com")
|
||||
expect(http.getCookieDomain("8080.test.example.com", proxyDomains)).toBe("example.com")
|
||||
})
|
||||
|
||||
it("should use the host when no proxy domain matches", () => {
|
||||
expect(http.getCookieDomain("code.other.com", ["{{port}}.example.com"])).toBe("code.other.com")
|
||||
expect(http.getCookieDomain("8080.example.com", ["{{port}}.{{host}}"])).toBe("8080.example.com")
|
||||
expect(http.getCookieDomain("8080.example.com", [])).toBe("8080.example.com")
|
||||
})
|
||||
|
||||
it("should not set a domain for localhost or IP addresses", () => {
|
||||
const proxyDomains = ["{{port}}.example.com"]
|
||||
expect(http.getCookieDomain("localhost:8080", proxyDomains)).toBe(undefined)
|
||||
expect(http.getCookieDomain("127.0.0.1:8080", proxyDomains)).toBe(undefined)
|
||||
expect(http.getCookieDomain("8080.dev.localhost", proxyDomains)).toBe(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe("constructRedirectPath", () => {
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import i18n, { loadCustomStrings } from "../../../src/node/i18n"
|
||||
import { loadCustomStrings } from "../../../src/node/i18n"
|
||||
|
||||
describe("i18n", () => {
|
||||
it("includes Turkish translations", () => {
|
||||
expect(i18n.getResource("tr", "translation", "WELCOME")).toBe("{{app}} uygulamasına hoş geldiniz")
|
||||
})
|
||||
|
||||
let tempDir: string
|
||||
let validJsonFile: string
|
||||
let invalidJsonFile: string
|
||||
|
||||
@@ -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