Compare commits

..

161 Commits

Author SHA1 Message Date
Asher
460a4564c3 Revert "chore: bump codecov/codecov-action from 3 to 4 (#6652)"
This reverts commit 63beaaabd7.

It appears to be no longer capable of finding git.
2024-02-28 14:04:55 -09:00
Muhammad Atif Ali
963fcfc3a5 docs: add coder module as an installation method (#6692)
Co-authored-by: Asher <ash@coder.com>
2024-02-28 22:06:49 +00:00
dependabot[bot]
75611411b4 chore: bump ip from 1.1.5 to 1.1.9 in /test (#6682)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.5 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.5...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 13:50:59 -09:00
dependabot[bot]
1e5666b68e chore: bump ip from 1.1.8 to 1.1.9 (#6681)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.8 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.8...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 13:50:49 -09:00
Olivier Benz
9d70cbc8b2 Update Code to 1.86.2 (#6677) 2024-02-15 22:12:56 +00:00
ckesc
853ab407de Update FAQ: clarify about hashed pass and compose file (#6671) 2024-02-12 22:11:45 +00:00
Asher
c31d2a0e37 Release v4.21.1 2024-02-09 13:02:44 -09:00
Dmitry Sharshakov
45164bf749 Use rpm to install in Fedora image (#6670)
Dnf will pull caches if invoked for local file install and is also unnecessary
2024-02-09 12:56:57 -09:00
Dmitry Sharshakov
a2d35ad815 docker: add Fedora 39 and openSUSE Tumbleweed based images (#6669) 2024-02-08 12:31:50 -09:00
Olivier Benz
76e6f75758 Update Code to 1.86.1 (#6668) 2024-02-08 11:10:43 -09:00
Asher
413c47a86d Update Node to 18.17.1
For https://github.com/coder/code-server/issues/6666.
2024-02-07 21:11:27 -09:00
Asher
5b62943216 Release v4.21.0 2024-02-05 09:41:51 -09:00
dependabot[bot]
84ca27278b chore: bump eslint-config-prettier from 9.0.0 to 9.1.0 (#6648)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 9.0.0 to 9.1.0.
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v9.0.0...v9.1.0)

---
updated-dependencies:
- dependency-name: eslint-config-prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-02 02:14:33 +00:00
dependabot[bot]
1471a152ff chore: bump i18next from 23.7.6 to 23.8.2 (#6645)
Bumps [i18next](https://github.com/i18next/i18next) from 23.7.6 to 23.8.2.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.7.6...v23.8.2)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:39:31 -09:00
dependabot[bot]
6adbfc461b chore: bump @typescript-eslint/eslint-plugin from 6.16.0 to 6.20.0 (#6646)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.16.0 to 6.20.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.20.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:39:14 -09:00
dependabot[bot]
2a55212027 chore: bump prettier from 3.1.1 to 3.2.4 (#6647)
Bumps [prettier](https://github.com/prettier/prettier) from 3.1.1 to 3.2.4.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.1.1...3.2.4)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:39:00 -09:00
dependabot[bot]
b63fda4bf7 chore: bump eslint-plugin-prettier from 5.0.0 to 5.1.3 (#6649)
Bumps [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) from 5.0.0 to 5.1.3.
- [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v5.0.0...v5.1.3)

---
updated-dependencies:
- dependency-name: eslint-plugin-prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:38:45 -09:00
dependabot[bot]
ab17495e3a chore: bump actions/cache from 3 to 4 (#6650)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:38:25 -09:00
dependabot[bot]
53b0fda510 chore: bump robinraju/release-downloader from 1.8 to 1.9 (#6651)
Bumps [robinraju/release-downloader](https://github.com/robinraju/release-downloader) from 1.8 to 1.9.
- [Release notes](https://github.com/robinraju/release-downloader/releases)
- [Commits](https://github.com/robinraju/release-downloader/compare/v1.8...v1.9)

---
updated-dependencies:
- dependency-name: robinraju/release-downloader
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:37:57 -09:00
dependabot[bot]
63beaaabd7 chore: bump codecov/codecov-action from 3 to 4 (#6652)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:37:42 -09:00
dependabot[bot]
2db0184c4a chore: bump github/codeql-action from 2 to 3 (#6653)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:37:33 -09:00
dependabot[bot]
dd9cefab66 chore: bump tj-actions/changed-files from 41 to 42 (#6654)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 41 to 42.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v41...v42)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 16:37:09 -09:00
Olivier Benz
1d774d01bf Update Code to 1.86.0 (#6655) 2024-02-01 16:36:47 -09:00
Asher
d6ef385de2 Release v4.20.1 2024-01-22 08:34:02 -09:00
Olivier Benz
e76afa4a2b Update Code to 1.85.2 (#6631) 2024-01-19 22:30:16 +00:00
Asher
fdb46d3fe5 Exit with 1 when VS Code CLI errors
Addresses part of #6367.  The script bundled with VS Code still has the
same problem but it would be better to fix that one upstream.
2024-01-11 12:46:09 -09:00
Asher
d49b3bf159 Fix query string being double-encoding over path proxy
Instead of trying to piece together the original URL and re-encode what
needs to be re-encoded, strip out the base from the original URL.

Fixes #6307.
2024-01-11 12:26:06 -09:00
dependabot[bot]
e87499c301 chore: bump follow-redirects from 1.15.3 to 1.15.4 (#6624)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-11 02:32:57 +00:00
dependabot[bot]
cc68c0fb0f chore: bump @typescript-eslint/parser from 6.9.1 to 6.17.0 (#6622)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.9.1 to 6.17.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.17.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:46:28 -09:00
dependabot[bot]
749e105cd9 chore: bump @types/node from 18.18.1 to 18.19.4 (#6613)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.18.1 to 18.19.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:33:10 -09:00
dependabot[bot]
94f759a53c chore: bump actions/download-artifact from 3 to 4 (#6609)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:32:33 -09:00
dependabot[bot]
2786f60752 chore: bump actions/upload-artifact from 3 to 4 (#6610)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:32:10 -09:00
dependabot[bot]
aea28cb499 chore: bump dawidd6/action-download-artifact from 2 to 3 (#6612)
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2 to 3.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:29:50 -09:00
dependabot[bot]
2cabe799e2 chore: bump @typescript-eslint/parser from 6.9.1 to 6.16.0 (#6614)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.9.1 to 6.16.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.16.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:28:30 -09:00
dependabot[bot]
c1be39abc7 chore: bump prettier from 3.0.3 to 3.1.1 (#6615)
Bumps [prettier](https://github.com/prettier/prettier) from 3.0.3 to 3.1.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.0.3...3.1.1)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:28:15 -09:00
dependabot[bot]
21e798ccdf chore: bump aquasecurity/trivy-action from 0.14.0 to 0.16.1 (#6621)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.14.0 to 0.16.1.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](2b6a709cf9...d43c1f16c0)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:28:00 -09:00
dependabot[bot]
871030e997 chore: bump typescript from 5.2.2 to 5.3.3 (#6616)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.2.2 to 5.3.3.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.2.2...v5.3.3)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:27:42 -09:00
dependabot[bot]
a143dcf111 chore: bump @typescript-eslint/eslint-plugin from 6.11.0 to 6.16.0 (#6617)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.11.0 to 6.16.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.16.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:27:25 -09:00
dependabot[bot]
5214555683 chore: bump tj-actions/changed-files from 40 to 41 in /.github/workflows (#6618)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 40 to 41.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v40...v41)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-05 13:27:05 -09:00
Merith
ff0fcf6cde Fix non-functional Docker Hub link (#6595)
registry.hub.docker.com leads to an blank white page
removing "registry' from the URL fixes it and takes the user to the correct page
2024-01-05 11:22:33 -09:00
Asher
07901026a0 Release v4.20.0 2023-12-21 12:53:25 -09:00
Asher
d0215eca88 Tweak bug report template
These checkboxes keep getting checked despite the submitter using an
insecure context or not having tested upstream.  I think two things are
at play here:

1. Folks might be interpreting "cannot reproduce" as "did not
   reproduce" or "did not have time to reproduce".
2. The checkboxes are required to submit the issue so folks might be
   marking them just so they can get their issue submitted; maybe they
   are not even reading the checkboxes and are just seeing the error
   that they need to be marked and blindly marking them because while
   in some cases folks will add "I had to check this but it is not
   true", usually they say nothing.

In any case, hopefully these changes make the checkboxes more accurate,
and then if they are unchecked we can ask them to go reproduce in VS
Code or use a secure context or whatever the case may be.
2023-12-18 13:56:35 -09:00
Dov Benyomin Sohacheski
d6c5a4af9c Add Debian bookworm config to bakefile (#6590) 2023-12-18 21:30:16 +00:00
Olivier Benz
0b84523121 Update Code to 1.85.1 (#6588) 2023-12-18 20:18:44 +00:00
Olivier Benz
45694d38c4 Update Code to 1.85.0 (#6573) 2023-12-15 12:38:01 -09:00
Dov Benyomin Sohacheski
d9fe46a6be Update and organize release image packages, add wget (#6581) 2023-12-15 20:32:14 +00:00
Ammar Bandukwala
6f078a48a6 Improve README callout to coder/coder (#6579) 2023-12-12 14:23:54 -09:00
Dov Benyomin Sohacheski
7649b6e6ca Update base release image to Debian:12 (#6574) 2023-12-12 11:37:17 -09:00
Jeff Miller
9622830518 Disable "Show Local" button, add --disable-file-uploads option and add file operation trace level logs (#6557) 2023-12-07 12:10:22 -09:00
Asher
26a3437849 Use debug instead of trace
Trace outputs stack traces which is entirely unnecessary for these two
log entries and makes the logs noisier than they need to be.
2023-12-06 13:19:36 -09:00
Evan Rush
1fac50d6f6 Fix Helm boolean environment variable (#6563) 2023-12-04 19:32:16 +00:00
Asher
3e8100b70e Release v4.19.1 2023-11-29 12:23:25 -09:00
Asher
0c98611e6b Ensure we only ever set workspace initialized to true
This is just a guard in case there are paths where the workspace is
already marked as initialized but the workspace configuration is not and
we end up actually un-initializing it.
2023-11-27 17:36:26 -09:00
Asher
73cb236535 Add back local storage patch
And fix the workspace bug.  It is caused by an issue with how some
global variables are being used asynchronously and is exacerbated by the
delay reading settings from the remote introduces.

1. The workspace is created and is marked as not initialized.
2. The configuration's change handler is triggered, and now
   initialization is complete.
3. The handler tries to set the global workspace variable to initialized
   but the workspace has not been set yet so we get an undefined error.
4. The workspace global is now set, but it is set to the old value with
   initialized still set to false.
5. Workspace is never marked as initialized until something else
   triggers the on change handler again.

Fixes #3061, and closes #6546.

My guess is this logic changed in one of the VS Code updates,
introducing this async bug but never getting caught probably because for
them the settings are always local thus minimal delay.
2023-11-27 17:25:38 -09:00
Asher
9ba66ec468 Use machine settings for e2e tests
User settings are browser-based so use machine settings instead.
2023-11-20 15:42:34 -09:00
Asher
09dd5fe44d Delete local storage patch
The main goal of this patch was to make user settings stored on disk
instead of in the browser, but this stopped working some time ago.  Not
only that but it is causing a bug where a workspace will not fully open.

A secondary goal was to fix the Vim extension but the extension appears
to work just fine without this change now (both the server and browser
versions).

This patch is not useful anymore anyway because there are remote-level
settings that *do* get stored on disk and can be used instead of
user-level settings when necessary.

Fixes #3061, and possibly #6153.
2023-11-20 13:32:59 -09:00
Quentin Quaadgras
958c5203ec Update Termux docs on how to enable keyboard shortcuts and tab key (#6539) 2023-11-20 08:16:17 -09:00
Asher
edf078d1d2 Release v4.19.0 2023-11-20 07:29:25 -09:00
Asher
984fb135dc Fix node-gyp failure on macOS (#6537) 2023-11-16 10:10:36 -09:00
Olivier Benz
9658969084 Update Code to 1.84.2 (#6524) 2023-11-14 13:44:21 -09:00
Asher
da254c39ee Set Node version in a single place (#6534)
This should make it much easier to update.  Also use 18.15.0
specifically since that is what VS Code ships with.

Additionally, it fixes the post-install script being skipped due to
a Yarn v1 bug that happens when Yarn installs node-gyp, which
it does because 18.18 onward stopped bundling node-gyp.
2023-11-14 12:45:56 -09:00
dependabot[bot]
239df56634 chore: bump @typescript-eslint/eslint-plugin from 6.7.2 to 6.11.0 (#6533)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.7.2 to 6.11.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.11.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:38:31 -09:00
dependabot[bot]
c285b99c74 chore: bump eslint from 8.49.0 to 8.53.0 (#6532)
Bumps [eslint](https://github.com/eslint/eslint) from 8.49.0 to 8.53.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.49.0...v8.53.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:36:26 -09:00
dependabot[bot]
f64bc022e9 chore: bump i18next from 23.5.1 to 23.7.6 (#6531)
Bumps [i18next](https://github.com/i18next/i18next) from 23.5.1 to 23.7.6.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.5.1...v23.7.6)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:27:30 -09:00
dependabot[bot]
22c54c3b2e chore: bump eslint-plugin-import from 2.28.1 to 2.29.0 (#6507)
Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.28.1 to 2.29.0.
- [Release notes](https://github.com/import-js/eslint-plugin-import/releases)
- [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.28.1...v2.29.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-import
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:27:10 -09:00
dependabot[bot]
ae75f76e30 chore: bump aquasecurity/trivy-action from 0.13.1 to 0.14.0 (#6530)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.13.1 to 0.14.0.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](f78e9ecf42...2b6a709cf9)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:26:40 -09:00
dependabot[bot]
53d856d3c6 chore: bump @babel/traverse from 7.16.8 to 7.23.2 in /test (#6495)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.16.8 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:26:04 -09:00
dependabot[bot]
4e4d510238 chore: bump docker/setup-qemu-action from 2 to 3 (#6464)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:25:33 -09:00
dependabot[bot]
3a0f4a2773 chore: bump i18next from 23.5.1 to 23.6.0 (#6508)
Bumps [i18next](https://github.com/i18next/i18next) from 23.5.1 to 23.6.0.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.5.1...v23.6.0)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:24:53 -09:00
dependabot[bot]
cbc17516fd chore: bump @typescript-eslint/parser from 6.7.2 to 6.9.1 (#6511)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.7.2 to 6.9.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.9.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:23:33 -09:00
dependabot[bot]
c4efcaf079 chore: bump actions/setup-node from 3 to 4 (#6512)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:23:05 -09:00
dependabot[bot]
f44b57393c chore: bump docker/login-action from 2 to 3 (#6513)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:21:54 -09:00
dependabot[bot]
3fc30cae3e chore: bump aquasecurity/trivy-action from 0.12.0 to 0.13.1 (#6514)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.12.0 to 0.13.1.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](fbd16365eb...f78e9ecf42)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:21:03 -09:00
dependabot[bot]
91f8ec6295 chore: bump tj-actions/changed-files from 39 to 40 (#6515)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39 to 40.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v39...v40)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 09:20:36 -09:00
Asher
11e6e656c0 Release v4.18.0 2023-10-20 12:03:13 -08:00
Olivier Benz
d7a2b4936a Update Code to 1.83.1 (#6488)
* Update Code to 1.83.1

* Patch out lookbehind for Safari support

Not sure why it needs a lookbehind unless a number followed by a capital
letter is not supposed to be considered a new word, which seems wrong to
me.  The tests do not contain any numbers so I can only guess.

---------

Co-authored-by: Asher <ash@coder.com>
2023-10-19 00:50:21 +00:00
Asher
c2d79d94f9 Use secure context in bug report template
Some folks run over localhost, which will work just fine for service
workers.
2023-10-11 17:19:19 -08:00
dependabot[bot]
9fec2d7cad chore: bump docker/setup-buildx-action from 2 to 3 (#6463)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-11 15:51:24 -08:00
dependabot[bot]
80dfb2b2a9 chore: bump actions/checkout from 3 to 4 (#6462)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-04 15:50:11 -08:00
Asher
27e7b931e7 Remove mention of legacy extension API
We would like to shut this down.
2023-10-04 15:44:54 -08:00
liuxhit
db9f678477 Update default nginx config in guide.md (#6471)
update nginx config to avoid wss error when expose code-server using a custom domain and a custom port via nginx.

see also: 
[issue of code-server](https://github.com/coder/code-server/issues/4443)
[different between `$host` and `$http_host`](https://stackoverflow.com/a/76875724)
2023-10-04 10:41:35 -08:00
Olivier Benz
c095c26dbc Update Code to 1.82.3 (#6472) 2023-10-04 17:17:27 +00:00
dependabot[bot]
262f66abf6 chore: bump @types/node from 18.17.18 to 18.18.1 (#6467)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.17.18 to 18.18.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 13:25:52 -08:00
dependabot[bot]
8ee45686b0 chore: bump aquasecurity/trivy-action from 0.11.2 to 0.12.0 (#6461)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.11.2 to 0.12.0.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](41f05d9ecf...fbd16365eb)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 13:24:45 -08:00
dependabot[bot]
512d97f22f chore: bump tj-actions/changed-files from 38 to 39 (#6460)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 38 to 39.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v38...v39)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 13:24:15 -08:00
Daniel T. Lee
897e0ae1da Modify manifest for window control overlay support (#6468)
Since the release of code-server v4.17.0 (Code 1.82), "Command Center" has become a default option. However, the current code-server PWA app lacks support for the Windows control overlay, resulting in an untidy appearance of the title bar. This commit introduces modifications to the manifest file to enable support for the window control overlay.
2023-10-02 18:03:37 +00:00
Asher
f4bf492051 Release v4.17.1 2023-09-29 15:21:48 -08:00
Asher
2eba7af117 Use code-server commit in product.json
Also remove github.com from the trusted domains.  This causes the
browser to block the popup instead (probably because the space between
interaction and popup is too great), which is difficult to notice in
Chromium.  Even in Firefox with the extra bar they add at the top it can
be easy to miss.
2023-09-29 13:58:01 -08:00
Asher
0dc59c0da2 Add trusted extension list
Also trust github.com to make the auth flow smoother.
2023-09-29 10:39:00 -08:00
Asher
6275520348 Fix incorrect argon2 target in arm builds (#6453)
* Fix building from source on arm

Not building from source causes argon2 to pull the wrong arch, so we
have to build from source.

But building from source is causing the new Kerberos module to fail on
arm64 and keytar to fail on both.

The latter has been very difficult to debug because the GitHub image
provides a different result to containers based on Ubuntu 20.04.
Because of this, use a container instead.

Use debian:buster as the container because it is easier to set up the
architecture sources (no need to modify the sources) and because it
seems to come with glibc 2.28 rather than 2.31.

Also use the exact version of Node (18.15.0) for reproducibility.

* Set owner and group during tar to zero

Otherwise you get IDs that can cause (benign) errors while extracting,
which might be confusing.  At the very least, I did not see these errors
from previous tars (although they seem to use 1001).

There is no guarantee what IDs might exist so 0 seems the most
reasonable.
2023-09-27 19:17:47 -08:00
Asher
2bb51a25a9 Refresh proxy URI patch 2023-09-26 12:19:13 -08:00
Asher
7a213161f2 Build from source on cross-compile step
The comment said the issue with argon2 was related to CentOS 7 but the
cross-compile steps never used CentOS 7 so maybe the real issue is with
the architecture.
2023-09-26 09:58:53 -08:00
Asher
a1131fadf2 Enable secret storage (#6450)
* Remove unused dependency patch

* Enable secret storage based on local storage

* Remove unnecessary GitHub auth patch

It works now without the patch.
2023-09-26 08:35:41 -08:00
Asher
468cf5c6ce Update npm publish workflow to use v18 2023-09-22 17:53:56 -08:00
Asher
800bf364d6 Release v4.17.0 2023-09-22 17:49:40 -08:00
DevMirza
5428442628 feat(lang): Add Urdu Locale (#6444) 2023-09-22 17:16:51 -08:00
Dov Benyomin Sohacheski
020f280458 Add .local mount to example Docker command (#6419) 2023-09-22 17:07:07 -08:00
Asher
58f6e24a07 Fix installation of kerberos module on armv7l (#6442)
Also build with the same version of Node we will release with.
2023-09-22 00:54:14 -08:00
Asher
7868f4db23 Fix cross-compilation (#6441)
* Avoid packaging yarn.lock

Since the shrinkwrap is what we want everything to use.

* Build with npm

It seems we stuck with yarn because npm was giving us errors but I will try
sorting it out now so we can build with npm as originally intended.

* Remove build from source

Not using CentOS 7 anymore so based on the comment we no longer need
this.  Keytar seems to install fine now.

* Update missed Node version

These numbers are all over the place.

* npm_config_arch must be lowercase

* Patch out Kerberos

I am not sure exactly how it is used but I think it is not a path code-server
worries about, at least not right now.  Just going to patch it out rather than
figure out how to build it on armv7l but we can revisit later.
2023-09-21 23:21:01 -08:00
Asher
acc50a5d36 Update dependencies and force-update qs (#6440)
* Update dependencies and force-update qs

This is mainly an attempt to get rid of as many resolutions as possible
since it seems they are unnecessary except for qs (according to yarn/npm
audit).

For qs use 6.9.7 since Express is using 6.9.6 and that matches the most
closely.

Also add overrides since this is npm's version of yarn's resolutions and
we need it for the shrinkwrap to generate with the right dependencies.

Decided to keep pinning @types/node as well although I am not sure it is
necessary.  Express is pulling in v20 types.  Since this is
development-only we only need it in resolutions.

* Run formatter

Some rules seem to have changed with the dependency updates.

* Replace deprecated bodyParser.json() usage

* Audit npm shrinkwrap as well

* Skip installing dependencies in audit

It seems the tools only require the lock files.

* Fix tests when using ipv6

* Add missing openssl dependency to flake
2023-09-21 16:13:34 -08:00
Asher
47ee7ae670 Bump minimum glibc to 2.28 (#6439)
At least, for the standalone and for anyone running on default Node 18.

If support for 2.17 is needed then one would need to build Node 18 with 2.17 and then build code-server with that version (specifically, the native npm modules).
2023-09-21 13:42:17 -08:00
Asher
70d0c603cc Update to VS Code 1.82.2 (#6436)
* Update VS Code to 1.82.2

* Add new libkrb5 dependency

* Update patches

The only changes were to context except:

- The URL callback provider uses a new _callbackRoute argument and moved
  locations.
- The telemetry provider gets passed the request service as the first
  argument now.
- CSP hash changed, as usual.

* Update Node to v18

* Revert back to es2020

es2022 is breaking Safari.
2023-09-20 15:33:28 -08:00
dependabot[bot]
2e29c233ea chore: bump tj-actions/changed-files from 37 to 38 (#6417)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 37 to 38.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v37...v38)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-18 11:54:56 -08:00
dependabot[bot]
331a017309 chore: bump argon2 from 0.30.3 to 0.31.0 (#6415)
Bumps [argon2](https://github.com/ranisalt/node-argon2) from 0.30.3 to 0.31.0.
- [Release notes](https://github.com/ranisalt/node-argon2/releases)
- [Commits](https://github.com/ranisalt/node-argon2/compare/v0.30.3...v0.31.0)

---
updated-dependencies:
- dependency-name: argon2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-18 11:53:31 -08:00
dependabot[bot]
f915d1e2c8 chore: bump eslint from 8.44.0 to 8.48.0 (#6414)
Bumps [eslint](https://github.com/eslint/eslint) from 8.44.0 to 8.48.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.44.0...v8.48.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-18 11:52:54 -08:00
Kaoru Yamamoto
95bcf101d7 Add Japanese locale (#6433) 2023-09-18 17:23:03 +00:00
James MacDonald
d80568df20 Add pod annotations (#6432) 2023-09-16 00:31:05 +00:00
Asher
03dc8cd808 Propagate post-installation failures
pipefail might be ideal here but not sure how wide the support is yet
considering this may run on plain sh.
2023-09-11 09:27:29 -08:00
Asher
3e1c00e017 Run formatter
Not sure why CI missed these, will have to look into it.
2023-09-11 09:27:28 -08:00
Cyanoure
a76e5241b6 Add "CODE_SERVER_HOST" environment variable (#6423) 2023-09-08 22:50:11 +00:00
Asher
913fc30866 Upgrade @coder/logger (#6409)
This gets rid of the unused peer dependency that was pulling in
protobufjs.
2023-08-30 12:10:34 -08:00
Asher
eb498b0d6d Remove humanPath (#6404)
The tilde is ambiguous and it can be helpful to know exactly what paths
code-server is trying to use, especially if it is running as a different
user than you expected.
2023-08-29 14:25:24 -08:00
Antoine
eb8099ff89 feat(helm): Don't create Secret if existingSecret is provided (#6397) 2023-08-28 11:01:11 -08:00
Efren
56d3548fa2 Add braces to Caddyfile example (#6382) 2023-08-10 00:44:23 +00:00
jothi prasath
2d335bd1ea Update screenshots (#6372) 2023-08-07 19:02:54 +00:00
dependabot[bot]
291682e1c0 chore: bump i18next from 23.2.11 to 23.4.1 (#6362)
Bumps [i18next](https://github.com/i18next/i18next) from 23.2.11 to 23.4.1.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.2.11...v23.4.1)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 10:17:13 -08:00
dependabot[bot]
97aeb77abe chore: bump eslint-plugin-import from 2.27.5 to 2.28.0 (#6363)
Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.27.5 to 2.28.0.
- [Release notes](https://github.com/import-js/eslint-plugin-import/releases)
- [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.27.5...v2.28.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-import
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 10:16:13 -08:00
dependabot[bot]
76fd2389e4 chore: bump proxy-agent from 6.2.1 to 6.3.0 (#6361)
Bumps [proxy-agent](https://github.com/TooTallNate/proxy-agents/tree/HEAD/packages/proxy-agent) from 6.2.1 to 6.3.0.
- [Release notes](https://github.com/TooTallNate/proxy-agents/releases)
- [Changelog](https://github.com/TooTallNate/proxy-agents/blob/main/packages/proxy-agent/CHANGELOG.md)
- [Commits](https://github.com/TooTallNate/proxy-agents/commits/proxy-agent@6.3.0/packages/proxy-agent)

---
updated-dependencies:
- dependency-name: proxy-agent
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 09:51:46 -08:00
Asher
3cb92edc76 Release v4.16.1 2023-07-31 11:21:45 -08:00
Olivier Benz
94ef3776ad Update Code to 1.80.2 (#6357) 2023-07-31 09:14:29 -08:00
Asher
a82f1ceaa5 Add missing FAQ table of contents entry 2023-07-28 17:46:36 -08:00
Asher
25254214fb Release v4.16.0 2023-07-28 17:32:57 -08:00
Asher
feb5e6770c Add entry for location of configuration
Closes #6324.
2023-07-28 17:32:48 -08:00
Asher
e37b35278d Account for disabled proxy in startup logs 2023-07-27 09:26:11 -08:00
Asher
2ffbcfdfcb Release v4.15.0 2023-07-21 15:30:03 -08:00
Ryan Brainard
74da5167a2 Add --disable-proxy option (#6349) 2023-07-21 15:23:21 -08:00
dependabot[bot]
daac46b3cf chore: bump i18next from 22.5.1 to 23.2.11 (#6326)
Bumps [i18next](https://github.com/i18next/i18next) from 22.5.1 to 23.2.11.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v22.5.1...v23.2.11)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-20 14:03:21 -05:00
dependabot[bot]
ea3c79ffd1 chore: bump @typescript-eslint/eslint-plugin from 5.59.1 to 5.62.0 (#6327)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.59.1 to 5.62.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.62.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-20 13:31:37 -05:00
Alex Thillen
93e60f7b0e add trusted-origins cli argument (#6319) 2023-07-19 14:04:03 -08:00
dependabot[bot]
7926647058 chore: bump tough-cookie from 4.0.0 to 4.1.3 in /test (#6318)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 14:02:19 -08:00
dependabot[bot]
d27cd43dce chore: bump @typescript-eslint/parser from 5.61.0 to 5.62.0 (#6328)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.61.0 to 5.62.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.62.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 14:01:32 -08:00
dependabot[bot]
1befd37310 chore: bump word-wrap from 1.2.3 to 1.2.4 (#6342)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 14:01:14 -08:00
dependabot[bot]
2b3b5e7051 chore: bump word-wrap from 1.2.3 to 1.2.4 in /test (#6343)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 14:00:56 -08:00
Olivier Benz
788da5d495 Update Code to 1.80.1 (#6340)
* Update Code to 1.80.1 (#6340)
* Give build workflow more time to run
2023-07-19 14:00:31 -08:00
dependabot[bot]
070a5a3179 chore: bump semver from 6.3.0 to 6.3.1 in /test (#6320)
Bumps [semver](https://github.com/npm/node-semver) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v6.3.1/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v6.3.0...v6.3.1)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-14 13:52:42 -08:00
Michael Thomas
7cbb6a8b09 Add Svelte to guide (#6269)
Added a guide on proxying to a Svelte app since there wasn't one already. Used the vue and angular guides as a template and included a link to an issue post on sveltekits website which adds some context.
2023-07-13 16:17:25 -05:00
dependabot[bot]
7fb54073db chore: bump @typescript-eslint/parser from 5.59.11 to 5.61.0 (#6312)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.59.11 to 5.61.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.61.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-13 16:04:32 -05:00
dependabot[bot]
e72e8bb6b5 chore: bump aquasecurity/trivy-action from 0.10.0 to 0.11.2 (#6303)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.10.0 to 0.11.2.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](e5f43133f6...41f05d9ecf)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-13 16:04:18 -05:00
dependabot[bot]
411846528b chore: bump eslint from 8.39.0 to 8.44.0 (#6299)
Bumps [eslint](https://github.com/eslint/eslint) from 8.39.0 to 8.44.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.39.0...v8.44.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-13 16:03:55 -05:00
dependabot[bot]
7f024eda6e chore: bump typescript from 5.0.4 to 5.1.6 (#6297)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.0.4 to 5.1.6.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-06 13:59:24 -05:00
dependabot[bot]
2617623ed6 chore: bump tj-actions/changed-files from 36 to 37 (#6302)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 36 to 37.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v36...v37)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-06 13:59:01 -05:00
Asher
70aa1b7722 Release v4.14.1 2023-06-26 10:21:35 -08:00
dependabot[bot]
90a4147381 chore: bump semver from 7.3.8 to 7.5.2 (#6287)
Bumps [semver](https://github.com/npm/node-semver) from 7.3.8 to 7.5.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.3.8...v7.5.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-26 12:12:45 -05:00
Asher
5c19962930 Set session socket into environment variable (#6282)
* Avoid spawning code-server with --reuse-window and --new-window

These flags mean the user explicitly wants to open in an existing
instance so if the socket is down it should error rather than try to
spawn code-server normally.

* Set session socket into environment variable

While I was at it I added a CLI flag to override the default.  I also
swapped the default to --user-data-dir.

The value is set on an environment variable so it can be used by the
extension host similar to VSCODE_IPC_HOOK_CLI.

* Add e2e test for opening files externally
2023-06-21 22:47:01 -08:00
Asher
56d10d82bf Enforce Node binary permissions
In some cases it may have extra write permissions.
2023-06-21 11:23:40 -08:00
Asher
cef2aa22dc Move session server log after HTTP server logs
The indented logs technically apply to the HTTP server so move the
session server log afterward to avoid making them look like they apply
to the session server.
2023-06-21 10:59:02 -08:00
Sean Lee
b5a9ef80e7 Use unique socket per user for managing editor sessions (#6278)
Also warn if editor session manager socket cannot be created rather than failing.
2023-06-21 13:39:25 -05:00
Asher
5d3c9edce4 Release v4.14.0 2023-06-16 13:38:21 -08:00
Asher
9955cd91a4 Update Code to 1.79.1 (#6264)
Mostly just the usual shifting or changing of the surrounding context
but I did refactor the getting started block we insert because it keeps
getting mangled on each update.  Instead of shifting things around the
columns I just prepend it to the right column.

Getting 404s on some vsda module but everything seems to work 
without it and I do not see it referenced in the package.json nor a
nywhere on npmjs.com so it seems to be optional.
2023-06-15 08:00:03 -08:00
dependabot[bot]
fdeaba9581 chore: bump proxy-agent from 5.0.0 to 6.2.1 (#6247)
* chore: bump proxy-agent from 5.0.0 to 6.2.1

Bumps [proxy-agent](https://github.com/TooTallNate/proxy-agents/tree/HEAD/packages/proxy-agent) from 5.0.0 to 6.2.1.
- [Release notes](https://github.com/TooTallNate/proxy-agents/releases)
- [Changelog](https://github.com/TooTallNate/proxy-agents/blob/main/packages/proxy-agent/CHANGELOG.md)
- [Commits](https://github.com/TooTallNate/proxy-agents/commits/proxy-agent@6.2.1/packages/proxy-agent)

---
updated-dependencies:
- dependency-name: proxy-agent
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update proxy-agent usage

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Asher <ash@coder.com>
2023-06-14 14:27:15 -08:00
dependabot[bot]
40ff2e6049 chore: bump @typescript-eslint/parser from 5.57.1 to 5.59.11 (#6262)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.57.1 to 5.59.11.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.59.11/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-14 14:08:39 -08:00
dependabot[bot]
73d42f7ea0 chore: bump i18next from 22.4.6 to 22.5.1 (#6261)
Bumps [i18next](https://github.com/i18next/i18next) from 22.4.6 to 22.5.1.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v22.4.6...v22.5.1)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-14 13:33:51 -08:00
Sean Lee
fb73742b2b Prefer matching editor sessions when opening files. (#6191)
Signed-off-by: Sean Lee <freshdried@gmail.com>
2023-06-14 13:32:07 -08:00
Asher
ccb0d3a34f Remove unused dependency split2
This was used with now-removed `--link`.
2023-06-13 10:38:13 -08:00
dependabot[bot]
4a121edd16 chore: bump tj-actions/changed-files from 35 to 36 (#6246)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 35 to 36.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v35...v36)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 18:28:24 +00:00
dependabot[bot]
f6db985712 chore: bump robinraju/release-downloader from 1.7 to 1.8 (#6245)
Bumps [robinraju/release-downloader](https://github.com/robinraju/release-downloader) from 1.7 to 1.8.
- [Release notes](https://github.com/robinraju/release-downloader/releases)
- [Commits](https://github.com/robinraju/release-downloader/compare/v1.7...v1.8)

---
updated-dependencies:
- dependency-name: robinraju/release-downloader
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 12:47:40 -05:00
dependabot[bot]
6d00fc7f46 chore: bump typescript from 4.6.4 to 5.0.4 (#6182)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.6.4 to 5.0.4.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.6.4...v5.0.4)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 12:45:49 -05:00
Jonas
ee024f3f2d docs: mention Termux extension workarounds (#6227) 2023-05-31 15:00:58 -08:00
Simon Merschjohann
0703ef008c Allow {{host}} and {{port}} in domain proxy (#6225) 2023-05-31 16:31:30 -05:00
Asher
2109d1cf6a Add new unreleased section to changelog 2023-05-22 12:21:30 -08:00
Asher
74af05dfbe Release v4.13.0 2023-05-19 13:14:29 -08:00
106 changed files with 4241 additions and 2603 deletions

View File

@@ -36,7 +36,7 @@ body:
2. install extension
3. run command
value: |
1.
1.
2.
3.
validations:
@@ -67,19 +67,23 @@ body:
- type: checkboxes
attributes:
label: Does this issue happen in VS Code or GitHub Codespaces?
description: Please try reproducing this issue in VS Code or GitHub Codespaces
description: Please try reproducing this issue in VS Code and GitHub Codespaces. If the bug reproduces in either VS Code or GitHub Codespaces, please submit the issue upstream instead (https://github.com/microsoft/vscode).
options:
- label: I cannot reproduce this in VS Code.
required: true
- label: I cannot reproduce this in GitHub Codespaces.
required: true
- label: I tested this in native VS Code.
required: false
- label: This does not happen in native VS Code.
required: false
- label: I tested this in GitHub Codespaces.
required: false
- label: This does not happen in GitHub Codespaces.
required: false
- type: checkboxes
attributes:
label: Are you accessing code-server over HTTPS?
description: code-server relies on service workers for many features. Double-check that you are using HTTPS.
label: Are you accessing code-server over a secure context?
description: code-server relies on service workers (which only work in secure contexts) for many features. Double-check that you are using a secure context like HTTPS or localhost.
options:
- label: I am using HTTPS.
required: true
- label: I am using a secure context.
required: false
- type: textarea
attributes:
label: Notes

View File

@@ -28,10 +28,10 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Run prettier with actionsx/prettier
uses: actionsx/prettier@v2
uses: actionsx/prettier@v3
with:
args: --check --loglevel=warn .
@@ -41,20 +41,20 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v42
with:
files: |
docs/**
- name: Install Node.js v16
- name: Install Node.js
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
cache: "yarn"
- name: Install doctoc
@@ -70,13 +70,13 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v42
with:
files: |
ci/helm-chart/**
@@ -101,13 +101,13 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v42
with:
files: |
**/*.ts
@@ -115,16 +115,16 @@ jobs:
files_ignore: |
lib/vscode/**
- name: Install Node.js v16
- name: Install Node.js
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Fetch dependencies from cache
if: steps.changed-files.outputs.any_changed == 'true'
id: cache-node-modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
@@ -144,7 +144,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Check workflow files
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/7fdc9630cc360ea1a469eed64ac6d78caeda1234/scripts/download-actionlint.bash)
@@ -157,29 +157,29 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v42
with:
files: |
**/*.ts
files_ignore: |
lib/vscode/**
- name: Install Node.js v16
- name: Install Node.js
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Fetch dependencies from cache
if: steps.changed-files.outputs.any_changed == 'true'
id: cache-node-modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
@@ -203,15 +203,18 @@ jobs:
build:
name: Build code-server
runs-on: ubuntu-20.04
timeout-minutes: 30
timeout-minutes: 60
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: true
- name: Install system dependencies
run: sudo apt update && sudo apt install -y libkrb5-dev
- name: Install quilt
uses: awalsh128/cache-apt-pkgs-action@latest
with:
@@ -221,14 +224,14 @@ jobs:
- name: Patch Code
run: quilt push -a
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Fetch dependencies from cache
id: cache-node-modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: "**/node_modules"
key: yarn-build-code-server-${{ hashFiles('**/yarn.lock') }}
@@ -256,7 +259,7 @@ jobs:
# force a rebuild.
- name: Fetch prebuilt Code package from cache
id: cache-vscode
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: lib/vscode-reh-web-*
key: vscode-reh-package-${{ secrets.VSCODE_CACHE_VERSION }}-${{ steps.vscode-rev.outputs.rev }}-${{ hashFiles('patches/*.diff', 'ci/build/build-vscode.sh') }}
@@ -278,7 +281,7 @@ jobs:
run: tar -czf package.tar.gz release
- name: Upload npm package artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: npm-package
path: ./package.tar.gz
@@ -290,16 +293,19 @@ jobs:
timeout-minutes: 25
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install system dependencies
run: sudo apt update && sudo apt install -y libkrb5-dev
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Fetch dependencies from cache
id: cache-node-modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
@@ -307,7 +313,7 @@ jobs:
yarn-build-
- name: Download npm package
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: npm-package
@@ -331,7 +337,7 @@ jobs:
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: failed-test-videos
path: ./test/test-results
@@ -346,16 +352,19 @@ jobs:
timeout-minutes: 25
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install system dependencies
run: sudo apt update && sudo apt install -y libkrb5-dev
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Fetch dependencies from cache
id: cache-node-modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
@@ -363,7 +372,7 @@ jobs:
yarn-build-
- name: Download npm package
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: npm-package
@@ -383,7 +392,7 @@ jobs:
./test/node_modules/.bin/playwright install
- name: Cache Caddy
uses: actions/cache@v3
uses: actions/cache@v4
id: caddy-cache
with:
path: |
@@ -411,7 +420,7 @@ jobs:
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: failed-test-videos-proxy
path: ./test/test-results

View File

@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install code-server
run: ./install.sh
@@ -44,7 +44,7 @@ jobs:
container: "alpine:3.17"
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install curl
run: apk add curl
@@ -67,7 +67,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install code-server
run: ./install.sh

View File

@@ -27,16 +27,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code-server
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
cache: "yarn"
- name: Download npm package from release artifacts
uses: robinraju/release-downloader@v1.7
uses: robinraju/release-downloader@v1.9
with:
repository: "coder/code-server"
tag: ${{ github.event.inputs.version || github.ref_name }}
@@ -70,7 +70,7 @@ jobs:
uses: Homebrew/actions/setup-homebrew@master
- name: Checkout code-server
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Configure git
run: |
@@ -101,13 +101,13 @@ jobs:
steps:
# We need to checkout code-server so we can get the version
- name: Checkout code-server
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
path: "./code-server"
- name: Checkout code-server-aur repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: "cdrci/code-server-aur"
token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
@@ -155,22 +155,22 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout code-server
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GHCR
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -183,14 +183,22 @@ jobs:
TAG="${{ github.event.inputs.version || github.ref_name }}"
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
- name: Download release artifacts
uses: robinraju/release-downloader@v1.7
- name: Download deb artifacts
uses: robinraju/release-downloader@v1.9
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
fileName: "*.deb"
out-file-path: "release-packages"
- name: Download rpm artifacts
uses: robinraju/release-downloader@v1.9
with:
repository: "coder/code-server"
tag: v${{ env.VERSION }}
fileName: "*.rpm"
out-file-path: "release-packages"
- name: Publish to Docker
run: ./ci/steps/docker-buildx-push.sh
env:

View File

@@ -27,25 +27,25 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
needs: npm-version
container: "centos:7"
container: "centos:8"
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Install development tools
run: |
yum install -y epel-release centos-release-scl make
yum install -y devtoolset-9-{make,gcc,gcc-c++} jq rsync python3
# for keytar
yum install -y libsecret-devel
cd /etc/yum.repos.d/
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
yum install -y gcc-c++ make jq rsync python3 libsecret-devel krb5-devel
- name: Install nfpm and envsubst
run: |
@@ -60,17 +60,15 @@ jobs:
run: npm install -g yarn
- name: Download npm package
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: npm-release-package
- name: Decompress npm package
run: tar -xzf package.tar.gz
# NOTE: && here is deliberate - GitHub puts each line in its own `.sh`
# file when running inside a docker container.
- name: Build standalone release
run: source scl_source enable devtoolset-9 && npm run release:standalone
run: npm run release:standalone
- name: Install test dependencies
run: SKIP_SUBMODULE_DEPS=1 yarn --frozen-lockfile
@@ -102,54 +100,59 @@ jobs:
discussion_category_name: "📣 Announcements"
files: ./release-packages/*
# NOTE@oxy:
# We use Ubuntu 16.04 here, so that our build is more compatible
# with older libc versions. We used to (Q1'20) use CentOS 7 here,
# but it has a full update EOL of Q4'20 and a 'critical security'
# update EOL of 2024. We're dropping full support a few years before
# the final EOL, but I don't believe CentOS 7 has a large arm64 userbase.
# It is not feasible to cross-compile with CentOS.
# Cross-compile notes: To compile native dependencies for arm64,
# we install the aarch64/armv7l cross toolchain and then set it as the default
# compiler/linker/etc. with the AR/CC/CXX/LINK environment variables.
# qemu-user-static on ubuntu-16.04 currently doesn't run Node correctly,
# so we just build with "native"/x86_64 node, then download arm64/armv7l node
# and then put it in our release. We can't smoke test the cross build this way,
# but this means we don't need to maintain a self-hosted runner!
# NOTE@jsjoeio:
# We used to use 18.04 until GitHub browned it out on December 15, 2022
# See here: https://github.com/actions/runner-images/issues/6002
package-linux-cross:
name: Linux cross-compile builds
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
timeout-minutes: 15
needs: npm-version
container: "debian:buster"
strategy:
matrix:
include:
- prefix: aarch64-linux-gnu
arch: arm64
npm_arch: arm64
apt_arch: arm64
- prefix: arm-linux-gnueabihf
arch: armv7l
npm_arch: armv7l
apt_arch: armhf
env:
AR: ${{ format('{0}-ar', matrix.prefix) }}
AS: ${{ format('{0}-as', matrix.prefix) }}
CC: ${{ format('{0}-gcc', matrix.prefix) }}
CPP: ${{ format('{0}-cpp', matrix.prefix) }}
CXX: ${{ format('{0}-g++', matrix.prefix) }}
LINK: ${{ format('{0}-g++', matrix.prefix) }}
NPM_CONFIG_ARCH: ${{ matrix.arch }}
NODE_VERSION: v16.13.0
FC: ${{ format('{0}-gfortran', matrix.prefix) }}
LD: ${{ format('{0}-ld', matrix.prefix) }}
STRIP: ${{ format('{0}-strip', matrix.prefix) }}
PKG_CONFIG_PATH: ${{ format('/usr/lib/{0}/pkgconfig', matrix.prefix) }}
TARGET_ARCH: ${{ matrix.apt_arch }}
npm_config_arch: ${{ matrix.npm_arch }}
# Not building from source results in an x86_64 argon2, as if
# npm_config_arch is being ignored.
npm_config_build_from_source: true
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Install cross-compiler and system dependencies
run: |
dpkg --add-architecture $TARGET_ARCH
apt-get update && apt-get install -y --no-install-recommends \
crossbuild-essential-$TARGET_ARCH \
libx11-dev:$TARGET_ARCH \
libx11-xcb-dev:$TARGET_ARCH \
libxkbfile-dev:$TARGET_ARCH \
libsecret-1-dev:$TARGET_ARCH \
libkrb5-dev:$TARGET_ARCH \
ca-certificates \
curl wget rsync gettext-base
- name: Install nfpm
run: |
@@ -157,28 +160,22 @@ jobs:
curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install cross-compiler
run: sudo apt update && sudo apt install $PACKAGE
env:
PACKAGE: ${{ format('g++-{0}', matrix.prefix) }}
- name: Download npm package
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: npm-release-package
- name: Decompress npm package
run: tar -xzf package.tar.gz
# NOTE@jsjoeio - npm fails here
# so use yarn
- name: Build standalone release
run: yarn release:standalone
run: npm run release:standalone
- name: Replace node with cross-compile equivalent
run: |
wget https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-${NPM_CONFIG_ARCH}.tar.xz
tar -xf node-${NODE_VERSION}-linux-${NPM_CONFIG_ARCH}.tar.xz node-${NODE_VERSION}-linux-${NPM_CONFIG_ARCH}/bin/node --strip-components=2
node_version=$(node --version)
wget https://nodejs.org/dist/${node_version}/node-${node_version}-linux-${npm_config_arch}.tar.xz
tar -xf node-${node_version}-linux-${npm_config_arch}.tar.xz node-${node_version}-linux-${npm_config_arch}/bin/node --strip-components=2
mv ./node ./release-standalone/lib/node
# NOTE@jsjoeio - we do this so we can strip out the v
@@ -191,7 +188,7 @@ jobs:
- name: Build packages with nfpm
env:
VERSION: ${{ env.VERSION }}
run: yarn package ${NPM_CONFIG_ARCH}
run: npm run package ${npm_config_arch}
- uses: softprops/action-gh-release@v1
with:
@@ -206,12 +203,12 @@ jobs:
needs: npm-version
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Install nfpm
run: |
@@ -219,8 +216,15 @@ jobs:
curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
echo "$HOME/.local/bin" >> $GITHUB_PATH
# The version of node-gyp we use depends on distutils but it was removed
# in Python 3.12. It seems to be fixed in the latest node-gyp so when we
# next update Node we can probably remove this. For now, install
# setuptools since it contains distutils.
- name: Install Python utilities
run: python3 -m pip install setuptools
- name: Download npm package
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: npm-release-package
@@ -261,7 +265,7 @@ jobs:
needs: npm-version
steps:
- name: Download npm package
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: npm-release-package
@@ -277,7 +281,7 @@ jobs:
timeout-minutes: 15
steps:
- name: Download artifacts
uses: dawidd6/action-download-artifact@v2
uses: dawidd6/action-download-artifact@v3
id: download
with:
branch: ${{ github.ref }}
@@ -305,7 +309,7 @@ jobs:
npm version --prefix release "$VERSION"
echo "Updating version in lib/vscode/product.json"
tmp=$(mktemp)
tmp=$(mktemp)
jq ".codeServerVersion = \"$VERSION\"" release/lib/vscode/product.json > "$tmp" && mv "$tmp" release/lib/vscode/product.json
# Ensure it has the same permissions as before
chmod 644 release/lib/vscode/product.json
@@ -314,7 +318,7 @@ jobs:
run: tar -czf package.tar.gz release
- name: Upload npm package artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: npm-release-package
path: ./package.tar.gz

View File

@@ -41,7 +41,7 @@ jobs:
container: "alpine:3.17"
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install test utilities
run: apk add bats checkbashisms
@@ -58,7 +58,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install lint utilities
run: sudo apt install shellcheck

View File

@@ -25,30 +25,21 @@ jobs:
timeout-minutes: 15
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Node.js v16
uses: actions/setup-node@v3
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "16"
node-version-file: .node-version
- name: Fetch dependencies from cache
id: cache-yarn
uses: actions/cache@v3
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
yarn-build-
- name: Audit yarn for vulnerabilities
run: yarn audit
if: success()
- name: Install dependencies
if: steps.cache-yarn.outputs.cache-hit != 'true'
run: SKIP_SUBMODULE_DEPS=1 yarn --frozen-lockfile
- name: Audit for vulnerabilities
run: yarn _audit
- name: Audit npm for vulnerabilities
run: npm shrinkwrap && npm audit
if: success()
trivy-scan-repo:
@@ -59,12 +50,12 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Trivy vulnerability scanner in repo mode
uses: aquasecurity/trivy-action@e5f43133f6e8736992c9f3c1b3296e24b37e17f2
uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca
with:
scan-type: "fs"
scan-ref: "."
@@ -75,7 +66,7 @@ jobs:
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: "trivy-repo-results.sarif"
@@ -89,17 +80,17 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
config-file: ./.github/codeql-config.yml
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

View File

@@ -48,10 +48,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner in image mode
uses: aquasecurity/trivy-action@e5f43133f6e8736992c9f3c1b3296e24b37e17f2
uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca
with:
image-ref: "docker.io/codercom/code-server:latest"
ignore-unfixed: true
@@ -60,6 +60,6 @@ jobs:
severity: "HIGH,CRITICAL"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: "trivy-image-results.sarif"

View File

@@ -1 +1 @@
16
18.17.1

View File

@@ -20,6 +20,198 @@ Code v99.99.999
-->
## Unreleased
## [4.21.1](https://github.com/coder/code-server/releases/tag/v4.21.1) - 2021-02-09
Code v1.86.1
## Changed
- Updated to Code 1.86.1.
- Updated to Node 18.17.1.
## Added
- Docker images for Fedora and openSUSE.
## [4.21.0](https://github.com/coder/code-server/releases/tag/v4.21.0) - 2021-02-05
Code v1.86.0
## Changed
- Updated to Code 1.86.0.
## [4.20.1](https://github.com/coder/code-server/releases/tag/v4.20.1) - 2021-01-22
Code v1.85.2
## Changed
- Updated to Code 1.85.2.
## Fixed
- Query variables are no longer double-encoded when going over the path proxy.
## [4.20.0](https://github.com/coder/code-server/releases/tag/v4.20.0) - 2023-12-21
Code v1.85.1
### Added
- New flag `--disable-file-uploads` to disable uploading files to the remote by
drag and drop and to disable opening local files via the "show local" button
in the file open prompt. Note that you can still open local files by drag and
dropping the file onto the editor pane.
- Added `wget` to the release image.
### Changed
- Updated to Code 1.85.1.
- The `--disable-file-downloads` flag will now disable the "show local" button
in the file save prompt as well.
- Debian release image updated to use Bookworm.
## [4.19.1](https://github.com/coder/code-server/releases/tag/v4.19.1) - 2023-11-29
Code v1.84.2
### Fixed
- Fixed an issue where parts of the editor would not load (like the file
explorer, source control, etc) when using a workspace file.
## [4.19.0](https://github.com/coder/code-server/releases/tag/v4.19.0) - 2023-11-18
Code v1.84.2
### Changed
- Updated to Code 1.84.2.
## [4.18.0](https://github.com/coder/code-server/releases/tag/v4.18.0) - 2023-10-20
Code v1.83.1
### Changed
- Updated to Code 1.83.1.
## [4.17.1](https://github.com/coder/code-server/releases/tag/v4.17.1) - 2023-09-29
Code v1.82.2
### Fixed
- Make secret storage persistent. For example, logging in with GitHub should
persist between browser refreshes and code-server restarts.
- Issues with argon2 on arm builds should be fixed now.
## [4.17.0](https://github.com/coder/code-server/releases/tag/v4.17.0) - 2023-09-22
Code v1.82.2
### Added
- Japanese locale.
- `CODE_SERVER_HOST` environment variable.
### Changed
- Update to Code 1.82.2. This includes an update to Node 18, which also means
that the minimum glibc is now 2.28. If you need to maintain a lower glibc then
you can take a version of Node 18 that is compiled with a lower glibc and use
that to build code-server (or at a minimum rebuild the native modules).
- Display paths to config files in full rather than abbreviated. If you have
trouble with the password not working please update and make sure the
displayed config paths are what you expect.
### Fixed
- Fix some dependency issues for the standalone arm64 and armv7l releases. If
you had issues with missing or failing modules please try these new builds.
## [4.16.1](https://github.com/coder/code-server/releases/tag/v4.16.1) - 2023-07-31
Code v1.80.2
### Changed
- Updated to Code 1.80.2.
## [4.16.0](https://github.com/coder/code-server/releases/tag/v4.16.0) - 2023-07-28
Code v1.80.1
### Added
- `--disable-proxy` flag. This disables the domain and path proxies but it does
not disable the ports panel in Code. That can be disabled by using
`remote.autoForwardPorts=false` in your settings.
## [4.15.0](https://github.com/coder/code-server/releases/tag/v4.15.0) - 2023-07-21
Code v1.80.1
### Changed
- Updated to Code 1.80.1.
### Added
- `--trusted-origin` flag for specifying origins that you trust but do not
control (for example a reverse proxy).
Code v1.79.2
## [4.14.1](https://github.com/coder/code-server/releases/tag/v4.14.1) - 2023-06-26
Code v1.79.2
### Security
- Remove extra write permissions on the Node binary bundled with the linux-amd64
tarball. If you extract the tar without a umask this could mean the Node
binary would be unexpectedly writable.
### Fixed
- Inability to launch multiple instances of code-server for different users.
### Added
- `--session-socket` CLI flag to configure the location of the session socket.
By default it will be placed in `<user data dir>/code-server-ipc.sock`.
## [4.14.0](https://github.com/coder/code-server/releases/tag/v4.14.0) - 2023-06-16
Code v1.79.2
### Added
- `--domain-proxy` now supports `{{port}}` and `{{host}}` template variables.
### Changed
- Updated to Code 1.79.2
- Files opened from an external terminal will now open in the most closely
related window rather than in the last opened window.
## [4.13.0](https://github.com/coder/code-server/releases/tag/v4.13.0) - 2023-05-19
Code v1.78.2
### Changed
- Updated to Code 1.78.2.
### Fixed
- Proxying files that contain non-ASCII characters.
- Origin check when X-Forwarded-Host contains comma-separated hosts.
## [4.12.0](https://github.com/coder/code-server/releases/tag/v4.12.0) - 2023-04-21
Code v1.77.3
@@ -193,7 +385,7 @@ Code v1.71.0
### Fixed
- Add flags --unsafe-perm --legacy-peer-deps in `npm-postinstsall.sh` which ensures installing with npm works correctly
- Add flags --unsafe-perm --legacy-peer-deps in `npm-postinstall.sh` which ensures installing with npm works correctly
## [4.6.1](https://github.com/coder/code-server/releases/tag/v4.6.1) - 2022-09-31

View File

@@ -27,7 +27,7 @@ main() {
release_archive() {
local release_name="code-server-$VERSION-$OS-$ARCH"
if [[ $OS == "linux" ]]; then
tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
tar -czf "release-packages/$release_name.tar.gz" --owner=0 --group=0 --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
else
tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone
fi

View File

@@ -56,7 +56,6 @@ bundle_code_server() {
}
EOF
) > "$RELEASE_PATH/package.json"
rsync yarn.lock "$RELEASE_PATH"
mv npm-shrinkwrap.json "$RELEASE_PATH"
rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh"
@@ -95,12 +94,10 @@ bundle_vscode() {
"$VSCODE_SRC_PATH/remote/package.json" \
"$VSCODE_SRC_PATH/package.json" > "$VSCODE_OUT_PATH/package.json"
rsync "$VSCODE_SRC_PATH/remote/yarn.lock" "$VSCODE_OUT_PATH/yarn.lock"
mv "$VSCODE_SRC_PATH/remote/npm-shrinkwrap.json" "$VSCODE_OUT_PATH/npm-shrinkwrap.json"
# Include global extension dependencies as well.
rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions/package.json"
rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions/yarn.lock"
mv "$VSCODE_SRC_PATH/extensions/npm-shrinkwrap.json" "$VSCODE_OUT_PATH/extensions/npm-shrinkwrap.json"
rsync "$VSCODE_SRC_PATH/extensions/postinstall.mjs" "$VSCODE_OUT_PATH/extensions/postinstall.mjs"
}

View File

@@ -1,10 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
# This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2
# See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057
export npm_config_build_from_source=true
main() {
cd "$(dirname "${0}")/../.."
@@ -13,17 +9,19 @@ main() {
rsync "$RELEASE_PATH/" "$RELEASE_PATH-standalone"
RELEASE_PATH+=-standalone
# We cannot find the path to node from $PATH because yarn shims a script to ensure
# we use the same version it's using so we instead run a script with yarn that
# will print the path to node.
# We cannot get the path to Node from $PATH (for example via `which node`)
# because Yarn shims a script called `node` and we would end up just copying
# that script. Instead we run Node and have it print its actual path.
local node_path
node_path="$(yarn -s node <<< 'console.info(process.execPath)')"
node_path="$(node <<< 'console.info(process.execPath)')"
mkdir -p "$RELEASE_PATH/bin"
mkdir -p "$RELEASE_PATH/lib"
rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
rsync "$node_path" "$RELEASE_PATH/lib/node"
chmod 755 "$RELEASE_PATH/lib/node"
pushd "$RELEASE_PATH"
npm install --unsafe-perm --omit=dev
popd

View File

@@ -40,6 +40,16 @@ main() {
source ./ci/lib.sh
# Set the commit Code will embed into the product.json. We need to do this
# since Code tries to get the commit from the `.git` directory which will fail
# as it is a submodule.
#
# Also, we use code-server's commit rather than VS Code's otherwise it would
# not update when only our patch files change, and that will cause caching
# issues where the browser keeps using outdated code.
export BUILD_SOURCEVERSION
BUILD_SOURCEVERSION=$(git rev-parse HEAD)
pushd lib/vscode
if [[ ! ${VERSION-} ]]; then
@@ -48,14 +58,11 @@ main() {
exit 1
fi
# Set the commit Code will embed into the product.json. We need to do this
# since Code tries to get the commit from the `.git` directory which will fail
# as it is a submodule.
export BUILD_SOURCEVERSION
BUILD_SOURCEVERSION=$(git rev-parse HEAD)
# Add the date, our name, links, and enable telemetry (this just makes
# telemetry available; telemetry can still be disabled by flag or setting).
# Add the date, our name, links, enable telemetry (this just makes telemetry
# available; telemetry can still be disabled by flag or setting), and
# configure trusted extensions (since some, like github.copilot-chat, never
# ask to be trusted and this is the only way to get auth working).
#
# This needs to be done before building as Code will read this file and embed
# it into the client-side code.
git checkout product.json # Reset in case the script exited early.
@@ -89,6 +96,11 @@ main() {
"linkProtectionTrustedDomains": [
"https://open-vsx.org"
],
"trustedExtensionAuthAccess": [
"vscode.git", "vscode.github",
"github.vscode-pull-request-github",
"github.copilot", "github.copilot-chat"
],
"aiConfig": {
"ariaKey": "code-server"
}
@@ -112,7 +124,7 @@ EOF
pushd lib/vscode-reh-web-linux-x64
# Make sure Code took the version we set in the environment variable. Not
# having a version will break display languages.
if ! jq -e .commit product.json ; then
if ! jq -e .commit product.json; then
echo "'commit' is missing from product.json"
exit 1
fi

View File

@@ -53,10 +53,6 @@ symlink_bin_script() {
OS="$(os)"
# This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2
# See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057
export npm_config_build_from_source=true
main() {
# Grabs the major version of node from $npm_config_user_agent which looks like
# yarn/1.21.1 npm/? node/v14.2.0 darwin x64
@@ -68,8 +64,8 @@ main() {
echo "USE AT YOUR OWN RISK!"
fi
if [ "$major_node_version" -ne "${FORCE_NODE_VERSION:-16}" ]; then
echo "ERROR: code-server currently requires node v16."
if [ "$major_node_version" -ne "${FORCE_NODE_VERSION:-18}" ]; then
echo "ERROR: code-server currently requires node v18."
if [ -n "$FORCE_NODE_VERSION" ]; then
echo "However, you have overrided the version check to use v$FORCE_NODE_VERSION."
fi
@@ -113,29 +109,40 @@ install_with_yarn_or_npm() {
# HACK: NPM's use of semver doesn't like resolving some peerDependencies that vscode (upstream) brings in the form of pre-releases.
# The legacy behavior doesn't complain about pre-releases being used, falling back to that for now.
# See https://github.com//pull/5071
npm install --unsafe-perm --legacy-peer-deps --omit=dev
if ! npm install --unsafe-perm --legacy-peer-deps --omit=dev; then
return 1
fi
;;
yarn*)
yarn --production --frozen-lockfile --no-default-rc
if ! yarn --production --frozen-lockfile --no-default-rc; then
return 1
fi
;;
*)
echo "Could not determine which package manager is being used to install code-server"
exit 1
;;
esac
return 0
}
vscode_install() {
echo 'Installing Code dependencies...'
cd lib/vscode
install_with_yarn_or_npm
if ! install_with_yarn_or_npm; then
return 1
fi
symlink_asar
symlink_bin_script remote-cli code code-server
symlink_bin_script helpers browser browser .sh
cd extensions
install_with_yarn_or_npm
if ! install_with_yarn_or_npm; then
return 1
fi
return 0
}
main "$@"

View File

@@ -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.8.0
version: 3.17.1
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: 4.12.0
appVersion: 4.21.1

View File

@@ -20,6 +20,9 @@ spec:
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Values.podAnnotations }}
annotations: {{- toYaml .Values.podAnnotations | nindent 8 }}
{{- end }}
spec:
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
{{- if .Values.hostnameOverride }}

View File

@@ -1,3 +1,4 @@
{{- if not .Values.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
@@ -11,8 +12,9 @@ metadata:
app.kubernetes.io/managed-by: {{ .Release.Service }}
type: Opaque
data:
{{ if .Values.password }}
{{- if .Values.password }}
password: "{{ .Values.password | b64enc }}"
{{ else }}
{{- else }}
password: "{{ randAlphaNum 24 | b64enc }}"
{{ end }}
{{- end }}
{{- end }}

View File

@@ -6,7 +6,7 @@ replicaCount: 1
image:
repository: codercom/code-server
tag: '4.12.0'
tag: '4.21.1'
pullPolicy: Always
# Specifies one or more secrets to be used when pulling images from a
@@ -71,7 +71,7 @@ extraArgs: []
# Optional additional environment variables
extraVars: []
# - name: DISABLE_TELEMETRY
# value: true
# value: "true"
# - name: DOCKER_HOST
# value: "tcp://localhost:2375"

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:experimental
ARG BASE=debian:11
ARG BASE=debian:12
FROM scratch AS packages
COPY release-packages/code-server*.deb /tmp/
@@ -10,18 +10,19 @@ RUN apt-get update \
&& apt-get install -y \
curl \
dumb-init \
zsh \
htop \
locales \
man \
nano \
git \
git-lfs \
procps \
openssh-client \
sudo \
vim.tiny \
htop \
locales \
lsb-release \
man-db \
nano \
openssh-client \
procps \
sudo \
vim-tiny \
wget \
zsh \
&& git lfs install \
&& rm -rf /var/lib/apt/lists/*
@@ -34,7 +35,7 @@ RUN adduser --gecos '' --disabled-password coder \
&& echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN ARCH="$(dpkg --print-architecture)" \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.5/fixuid-0.5-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid \

View File

@@ -0,0 +1,51 @@
# syntax=docker/dockerfile:experimental
ARG BASE=fedora:39
FROM scratch AS packages
COPY release-packages/code-server*.rpm /tmp/
FROM $BASE
RUN dnf update -y \
&& dnf install -y \
curl \
git \
git-lfs \
htop \
nano \
openssh-clients \
procps \
wget \
zsh \
dumb-init \
glibc-langpack-en \
&& rm -rf /var/cache/dnf
RUN git lfs install
ENV LANG=en_US.UTF-8
RUN echo 'LANG="en_US.UTF-8"' > /etc/locale.conf
RUN useradd -u 1000 coder && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')" \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid \
&& printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
RUN --mount=from=packages,src=/tmp,dst=/tmp/packages rpm -i /tmp/packages/code-server*$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g').rpm
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
ENV ENTRYPOINTD=${HOME}/entrypoint.d
EXPOSE 8080
# This way, if someone sets $DOCKER_USER, docker-exec will still work as
# the uid will remain the same. note: only relevant if -u isn't passed to
# docker-run.
USER 1000
ENV USER=coder
WORKDIR /home/coder
ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]

View File

@@ -0,0 +1,51 @@
# syntax=docker/dockerfile:experimental
ARG BASE=opensuse/tumbleweed
FROM scratch AS packages
COPY release-packages/code-server*.rpm /tmp/
FROM $BASE
RUN zypper dup -y \
&& zypper in -y \
curl \
git \
git-lfs \
htop \
nano \
openssh-clients \
procps \
wget \
zsh \
sudo \
catatonit \
&& rm -rf /var/cache/zypp /var/cache/zypper
RUN git lfs install
ENV LANG=en_US.UTF-8
RUN echo 'LANG="en_US.UTF-8"' > /etc/locale.conf
RUN useradd -u 1000 coder && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')" \
&& curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
&& chown root:root /usr/local/bin/fixuid \
&& chmod 4755 /usr/local/bin/fixuid \
&& mkdir -p /etc/fixuid \
&& printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
COPY ci/release-image/entrypoint-catatonit.sh /usr/bin/entrypoint-catatonit.sh
RUN --mount=from=packages,src=/tmp,dst=/tmp/packages rpm -i /tmp/packages/code-server*$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g').rpm
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
ENV ENTRYPOINTD=${HOME}/entrypoint.d
EXPOSE 8080
# This way, if someone sets $DOCKER_USER, docker-exec will still work as
# the uid will remain the same. note: only relevant if -u isn't passed to
# docker-run.
USER 1000
ENV USER=coder
WORKDIR /home/coder
ENTRYPOINT ["/usr/bin/entrypoint-catatonit.sh", "--bind-addr", "0.0.0.0:8080", "."]

View File

@@ -16,8 +16,10 @@ variable "GITHUB_REGISTRY" {
group "default" {
targets = [
"code-server-debian-11",
"code-server-debian-12",
"code-server-ubuntu-focal",
"code-server-fedora-39",
"code-server-opensuse-tumbleweed",
]
}
@@ -45,12 +47,12 @@ function "gen_tags_for_docker_and_ghcr" {
)
}
target "code-server-debian-11" {
target "code-server-debian-12" {
dockerfile = "ci/release-image/Dockerfile"
tags = concat(
gen_tags_for_docker_and_ghcr(""),
gen_tags_for_docker_and_ghcr("debian"),
gen_tags_for_docker_and_ghcr("bullseye"),
gen_tags_for_docker_and_ghcr("bookworm"),
)
platforms = ["linux/amd64", "linux/arm64"]
}
@@ -66,3 +68,27 @@ target "code-server-ubuntu-focal" {
}
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-fedora-39" {
dockerfile = "ci/release-image/Dockerfile.fedora"
tags = concat(
gen_tags_for_docker_and_ghcr("fedora"),
gen_tags_for_docker_and_ghcr("39"),
)
args = {
BASE = "fedora:39"
}
platforms = ["linux/amd64", "linux/arm64"]
}
target "code-server-opensuse-tumbleweed" {
dockerfile = "ci/release-image/Dockerfile.opensuse"
tags = concat(
gen_tags_for_docker_and_ghcr("opensuse"),
gen_tags_for_docker_and_ghcr("tumbleweed"),
)
args = {
BASE = "opensuse/tumbleweed"
}
platforms = ["linux/amd64", "linux/arm64"]
}

View File

@@ -0,0 +1,27 @@
#!/bin/sh
set -eu
# We do this first to ensure sudo works below when renaming the user.
# Otherwise the current container UID may not exist in the passwd database.
eval "$(fixuid -q)"
if [ "${DOCKER_USER-}" ]; then
USER="$DOCKER_USER"
if [ "$DOCKER_USER" != "$(whoami)" ]; then
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
# Unfortunately we cannot change $HOME as we cannot move any bind mounts
# nor can we bind mount $HOME into a new home as that requires a privileged container.
sudo usermod --login "$DOCKER_USER" coder
sudo groupmod -n "$DOCKER_USER" coder
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
fi
fi
# Allow users to have scripts run on container startup to prepare workspace.
# https://github.com/coder/code-server/issues/5177
if [ -d "${ENTRYPOINTD}" ]; then
find "${ENTRYPOINTD}" -type f -executable -print -exec {} \;
fi
exec catatonit -- /usr/bin/code-server "$@"

View File

@@ -37,7 +37,7 @@ for [VS
Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
Here is what is needed:
- `node` v16.x
- `node` v18.x
- `git` v2.x or greater
- [`git-lfs`](https://git-lfs.github.com)
- [`yarn`](https://classic.yarnpkg.com/en/)
@@ -63,7 +63,7 @@ Here is what is needed:
If you're developing code-server on Linux, make sure you have installed or install the following dependencies:
```shell
sudo apt-get install build-essential g++ libx11-dev libxkbfile-dev libsecret-1-dev python-is-python3
sudo apt-get install build-essential g++ libx11-dev libxkbfile-dev libsecret-1-dev libkrb5-dev python-is-python3
```
These are required by Code. See [their Wiki](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites) for more information.
@@ -127,13 +127,13 @@ while quilt push; do quilt refresh; done
0. You can go through the patch stack with `quilt push` and `quilt pop`.
1. Create a new patch (`quilt new {name}.diff`) or use an existing patch.
2. Add the file(s) you are patching (`quilt add [-P patch] {file}`). A file
1. Add the file(s) you are patching (`quilt add [-P patch] {file}`). A file
**must** be added before you make changes to it.
3. Make your changes. Patches do not need to be independent of each other but
1. Make your changes. Patches do not need to be independent of each other but
each patch must result in a working code-server without any broken in-between
states otherwise they are difficult to test and modify.
4. Add your changes to the patch (`quilt refresh`)
5. Add a comment in the patch about the reason for the patch and how to
1. Add your changes to the patch (`quilt refresh`)
1. Add a comment in the patch about the reason for the patch and how to
reproduce the behavior it fixes or adds. Every patch should have an e2e test
as well.

View File

@@ -14,6 +14,7 @@
- [How do I install an extension manually?](#how-do-i-install-an-extension-manually)
- [How do I use my own extensions marketplace?](#how-do-i-use-my-own-extensions-marketplace)
- [Where are extensions stored?](#where-are-extensions-stored)
- [Where is VS Code configuration stored?](#where-is-vs-code-configuration-stored)
- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
- [How do I access my Documents/Downloads/Desktop folders in code-server on macOS?](#how-do-i-access-my-documentsdownloadsdesktop-folders-in-code-server-on-macos)
@@ -34,6 +35,7 @@
- [Are there community projects involving code-server?](#are-there-community-projects-involving-code-server)
- [How do I change the port?](#how-do-i-change-the-port)
- [How do I hide the coder/coder promotion in Help: Getting Started?](#how-do-i-hide-the-codercoder-promotion-in-help-getting-started)
- [How do I disable the proxy?](#how-do-i-disable-the-proxy)
- [How do I disable file download?](#how-do-i-disable-file-download)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -175,10 +177,10 @@ If you own a marketplace that implements the VS Code Extension Gallery API, you
can point code-server to it by setting `$EXTENSIONS_GALLERY`.
This corresponds directly with the `extensionsGallery` entry in in VS Code's `product.json`.
For example, to use the legacy Coder extensions marketplace:
For example:
```bash
export EXTENSIONS_GALLERY='{"serviceUrl": "https://extensions.coder.com/api"}'
export EXTENSIONS_GALLERY='{"serviceUrl": "https://my-extensions/api"}'
```
Though you can technically use Microsoft's marketplace in this manner, we
@@ -191,10 +193,20 @@ docs](https://github.com/VSCodium/vscodium/blob/master/DOCS.md#extensions--marke
## Where are extensions stored?
Extensions are store, by default, to `~/.local/share/code-server/extensions`.
Extensions are stored in `~/.local/share/code-server/extensions` by default.
If you set the `XDG_DATA_HOME` environment variable, the data directory will be
`$XDG_DATA_HOME/code-server/extensions`. In general, we try to follow the XDG directory spec.
On Linux and macOS if you set the `XDG_DATA_HOME` environment variable, the
extensions directory will be `$XDG_DATA_HOME/code-server/extensions`. In
general, we try to follow the XDG directory spec.
## Where is VS Code configuration stored?
VS Code configuration such as settings and keybindings are stored in
`~/.local/share/code-server` by default.
On Linux and macOS if you set the `XDG_DATA_HOME` environment variable, the data
directory will be `$XDG_DATA_HOME/code-server`. In general, we try to follow the
XDG directory spec.
## How can I reuse my VS Code configuration?
@@ -344,6 +356,12 @@ hashed-password: "$argon2i$v=19$m=4096,t=3,p=1$wST5QhBgk2lu1ih4DMuxvg$LS1alrVdIW
The `hashed-password` field takes precedence over `password`.
If you're using Docker Compose file, in order to make this work, you need to change all the single $ to $$. For example:
```yaml
- HASHED_PASSWORD=$$argon2i$$v=19$$m=4096,t=3,p=1$$wST5QhBgk2lu1ih4DMuxvg$$LS1alrVdIWtvZHwnzCM1DUGg+5DTO3Dt1d5v9XtLws4
```
## Is multi-tenancy possible?
If you want to run multiple code-servers on shared infrastructure, we recommend
@@ -453,6 +471,19 @@ You can pass the flag `--disable-getting-started-override` to `code-server` or
you can set the environment variable `CS_DISABLE_GETTING_STARTED_OVERRIDE=1` or
`CS_DISABLE_GETTING_STARTED_OVERRIDE=true`.
## How do I disable the proxy?
You can pass the flag `--disable-proxy` to `code-server` or
you can set the environment variable `CS_DISABLE_PROXY=1` or
`CS_DISABLE_PROXY=true`.
Note, this option currently only disables the proxy routes to forwarded ports, including
the domain and path proxy routes over HTTP and WebSocket; however, it does not
disable the automatic port forwarding in the VS Code workbench itself. In other words,
user will still see the Ports tab and notifications, but will not be able to actually
use access the ports. It is recommended to set `remote.autoForwardPorts` to `false`
when using the option.
## How do I disable file download?
You can pass the flag `--disable-file-downloads` to `code-server`

View File

@@ -171,7 +171,7 @@ We publish to AUR as a package [here](https://aur.archlinux.org/packages/code-se
#### Docker
We publish code-server as a Docker image [here](https://registry.hub.docker.com/r/codercom/code-server), tagging it both with the version and latest.
We publish code-server as a Docker image [here](https://hub.docker.com/r/codercom/code-server), tagging it both with the version and latest.
This is currently automated with the release process.

View File

@@ -5,7 +5,8 @@
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and
access it in the browser.
![Screenshot](./assets/screenshot.png)
![Screenshot](./assets/screenshot-1.png)
![Screenshot](./assets/screenshot-2.png)
## Highlights
@@ -72,7 +73,7 @@ details.
Interested in [working at Coder](https://coder.com/careers)? Check out [our open
positions](https://coder.com/careers#openings)!
## For Organizations
## For Teams
Want remote development for your organization or enterprise? Visit [our
website](https://coder.com) to learn more about Coder.
We develop [coder/coder](https://cdr.co/coder-github) to help teams to
adopt remote development.

View File

@@ -11,11 +11,11 @@ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
```
6. Exit the terminal using `exit` and then reopen the terminal
7. Install and use Node.js 16:
7. Install and use Node.js 18:
```shell
nvm install 16
nvm use 16
nvm install 18
nvm use 18
```
8. Install code-server globally on device with: `npm install --global code-server --unsafe-perm`

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 KiB

View File

@@ -33,5 +33,16 @@ resource "coder_app" "code-server" {
}
```
Or use our official [`code-server`](https://registry.coder.com/modules/code-server) module from the Coder [module registry](htpps://registry.coder.com/modules):
```terraform
module "code-server" {
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.5"
agent_id = coder_agent.example.id
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
}
```
If you run into issues, ask for help on the `coder/coder` [Discussions
here](https://github.com/coder/coder/discussions).

View File

@@ -19,6 +19,7 @@
- [Proxying to create a React app](#proxying-to-create-a-react-app)
- [Proxying to a Vue app](#proxying-to-a-vue-app)
- [Proxying to an Angular app](#proxying-to-an-angular-app)
- [Proxying to a Svelte app](#proxying-to-a-svelte-app)
- [SSH into code-server on VS Code](#ssh-into-code-server-on-vs-code)
- [Option 1: cloudflared tunnel](#option-1-cloudflared-tunnel)
- [Option 2: ngrok tunnel](#option-2-ngrok-tunnel)
@@ -138,9 +139,9 @@ sudo apt install caddy
1. Replace `/etc/caddy/Caddyfile` using `sudo` so that the file looks like this:
```text
mydomain.com
reverse_proxy 127.0.0.1:8080
mydomain.com {
reverse_proxy 127.0.0.1:8080
}
```
If you want to serve code-server from a sub-path, you can do so as follows:
@@ -190,7 +191,7 @@ At this point, you should be able to access code-server via
location / {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
@@ -414,6 +415,27 @@ In order to use code-server's built-in proxy with Angular, you need to make the
For additional context, see [this GitHub Discussion](https://github.com/coder/code-server/discussions/5439#discussioncomment-3371983).
### Proxying to a Svelte app
In order to use code-server's built-in proxy with Svelte, you need to make the following changes in your app:
1. Add `svelte.config.js` if you don't already have one
2. Update the values to match this (you can use any free port):
```js
const config = {
kit: {
paths: {
base: "/absproxy/5173",
},
},
}
```
3. Access app at `<code-server-root>/absproxy/5173/` e.g. `http://localhost:8080/absproxy/5173/
For additional context, see [this Github Issue](https://github.com/sveltejs/kit/issues/2958)
## SSH into code-server on VS Code
[![SSH](https://img.shields.io/badge/SSH-363636?style=for-the-badge&logo=GNU+Bash&logoColor=ffffff)](https://ohmyz.sh/) [![Terminal](https://img.shields.io/badge/Terminal-2E2E2E?style=for-the-badge&logo=Windows+Terminal&logoColor=ffffff)](https://img.shields.io/badge/Terminal-2E2E2E?style=for-the-badge&logo=Windows+Terminal&logoColor=ffffff) [![Visual Studio Code](https://img.shields.io/badge/Visual_Studio_Code-007ACC?style=for-the-badge&logo=Visual+Studio+Code&logoColor=ffffff)](vscode:extension/ms-vscode-remote.remote-ssh)

View File

@@ -103,10 +103,9 @@ _exact_ same commands presented in the rest of this document.
We recommend installing with `npm` when:
1. You aren't using a machine with `amd64` or `arm64`.
1. You are installing code-server on Windows
1. You're on Linux with `glibc` < v2.17, `glibcxx` < v3.4.18 on `amd64`, `glibc`
< v2.23, or `glibcxx` < v3.4.21 on `arm64`.
1. You're running Alpine Linux or are using a non-glibc libc. See
2. You are installing code-server on Windows.
3. You're on Linux with `glibc` < v2.28 or `glibcxx` < v3.4.21.
4. You're running Alpine Linux or are using a non-glibc libc. See
[#1430](https://github.com/coder/code-server/issues/1430#issuecomment-629883198)
for more information.
@@ -123,8 +122,8 @@ node binary and node modules.
We create the standalone releases using the [npm package](#npm), and we
then create the remaining releases using the standalone version.
The only requirement to use the standalone release is `glibc` >= 2.17 and
`glibcxx` >= v3.4.18 on Linux (for macOS, there is no minimum system
The only requirement to use the standalone release is `glibc` >= 2.28 and
`glibcxx` >= v3.4.21 on Linux (for macOS, there is no minimum system
requirement).
To use a standalone release:
@@ -280,6 +279,7 @@ brew services start code-server
# outside the container.
mkdir -p ~/.config
docker run -it --name code-server -p 127.0.0.1:8080:8080 \
-v "$HOME/.local:/home/coder/.local" \
-v "$HOME/.config:/home/coder/.config" \
-v "$PWD:/home/coder/project" \
-u "$(id -u):$(id -g)" \

View File

@@ -30,7 +30,7 @@ includes installing instructions based on your operating system.
## Node.js version
We use the same major version of Node.js shipped with Code's remote, which is
currently `16.x`. VS Code also [lists Node.js
currently `18.x`. VS Code also [lists Node.js
requirements](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites).
Using other versions of Node.js [may lead to unexpected
@@ -79,7 +79,7 @@ Proceed to [installing](#installing)
## FreeBSD
```sh
pkg install -y git python npm-node16 pkgconf
pkg install -y git python npm-node18 pkgconf
pkg install -y libinotify
```

View File

@@ -22,7 +22,7 @@ The following steps walk you through setting up a VM running Debian using Google
Cloud (though you are welcome to use any machine or VM provider).
If you're [signing up with Google](https://console.cloud.google.com/getting-started) for the first time, you should get a 3-month trial with
$300 of credits.
\$300 of credits.
After you sign up and create a new Google Cloud Provider (GCP) project, create a
new Compute Engine VM instance:

View File

@@ -8,7 +8,9 @@
- [Upgrade](#upgrade)
- [Known Issues](#known-issues)
- [Git won't work in `/sdcard`](#git-wont-work-in-sdcard)
- [Many extensions including language packs fail to install](#many-extensions-including-language-packs-fail-to-install)
- [Extra](#extra)
- [Keyboard Shortcuts and Tab Key](#keyboard-shortcuts-and-tab-key)
- [Create a new user](#create-a-new-user)
- [Install Go](#install-go)
- [Install Python](#install-python)
@@ -55,7 +57,7 @@ npm config set python python3
node -v
```
you will get node version `v16.15.0`
you will get Node version `v18`
5. Now install code-server following our guide on [installing with npm](./npm.md)
@@ -87,8 +89,50 @@ Potential Workaround :
1. Create a soft-link from the debian-fs to your folder in `/sdcard`
2. Use git from termux (preferred)
### Many extensions including language packs fail to install
Issue: Android is not seen as a Linux environment but as a separate, unsupported platform, so code-server only allows [Web Extensions](https://code.visualstudio.com/api/extension-guides/web-extensions), refusing to download extensions that run on the server.\
Fix: None\
Potential workarounds :
Either
- Manually download extensions as `.vsix` file and install them via `Extensions: Install from VSIX...` in the Command Palette.
- Use an override to pretend the platform is Linux:
Create a JS script that patches `process.platform`:
```js
// android-as-linux.js
Object.defineProperty(process, "platform", {
get() {
return "linux"
},
})
```
Then use Node's `--require` option to make sure it is loaded before `code-server` starts:
```sh
NODE_OPTIONS="--require /path/to/android-as-linux.js" code-server
```
⚠️ Note that Android and Linux are not 100% compatible, so use these workarounds at your own risk. Extensions that have native dependencies other than Node or that directly interact with the OS might cause issues.
## Extra
### Keyboard Shortcuts and Tab Key
In order to support the tab key and use keyboard shortcuts, add this to your
settings.json:
```json
{
"keyboard.dispatch": "keyCode"
}
```
### Create a new user
To create a new user follow these simple steps -

View File

@@ -7,14 +7,14 @@
flake-utils.lib.eachDefaultSystem
(system:
let pkgs = nixpkgs.legacyPackages.${system};
nodejs = pkgs.nodejs-16_x;
nodejs = pkgs.nodejs-18_x;
yarn' = pkgs.yarn.override { inherit nodejs; };
in {
devShells.default = pkgs.mkShell {
nativeBuildInputs = with pkgs; [
nodejs yarn' python3 pkg-config git rsync jq moreutils quilt bats
nodejs yarn' python3 pkg-config git rsync jq moreutils quilt bats openssl
];
buildInputs = with pkgs; (lib.optionals (!stdenv.isDarwin) [ libsecret ]
buildInputs = with pkgs; (lib.optionals (!stdenv.isDarwin) [ libsecret libkrb5 ]
++ (with xorg; [ libX11 libxkbfile ])
++ lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [
AppKit Cocoa CoreServices Security xcbuild

View File

@@ -441,7 +441,7 @@ install_npm() {
return
fi
echoerr "Please install npm to install code-server!"
echoerr "You will need at least node v12 and a few C dependencies."
echoerr "You will need at least node v18 and a few C dependencies."
echoerr "See the docs https://coder.com/docs/code-server/latest/install#npm"
exit 1

View File

@@ -38,77 +38,62 @@
},
"main": "out/node/entry.js",
"devDependencies": {
"@schemastore/package": "^0.0.6",
"@types/compression": "^1.7.0",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.8",
"@types/http-proxy": "^1.17.4",
"@types/js-yaml": "^4.0.0",
"@types/node": "^16.0.0",
"@types/pem": "^1.9.5",
"@schemastore/package": "^0.0.10",
"@types/compression": "^1.7.3",
"@types/cookie-parser": "^1.4.4",
"@types/express": "^4.17.17",
"@types/http-proxy": "1.17.7",
"@types/js-yaml": "^4.0.6",
"@types/node": "^18.0.0",
"@types/pem": "^1.14.1",
"@types/proxy-from-env": "^1.0.1",
"@types/safe-compare": "^1.1.0",
"@types/semver": "^7.1.0",
"@types/split2": "^3.2.0",
"@types/trusted-types": "^2.0.2",
"@types/ws": "^8.5.3",
"@typescript-eslint/eslint-plugin": "^5.41.0",
"@typescript-eslint/parser": "^5.41.0",
"audit-ci": "^6.0.0",
"doctoc": "2.2.1",
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "2.8.0",
"prettier-plugin-sh": "^0.12.8",
"ts-node": "^10.0.0",
"typescript": "^4.6.2"
},
"resolutions": {
"ansi-regex": "^5.0.1",
"normalize-package-data": "^5.0.0",
"doctoc/underscore": "^1.13.1",
"doctoc/**/trim": "^1.0.0",
"postcss": "^8.2.1",
"browserslist": "^4.16.5",
"safe-buffer": "^5.1.1",
"vfile-message": "^2.0.2",
"tar": "^6.1.9",
"path-parse": "^1.0.7",
"vm2": "^3.9.11",
"follow-redirects": "^1.14.8",
"node-fetch": "^2.6.7",
"nanoid": "^3.1.31",
"minimist": "npm:minimist-lite@2.2.1",
"glob-parent": "^6.0.1",
"@types/node": "^16.0.0",
"qs": "^6.7.3"
"@types/semver": "^7.5.2",
"@types/trusted-types": "^2.0.4",
"@types/ws": "^8.5.5",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"audit-ci": "^6.6.1",
"doctoc": "^2.2.1",
"eslint": "^8.49.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "^3.0.3",
"prettier-plugin-sh": "^0.13.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"dependencies": {
"@coder/logger": "^3.0.0",
"argon2": "0.30.3",
"@coder/logger": "^3.0.1",
"argon2": "^0.31.1",
"compression": "^1.7.4",
"cookie-parser": "^1.4.5",
"env-paths": "^2.2.0",
"cookie-parser": "^1.4.6",
"env-paths": "^2.2.1",
"express": "5.0.0-alpha.8",
"http-proxy": "^1.18.0",
"http-proxy": "^1.18.1",
"httpolyglot": "^0.1.2",
"i18next": "^22.4.6",
"js-yaml": "^4.0.0",
"i18next": "^23.5.1",
"js-yaml": "^4.1.0",
"limiter": "^2.1.0",
"pem": "^1.14.2",
"proxy-agent": "^5.0.0",
"qs": "6.11.0",
"rotating-file-stream": "^3.0.0",
"safe-buffer": "^5.1.1",
"pem": "^1.14.8",
"proxy-agent": "^6.3.1",
"qs": "6.9.7",
"rotating-file-stream": "^3.1.1",
"safe-buffer": "^5.2.1",
"safe-compare": "^1.1.4",
"semver": "^7.1.3",
"split2": "^4.0.0",
"ws": "^8.0.0",
"semver": "^7.5.4",
"ws": "^8.14.2",
"xdg-basedir": "^4.0.0"
},
"resolutions": {
"@types/node": "^18.0.0",
"qs": "6.9.7"
},
"overrides": {
"qs": "6.9.7"
},
"bin": {
"code-server": "out/node/entry.js"
},
@@ -122,7 +107,7 @@
"remote-development"
],
"engines": {
"node": "16"
"node": "18"
},
"jest": {
"transform": {

View File

@@ -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
@@ -167,7 +167,9 @@ class RemoteAuthoritiesImpl {
@@ -181,7 +181,9 @@ class RemoteAuthoritiesImpl {
return URI.from({
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
authority: `${host}:${port}`,
@@ -99,26 +99,19 @@ Index: code-server/lib/vscode/src/vs/platform/remote/browser/browserSocketFactor
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts
+++ code-server/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts
@@ -274,6 +274,7 @@ export class BrowserSocketFactory implem
connect(host: string, port: number, path: string, query: string, debugLabel: string, callback: IConnectCallback): void {
const webSocketSchema = (/^https:/.test(window.location.href) ? 'wss' : 'ws');
+ path = (window.location.pathname + "/" + path).replace(/\/\/+/g, "/")
const socket = this._webSocketFactory.create(`${webSocketSchema}://${(/:/.test(host) && !/\[/.test(host)) ? `[${host}]` : host}:${port}${path}?${query}&skipWebSocketFrames=false`, debugLabel);
const errorListener = socket.onError((err) => callback(err, undefined));
socket.onOpen(() => {
@@ -282,6 +283,3 @@ export class BrowserSocketFactory implem
});
}
}
-
-
-
@@ -281,6 +281,7 @@ export class BrowserSocketFactory implem
connect({ host, port }: WebSocketRemoteConnection, path: string, query: string, debugLabel: string): Promise<ISocket> {
return new Promise<ISocket>((resolve, reject) => {
const webSocketSchema = (/^https:/.test(mainWindow.location.href) ? 'wss' : 'ws');
+ path = (mainWindow.location.pathname + "/" + path).replace(/\/\/+/g, "/")
const socket = this._webSocketFactory.create(`${webSocketSchema}://${(/:/.test(host) && !/\[/.test(host)) ? `[${host}]` : host}:${port}${path}?${query}&skipWebSocketFrames=false`, debugLabel);
const errorListener = socket.onError(reject);
socket.onOpen(() => {
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
@@ -267,12 +267,11 @@ export class WebClientServer {
@@ -269,16 +269,15 @@ export class WebClientServer {
return void res.end();
}
@@ -127,16 +120,20 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
- return Array.isArray(val) ? val[0] : val;
- };
-
- const remoteAuthority = getFirstHeader('x-original-host') || getFirstHeader('x-forwarded-host') || req.headers.host;
const useTestResolver = (!this._environmentService.isBuilt && this._environmentService.args['use-test-resolver']);
+ // For now we are getting the remote authority from the client to avoid
+ // needing specific configuration for reverse proxies to work. Set this to
+ // something invalid to make sure we catch code that is using this value
+ // from the backend when it should not.
+ const remoteAuthority = 'remote';
const remoteAuthority = (
useTestResolver
? 'test+test'
- : (getFirstHeader('x-original-host') || getFirstHeader('x-forwarded-host') || req.headers.host)
+ : 'remote'
);
if (!remoteAuthority) {
return serveError(req, res, 400, `Bad request.`);
}
@@ -298,8 +297,12 @@ export class WebClientServer {
@@ -305,8 +304,12 @@ export class WebClientServer {
scopes: [['user:email'], ['repo']]
} : undefined;
@@ -149,7 +146,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
embedderIdentifier: 'server-distro',
extensionsGallery: this._webExtensionResourceUrlTemplate ? {
...this._productService.extensionsGallery,
@@ -334,11 +337,12 @@ export class WebClientServer {
@@ -341,8 +344,10 @@ export class WebClientServer {
const values: { [key: string]: string } = {
WORKBENCH_WEB_CONFIGURATION: asJSON(workbenchWebConfiguration),
WORKBENCH_AUTH_SESSION: authSessionInfo ? asJSON(authSessionInfo) : '',
@@ -161,20 +158,17 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
+ VS_BASE: vscodeBase,
};
-
let data;
try {
const workbenchTemplate = (await fsp.readFile(filePath)).toString();
@@ -352,7 +356,7 @@ export class WebClientServer {
if (useTestResolver) {
@@ -369,7 +374,7 @@ export class WebClientServer {
'default-src \'self\';',
'img-src \'self\' https: data: blob:;',
'media-src \'self\';',
- `script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} 'sha256-fh3TwPMflhsEIpR8g1OYTIMVWhXTLcjQ9kh2tIpmv54=' http://${remoteAuthority};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html
+ `script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} 'sha256-fh3TwPMflhsEIpR8g1OYTIMVWhXTLcjQ9kh2tIpmv54=';`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html
- `script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} '${webWorkerExtensionHostIframeScriptSHA}' ${useTestResolver ? '' : `http://${remoteAuthority}`};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html
+ `script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} '${webWorkerExtensionHostIframeScriptSHA}' ${useTestResolver ? '' : ''};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html
'child-src \'self\';',
`frame-src 'self' https://*.vscode-cdn.net data:;`,
'worker-src \'self\' data: blob:;',
@@ -425,3 +429,70 @@ export class WebClientServer {
@@ -442,3 +447,70 @@ export class WebClientServer {
return void res.end(data);
}
}
@@ -261,23 +255,45 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -489,6 +489,7 @@ function doCreateUri(path: string, query
});
@@ -304,7 +304,8 @@ class LocalStorageURLCallbackProvider ex
this.startListening();
}
- return URI.parse(mainWindow.location.href).with({ path: this._callbackRoute, query: queryParams.join('&') });
+ const path = (mainWindow.location.pathname + "/" + this._callbackRoute).replace(/\/\/+/g, "/");
+ return URI.parse(mainWindow.location.href).with({ path: path, query: queryParams.join('&') });
}
+ path = (window.location.pathname + "/" + path).replace(/\/\/+/g, "/")
return URI.parse(window.location.href).with({ path, query });
private startListening(): void {
@@ -550,17 +551,6 @@ class WorkspaceProvider implements IWork
}
}
@@ -500,7 +501,7 @@ function doCreateUri(path: string, query
-function readCookie(name: string): string | undefined {
- const cookies = document.cookie.split('; ');
- for (const cookie of cookies) {
- if (cookie.startsWith(name + '=')) {
- return cookie.substring(name.length + 1);
- }
- }
-
- return undefined;
-}
-
(function () {
// Find config by checking for DOM
@@ -569,8 +559,8 @@ function readCookie(name: string): strin
if (!configElement || !configElementAttribute) {
throw new Error('Missing web configuration element');
}
- const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents; workspaceUri?: UriComponents; callbackRoute: string } = JSON.parse(configElementAttribute);
- const secretStorageKeyPath = readCookie('vscode-secret-key-path');
+ const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents; workspaceUri?: UriComponents; callbackRoute: string } = { ...JSON.parse(configElementAttribute), remoteAuthority: location.host }
+ const secretStorageKeyPath = (window.location.pathname + "/mint-key").replace(/\/\/+/g, "/");
const secretStorageCrypto = secretStorageKeyPath && ServerKeyedAESCrypto.supported()
? new ServerKeyedAESCrypto(secretStorageKeyPath) : new TransparentCrypto();
// Create workbench
create(document.body, {
Index: code-server/lib/vscode/src/vs/platform/extensionResourceLoader/common/extensionResourceLoader.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/extensionResourceLoader/common/extensionResourceLoader.ts
@@ -288,12 +304,12 @@ Index: code-server/lib/vscode/src/vs/platform/extensionResourceLoader/common/ext
import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
-import { RemoteAuthorities } from 'vs/base/common/network';
import { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';
import { TargetPlatform } from 'vs/platform/extensions/common/extensions';
const WEB_EXTENSION_RESOURCE_END_POINT = 'web-extension-resource';
@@ -75,7 +74,7 @@ export abstract class AbstractExtensionR
public getExtensionGalleryResourceURL(galleryExtension: { publisher: string; name: string; version: string }, path?: string): URI | undefined {
if (this._extensionGalleryResourceUrlTemplate) {
const uri = URI.parse(format2(this._extensionGalleryResourceUrlTemplate, { publisher: galleryExtension.publisher, name: galleryExtension.name, version: galleryExtension.version, path: 'extension' }));
@@ -102,7 +101,7 @@ export abstract class AbstractExtensionR
: version,
path: 'extension'
}));
- return this._isWebExtensionResourceEndPoint(uri) ? uri.with({ scheme: RemoteAuthorities.getPreferredWebSchema() }) : uri;
+ return this._isWebExtensionResourceEndPoint(uri) ? URI.joinPath(URI.parse(window.location.href), uri.path) : uri;
}

View File

@@ -17,7 +17,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/terminal/browser/remoteTe
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts
@@ -97,10 +97,14 @@ class RemoteTerminalBackend extends Base
@@ -104,10 +104,14 @@ class RemoteTerminalBackend extends Base
}
const reqId = e.reqId;
const commandId = e.commandId;

View File

@@ -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
@@ -243,6 +243,10 @@ export class Extension implements IExten
@@ -249,6 +249,10 @@ export class Extension implements IExten
if (this.type === ExtensionType.System && this.productService.quality === 'stable') {
return false;
}

View File

@@ -1,183 +0,0 @@
Add option to disable file downloads via CLI
This patch adds support for a new CLI flag called `--disable-file-downloads`
which allows a user to remove the "Download..." option that shows up when you
right-click files in Code. The default value for this is `false`.
To test this, start code-server with `--disable-file-downloads`, open editor,
right-click on a file (not a folder) and you should **not** see the
"Download..." option.
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
@@ -260,6 +260,11 @@ export interface IWorkbenchConstructionO
*/
readonly userDataPath?: string
+ /**
+ * Whether the "Download..." option is enabled for files.
+ */
+ readonly isEnabledFileDownloads?: boolean
+
//#endregion
//#region Profile options
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
@@ -32,6 +32,11 @@ export interface IBrowserWorkbenchEnviro
* Options used to configure the workbench.
*/
readonly options?: IWorkbenchConstructionOptions;
+
+ /**
+ * Enable downloading files via menu actions.
+ */
+ readonly isEnabledFileDownloads?: boolean;
}
export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvironmentService {
@@ -101,6 +106,13 @@ export class BrowserWorkbenchEnvironment
return this.options.userDataPath;
}
+ get isEnabledFileDownloads(): boolean {
+ if (typeof this.options.isEnabledFileDownloads === "undefined") {
+ throw new Error('isEnabledFileDownloads was not provided to the browser');
+ }
+ return this.options.isEnabledFileDownloads;
+ }
+
@memoize
get argvResource(): URI { return joinPath(this.userRoamingDataHome, 'argv.json'); }
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
@@ -14,6 +14,7 @@ export const serverOptions: OptionDescri
/* ----- code-server ----- */
'disable-update-check': { type: 'boolean' },
'auth': { type: 'string' },
+ 'disable-file-downloads': { type: 'boolean' },
/* ----- server setup ----- */
@@ -94,6 +95,7 @@ export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;
'auth'?: string
+ 'disable-file-downloads'?: boolean;
/* ----- server setup ----- */
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
@@ -325,6 +325,7 @@ export class WebClientServer {
remoteAuthority,
webviewEndpoint: vscodeBase + this._staticRoute + '/out/vs/workbench/contrib/webview/browser/pre',
userDataPath: this._environmentService.userDataPath,
+ isEnabledFileDownloads: !this._environmentService.args['disable-file-downloads'],
_wrapWebWorkerExtHostInIframe,
developmentOptions: { enableSmokeTestDriver: this._environmentService.args['enable-smoke-test-driver'] ? true : undefined, logLevel: this._logService.getLevel() },
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
Index: code-server/lib/vscode/src/vs/workbench/browser/contextkeys.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/contextkeys.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/contextkeys.ts
@@ -7,12 +7,11 @@ import { Event } from 'vs/base/common/ev
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey, setConstant as setConstantContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext, IsMobileContext } from 'vs/platform/contextkey/common/contextkeys';
-import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext } from 'vs/workbench/common/contextkeys';
+import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, IsEnabledFileDownloads } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
-import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { WorkbenchState, IWorkspaceContextService, isTemporaryWorkspace } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchLayoutService, Parts, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
@@ -25,6 +24,7 @@ import { IPaneCompositePartService } fro
import { Schemas } from 'vs/base/common/network';
import { WebFileSystemAccess } from 'vs/platform/files/browser/webFileSystemAccess';
import { IProductService } from 'vs/platform/product/common/productService';
+import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
export class WorkbenchContextKeysHandler extends Disposable {
private inputFocusedContext: IContextKey<boolean>;
@@ -77,7 +77,7 @@ export class WorkbenchContextKeysHandler
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IConfigurationService private readonly configurationService: IConfigurationService,
- @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
+ @IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,
@IProductService private readonly productService: IProductService,
@IEditorService private readonly editorService: IEditorService,
@IEditorResolverService private readonly editorResolverService: IEditorResolverService,
@@ -205,6 +205,9 @@ export class WorkbenchContextKeysHandler
this.auxiliaryBarVisibleContext = AuxiliaryBarVisibleContext.bindTo(this.contextKeyService);
this.auxiliaryBarVisibleContext.set(this.layoutService.isVisible(Parts.AUXILIARYBAR_PART));
+ // code-server
+ IsEnabledFileDownloads.bindTo(this.contextKeyService).set(this.environmentService.isEnabledFileDownloads ?? true)
+
this.registerListeners();
}
Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts
@@ -20,7 +20,7 @@ import { CLOSE_SAVED_EDITORS_COMMAND_ID,
import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService';
import { Schemas } from 'vs/base/common/network';
-import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/contextkeys';
+import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext, IsEnabledFileDownloads } from 'vs/workbench/common/contextkeys';
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ThemeIcon } from 'vs/base/common/themables';
@@ -485,13 +485,16 @@ MenuRegistry.appendMenuItem(MenuId.Explo
id: DOWNLOAD_COMMAND_ID,
title: DOWNLOAD_LABEL
},
- when: ContextKeyExpr.or(
- // native: for any remote resource
- ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.notEqualsTo(Schemas.file)),
- // web: for any files
- ContextKeyExpr.and(IsWebContext, ExplorerFolderContext.toNegated(), ExplorerRootContext.toNegated()),
- // web: for any folders if file system API support is provided
- ContextKeyExpr.and(IsWebContext, HasWebFileSystemAccess)
+ when: ContextKeyExpr.and(
+ IsEnabledFileDownloads,
+ ContextKeyExpr.or(
+ // native: for any remote resource
+ ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.notEqualsTo(Schemas.file)),
+ // web: for any files
+ ContextKeyExpr.and(IsWebContext, ExplorerFolderContext.toNegated(), ExplorerRootContext.toNegated()),
+ // web: for any folders if file system API support is provided
+ ContextKeyExpr.and(IsWebContext, HasWebFileSystemAccess)
+ )
)
}));
Index: code-server/lib/vscode/src/vs/workbench/common/contextkeys.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/common/contextkeys.ts
+++ code-server/lib/vscode/src/vs/workbench/common/contextkeys.ts
@@ -35,6 +35,8 @@ export const HasWebFileSystemAccess = ne
export const EmbedderIdentifierContext = new RawContextKey<string | undefined>('embedderIdentifier', undefined, localize('embedderIdentifier', 'The identifier of the embedder according to the product service, if one is defined'));
+export const IsEnabledFileDownloads = new RawContextKey<boolean>('isEnabledFileDownloads', true, true);
+
//#endregion

View File

@@ -21,15 +21,24 @@ 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
@@ -233,6 +233,9 @@ export async function setupServerService
@@ -11,7 +11,7 @@ import * as path from 'vs/base/common/pa
import { IURITransformer } from 'vs/base/common/uriIpc';
import { getMachineId, getSqmMachineId } from 'vs/base/node/id';
import { Promises } from 'vs/base/node/pfs';
-import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
+import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer, ProxyChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
import { ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
@@ -228,6 +228,9 @@ export async function setupServerService
const channel = new ExtensionManagementChannel(extensionManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority));
socketServer.registerChannel('extensions', channel);
+ const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService));
+ const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService), disposables);
+ socketServer.registerChannel('languagePacks', languagePackChannel);
+
const encryptionChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(IEncryptionMainService));
socketServer.registerChannel('encryption', encryptionChannel);
// clean up extensions folder
remoteExtensionsScanner.whenExtensionsReady().then(() => extensionManagementService.cleanUp());
Index: code-server/lib/vscode/src/vs/base/common/platform.ts
===================================================================
@@ -44,7 +53,7 @@ Index: code-server/lib/vscode/src/vs/base/common/platform.ts
export const LANGUAGE_DEFAULT = 'en';
let _isWindows = false;
@@ -90,17 +88,21 @@ if (typeof navigator === 'object' && !is
@@ -111,17 +109,21 @@ else if (typeof navigator === 'object' &
_isMobile = _userAgent?.indexOf('Mobi') >= 0;
_isWeb = true;
@@ -74,7 +83,7 @@ Index: code-server/lib/vscode/src/vs/base/common/platform.ts
+ }
}
// Native environment
// Unknown environment
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
@@ -89,10 +98,10 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
<!-- Workbench Icon/Manifest/CSS -->
<link rel="icon" href="{{BASE}}/_static/src/browser/media/favicon-dark-support.svg" />
<link rel="alternate icon" href="{{BASE}}/_static/src/browser/media/favicon.ico" type="image/x-icon" />
@@ -46,15 +49,26 @@
// Set up nls if the user is not using the default language (English)
const nlsConfig = {};
const locale = window.localStorage.getItem('vscode.nls.locale') || navigator.language;
@@ -48,15 +51,27 @@
// Normalize locale to lowercase because translationServiceUrl is case-sensitive.
// ref: https://github.com/microsoft/vscode/issues/187795
const locale = localStorage.getItem('vscode.nls.locale') || navigator.language.toLowerCase();
- if (!locale.startsWith('en')) {
- nlsConfig['vs/nls'] = {
- availableLanguages: {
@@ -101,7 +110,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
- translationServiceUrl: '{{WORKBENCH_NLS_BASE_URL}}'
- };
- }
-
+ try {
+ nlsConfig['vs/nls'] = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
+ if (nlsConfig['vs/nls']._resolvedLanguagePackCoreLocation) {
@@ -203,15 +212,15 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -26,6 +26,7 @@ import { URI } from 'vs/base/common/uri'
@@ -27,6 +27,7 @@ import { URI } from 'vs/base/common/uri'
import { streamToBuffer } from 'vs/base/common/buffer';
import { IProductConfiguration } from 'vs/base/common/product';
import { isString } from 'vs/base/common/types';
+import { getLocaleFromConfig, getNLSConfiguration } from 'vs/server/node/remoteLanguagePacks';
import { CharCode } from 'vs/base/common/charCode';
import { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';
@@ -337,6 +338,8 @@ export class WebClientServer {
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
@@ -345,6 +346,8 @@ export class WebClientServer {
callbackRoute: this._callbackRoute
};
@@ -220,30 +229,30 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
const nlsBaseUrl = this._productService.extensionsGallery?.nlsBaseUrl;
const values: { [key: string]: string } = {
WORKBENCH_WEB_CONFIGURATION: asJSON(workbenchWebConfiguration),
@@ -345,6 +348,7 @@ export class WebClientServer {
@@ -353,6 +356,7 @@ export class WebClientServer {
WORKBENCH_NLS_BASE_URL: vscodeBase + (nlsBaseUrl ? `${nlsBaseUrl}${!nlsBaseUrl.endsWith('/') ? '/' : ''}${this._productService.commit}/${this._productService.version}/` : ''),
BASE: base,
VS_BASE: vscodeBase,
+ NLS_CONFIGURATION: asJSON(nlsConfiguration),
};
let data;
if (useTestResolver) {
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
@@ -15,6 +15,7 @@ export const serverOptions: OptionDescri
'disable-update-check': { type: 'boolean' },
@@ -18,6 +18,7 @@ export const serverOptions: OptionDescri
'auth': { type: 'string' },
'disable-file-downloads': { type: 'boolean' },
'disable-file-uploads': { type: 'boolean' },
+ 'locale': { type: 'string' },
/* ----- server setup ----- */
@@ -96,6 +97,7 @@ export interface ServerParsedArgs {
'disable-update-check'?: boolean;
@@ -102,6 +103,7 @@ export interface ServerParsedArgs {
'auth'?: string
'disable-file-downloads'?: boolean;
'disable-file-uploads'?: boolean;
+ 'locale'?: string
/* ----- server setup ----- */
@@ -252,7 +261,7 @@ Index: code-server/lib/vscode/src/vs/workbench/workbench.web.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/workbench.web.main.ts
+++ code-server/lib/vscode/src/vs/workbench/workbench.web.main.ts
@@ -52,7 +52,7 @@ import 'vs/workbench/services/dialogs/br
@@ -50,7 +50,7 @@ import 'vs/workbench/services/dialogs/br
import 'vs/workbench/services/host/browser/browserHostService';
import 'vs/workbench/services/lifecycle/browser/lifecycleService';
import 'vs/workbench/services/clipboard/browser/clipboardService';
@@ -339,7 +348,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
@@ -335,9 +335,6 @@ export abstract class AbstractInstallAct
@@ -338,9 +338,6 @@ export class InstallAction extends Exten
if (this.extension.isBuiltin) {
return;
}
@@ -349,7 +358,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) {
this.enabled = this.options.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion;
this.updateLabel();
@@ -715,7 +712,7 @@ export abstract class InstallInOtherServ
@@ -608,7 +605,7 @@ export abstract class InstallInOtherServ
}
if (isLanguagePackExtension(this.extension.local.manifest)) {
@@ -358,7 +367,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
}
// Prefers to run on UI
@@ -1803,17 +1800,6 @@ export class SetLanguageAction extends E
@@ -1780,17 +1777,6 @@ export class SetLanguageAction extends E
update(): void {
this.enabled = false;
this.class = SetLanguageAction.DisabledClass;
@@ -376,7 +385,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
}
override async run(): Promise<any> {
@@ -1830,7 +1816,6 @@ export class ClearLanguageAction extends
@@ -1807,7 +1793,6 @@ export class ClearLanguageAction extends
private static readonly DisabledClass = `${ClearLanguageAction.EnabledClass} disabled`;
constructor(
@@ -384,7 +393,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
@ILocaleService private readonly localeService: ILocaleService,
) {
super(ClearLanguageAction.ID, ClearLanguageAction.TITLE.value, ClearLanguageAction.DisabledClass, false);
@@ -1840,17 +1825,6 @@ export class ClearLanguageAction extends
@@ -1817,17 +1802,6 @@ export class ClearLanguageAction extends
update(): void {
this.enabled = false;
this.class = ClearLanguageAction.DisabledClass;

View File

@@ -0,0 +1,358 @@
Add option to disable file downloads and uploads via cli
This patch adds support for a new CLI flag called `--disable-file-downloads`
which allows a user to remove the "Download..." option that shows up when you
right-click files in Code. It also disables the "Show Local" button on the dialog
for Save, Save-As and Save Workspace. The default value for this is `false`.
This patch also add support for a new CLI flag called `--disable-file-uploads`
which disables the drag to upload functionality and the "Upload..." option when you
right-click folders in Code. It also disables the "Show Local" button on the dialog
for opening a file. The default value for this is `false`.
This patch also adds trace log statements for when a file is read and written to disk.
To test disabling downloads, start code-server with `--disable-file-downloads`, open editor,
right-click on a file (not a folder) and you should **not** see the
"Download..." option. When saving a file or workspace, the "Show Local" button
should **not** appear on the dialog that comes on screen.
To test disabling uploads, start code-server with `--disable-file-uploads`, open editor,
right-click on a folder (not a file) and you should **not** see the
"Upload..." option. If you drag a file into the file navigator, the file should **not** upload
and appear in the file navigator. When opening a file, the "Show Local" button
should **not** appear on the dialog that comes on screen.
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
@@ -282,6 +282,16 @@ export interface IWorkbenchConstructionO
*/
readonly userDataPath?: string
+ /**
+ * Whether the "Download..." option is enabled for files.
+ */
+ readonly isEnabledFileDownloads?: boolean
+
+ /**
+ * Whether the "Upload..." button is enabled.
+ */
+ readonly isEnabledFileUploads?: boolean
+
//#endregion
//#region Profile options
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
@@ -34,6 +34,16 @@ export interface IBrowserWorkbenchEnviro
readonly options?: IWorkbenchConstructionOptions;
/**
+ * Enable downloading files via menu actions.
+ */
+ readonly isEnabledFileDownloads?: boolean;
+
+ /**
+ * Enable uploading files via menu actions.
+ */
+ readonly isEnabledFileUploads?: boolean;
+
+ /**
* Gets whether a resolver extension is expected for the environment.
*/
readonly expectsResolverExtension: boolean;
@@ -111,6 +121,20 @@ export class BrowserWorkbenchEnvironment
return this.options.userDataPath;
}
+ get isEnabledFileDownloads(): boolean {
+ if (typeof this.options.isEnabledFileDownloads === "undefined") {
+ throw new Error('isEnabledFileDownloads was not provided to the browser');
+ }
+ return this.options.isEnabledFileDownloads;
+ }
+
+ get isEnabledFileUploads(): boolean {
+ if (typeof this.options.isEnabledFileUploads === "undefined") {
+ throw new Error('isEnabledFileUploads was not provided to the browser');
+ }
+ return this.options.isEnabledFileUploads;
+ }
+
@memoize
get argvResource(): URI { return joinPath(this.userRoamingDataHome, 'argv.json'); }
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
@@ -16,6 +16,8 @@ export const serverOptions: OptionDescri
/* ----- code-server ----- */
'disable-update-check': { type: 'boolean' },
'auth': { type: 'string' },
+ 'disable-file-downloads': { type: 'boolean' },
+ 'disable-file-uploads': { type: 'boolean' },
/* ----- server setup ----- */
@@ -98,6 +100,8 @@ export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;
'auth'?: string
+ 'disable-file-downloads'?: boolean;
+ 'disable-file-uploads'?: boolean;
/* ----- server setup ----- */
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
@@ -332,6 +332,8 @@ export class WebClientServer {
remoteAuthority,
webviewEndpoint: vscodeBase + this._staticRoute + '/out/vs/workbench/contrib/webview/browser/pre',
userDataPath: this._environmentService.userDataPath,
+ isEnabledFileDownloads: !this._environmentService.args['disable-file-downloads'],
+ isEnabledFileUploads: !this._environmentService.args['disable-file-uploads'],
_wrapWebWorkerExtHostInIframe,
developmentOptions: { enableSmokeTestDriver: this._environmentService.args['enable-smoke-test-driver'] ? true : undefined, logLevel: this._logService.getLevel() },
settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined,
Index: code-server/lib/vscode/src/vs/workbench/browser/contextkeys.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/contextkeys.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/contextkeys.ts
@@ -7,12 +7,12 @@ import { Event } from 'vs/base/common/ev
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey, setConstant as setConstantContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext, IsMobileContext } from 'vs/platform/contextkey/common/contextkeys';
-import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, MainEditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsMainWindowFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, TitleBarVisibleContext, TitleBarStyleContext, MultipleEditorGroupsContext, IsAuxiliaryWindowFocusedContext, ActiveCompareEditorOriginalWriteableContext } from 'vs/workbench/common/contextkeys';
+import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, MainEditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsMainWindowFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, TitleBarVisibleContext, TitleBarStyleContext, MultipleEditorGroupsContext, IsAuxiliaryWindowFocusedContext, ActiveCompareEditorOriginalWriteableContext, IsEnabledFileDownloads, IsEnabledFileUploads } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType, onDidRegisterWindow, getActiveWindow } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
-import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
+import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { WorkbenchState, IWorkspaceContextService, isTemporaryWorkspace } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchLayoutService, Parts, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
@@ -87,7 +87,7 @@ export class WorkbenchContextKeysHandler
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IConfigurationService private readonly configurationService: IConfigurationService,
- @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
+ @IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,
@IProductService private readonly productService: IProductService,
@IEditorService private readonly editorService: IEditorService,
@IEditorResolverService private readonly editorResolverService: IEditorResolverService,
@@ -224,6 +224,10 @@ export class WorkbenchContextKeysHandler
this.auxiliaryBarVisibleContext = AuxiliaryBarVisibleContext.bindTo(this.contextKeyService);
this.auxiliaryBarVisibleContext.set(this.layoutService.isVisible(Parts.AUXILIARYBAR_PART));
+ // code-server
+ IsEnabledFileDownloads.bindTo(this.contextKeyService).set(this.environmentService.isEnabledFileDownloads ?? true)
+ IsEnabledFileUploads.bindTo(this.contextKeyService).set(this.environmentService.isEnabledFileUploads ?? true)
+
this.registerListeners();
}
Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts
@@ -20,7 +20,7 @@ import { CLOSE_SAVED_EDITORS_COMMAND_ID,
import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService';
import { Schemas } from 'vs/base/common/network';
-import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/contextkeys';
+import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext, IsEnabledFileDownloads, IsEnabledFileUploads } from 'vs/workbench/common/contextkeys';
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ThemeIcon } from 'vs/base/common/themables';
@@ -550,13 +550,16 @@ MenuRegistry.appendMenuItem(MenuId.Explo
id: DOWNLOAD_COMMAND_ID,
title: DOWNLOAD_LABEL
},
- when: ContextKeyExpr.or(
- // native: for any remote resource
- ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.notEqualsTo(Schemas.file)),
- // web: for any files
- ContextKeyExpr.and(IsWebContext, ExplorerFolderContext.toNegated(), ExplorerRootContext.toNegated()),
- // web: for any folders if file system API support is provided
- ContextKeyExpr.and(IsWebContext, HasWebFileSystemAccess)
+ when: ContextKeyExpr.and(
+ IsEnabledFileDownloads,
+ ContextKeyExpr.or(
+ // native: for any remote resource
+ ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.notEqualsTo(Schemas.file)),
+ // web: for any files
+ ContextKeyExpr.and(IsWebContext, ExplorerFolderContext.toNegated(), ExplorerRootContext.toNegated()),
+ // web: for any folders if file system API support is provided
+ ContextKeyExpr.and(IsWebContext, HasWebFileSystemAccess)
+ )
)
}));
@@ -568,6 +571,7 @@ MenuRegistry.appendMenuItem(MenuId.Explo
title: UPLOAD_LABEL,
},
when: ContextKeyExpr.and(
+ IsEnabledFileUploads,
// only in web
IsWebContext,
// only on folders
Index: code-server/lib/vscode/src/vs/workbench/common/contextkeys.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/common/contextkeys.ts
+++ code-server/lib/vscode/src/vs/workbench/common/contextkeys.ts
@@ -40,6 +40,9 @@ export const HasWebFileSystemAccess = ne
export const EmbedderIdentifierContext = new RawContextKey<string | undefined>('embedderIdentifier', undefined, localize('embedderIdentifier', 'The identifier of the embedder according to the product service, if one is defined'));
+export const IsEnabledFileDownloads = new RawContextKey<boolean>('isEnabledFileDownloads', true, true);
+export const IsEnabledFileUploads = new RawContextKey<boolean>('isEnabledFileUploads', true, true);
+
//#endregion
Index: code-server/lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts
+++ code-server/lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts
@@ -18,7 +18,7 @@ import { IModelService } from 'vs/editor
import { ILanguageService } from 'vs/editor/common/languages/language';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { Schemas } from 'vs/base/common/network';
-import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
+import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { equalsIgnoreCase, format, startsWithIgnoreCase } from 'vs/base/common/strings';
@@ -143,7 +143,7 @@ export class SimpleFileDialog implements
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@IModelService private readonly modelService: IModelService,
@ILanguageService private readonly languageService: ILanguageService,
- @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService,
+ @IBrowserWorkbenchEnvironmentService protected readonly environmentService: IBrowserWorkbenchEnvironmentService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@IPathService protected readonly pathService: IPathService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@@ -286,20 +286,22 @@ export class SimpleFileDialog implements
this.filePickBox.sortByLabel = false;
this.filePickBox.ignoreFocusOut = true;
this.filePickBox.ok = true;
- if ((this.scheme !== Schemas.file) && this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) {
- this.filePickBox.customButton = true;
- this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local');
- let action;
- if (isSave) {
- action = SaveLocalFileCommand;
- } else {
- action = this.allowFileSelection ? (this.allowFolderSelection ? OpenLocalFileFolderCommand : OpenLocalFileCommand) : OpenLocalFolderCommand;
- }
- const keybinding = this.keybindingService.lookupKeybinding(action.ID);
- if (keybinding) {
- const label = keybinding.getLabel();
- if (label) {
- this.filePickBox.customHover = format('{0} ({1})', action.LABEL, label);
+ if ((isSave && this.environmentService.isEnabledFileDownloads) || (!isSave && this.environmentService.isEnabledFileUploads)) {
+ if ((this.scheme !== Schemas.file) && this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) {
+ this.filePickBox.customButton = true;
+ this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local');
+ let action;
+ if (isSave) {
+ action = SaveLocalFileCommand;
+ } else {
+ action = this.allowFileSelection ? (this.allowFolderSelection ? OpenLocalFileFolderCommand : OpenLocalFileCommand) : OpenLocalFolderCommand;
+ }
+ const keybinding = this.keybindingService.lookupKeybinding(action.ID);
+ if (keybinding) {
+ const label = keybinding.getLabel();
+ if (label) {
+ this.filePickBox.customHover = format('{0} ({1})', action.LABEL, label);
+ }
}
}
}
Index: code-server/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts
===================================================================
--- 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
@@ -68,6 +68,7 @@ import { HoverPosition } from 'vs/base/b
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { mainWindow } from 'vs/base/browser/window';
import { IExplorerFileContribution, explorerFileContribRegistry } from 'vs/workbench/contrib/files/browser/explorerFileContrib';
+import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
@@ -1079,7 +1080,8 @@ export class FileDragAndDrop implements
@IConfigurationService private configurationService: IConfigurationService,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
- @IUriIdentityService private readonly uriIdentityService: IUriIdentityService
+ @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
+ @IBrowserWorkbenchEnvironmentService protected readonly environmentService: IBrowserWorkbenchEnvironmentService
) {
const updateDropEnablement = (e: IConfigurationChangeEvent | undefined) => {
if (!e || e.affectsConfiguration('explorer.enableDragAndDrop')) {
@@ -1284,15 +1286,17 @@ export class FileDragAndDrop implements
// External file DND (Import/Upload file)
if (data instanceof NativeDragAndDropData) {
- // Use local file import when supported
- if (!isWeb || (isTemporaryWorkspace(this.contextService.getWorkspace()) && WebFileSystemAccess.supported(mainWindow))) {
- const fileImport = this.instantiationService.createInstance(ExternalFileImport);
- await fileImport.import(resolvedTarget, originalEvent, mainWindow);
- }
- // Otherwise fallback to browser based file upload
- else {
- const browserUpload = this.instantiationService.createInstance(BrowserFileUpload);
- await browserUpload.upload(target, originalEvent);
+ if (this.environmentService.isEnabledFileUploads) {
+ // Use local file import when supported
+ if (!isWeb || (isTemporaryWorkspace(this.contextService.getWorkspace()) && WebFileSystemAccess.supported(mainWindow))) {
+ const fileImport = this.instantiationService.createInstance(ExternalFileImport);
+ await fileImport.import(resolvedTarget, originalEvent, mainWindow);
+ }
+ // Otherwise fallback to browser based file upload
+ else {
+ const browserUpload = this.instantiationService.createInstance(BrowserFileUpload);
+ await browserUpload.upload(target, originalEvent);
+ }
}
}
Index: code-server/lib/vscode/src/vs/platform/files/node/diskFileSystemProviderServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/files/node/diskFileSystemProviderServer.ts
+++ code-server/lib/vscode/src/vs/platform/files/node/diskFileSystemProviderServer.ts
@@ -92,6 +92,7 @@ export abstract class AbstractDiskFileSy
private async readFile(uriTransformer: IURITransformer, _resource: UriComponents, opts?: IFileAtomicReadOptions): Promise<VSBuffer> {
const resource = this.transformIncoming(uriTransformer, _resource, true);
+ this.logService.trace(`File action: readFile ${resource.path}`);
const buffer = await this.provider.readFile(resource, opts);
return VSBuffer.wrap(buffer);
@@ -110,6 +111,7 @@ export abstract class AbstractDiskFileSy
}
});
+ this.logService.trace(`File action: readFileStream ${resource.path}`);
const fileStream = this.provider.readFileStream(resource, opts, cts.token);
listenStream(fileStream, {
onData: chunk => emitter.fire(VSBuffer.wrap(chunk)),
@@ -130,7 +132,7 @@ export abstract class AbstractDiskFileSy
private writeFile(uriTransformer: IURITransformer, _resource: UriComponents, content: VSBuffer, opts: IFileWriteOptions): Promise<void> {
const resource = this.transformIncoming(uriTransformer, _resource);
-
+ this.logService.trace(`File action: writeFile ${resource.path}`);
return this.provider.writeFile(resource, content.buffer, opts);
}

View File

@@ -10,16 +10,25 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/bro
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts
@@ -60,7 +60,7 @@ import { GettingStartedIndexList } from
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { $, Dimension, addDisposableListener, append, clearNode, getWindow, reset } from 'vs/base/browser/dom';
+import { $, Dimension, addDisposableListener, append, clearNode, getWindow, reset, prepend } from 'vs/base/browser/dom';
import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { getTelemetryLevel } from 'vs/platform/telemetry/common/telemetryUtils';
import { Button } from 'vs/base/browser/ui/button/button';
@@ -58,7 +58,7 @@ import { IRecentFolder, IRecentWorkspace
import { OpenRecentAction } from 'vs/workbench/browser/actions/windowActions';
import { OpenFileFolderAction, OpenFolderAction, OpenFolderViaWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
-import { WorkbenchStateContext } from 'vs/workbench/common/contextkeys';
+import { IsEnabledCoderGettingStarted, WorkbenchStateContext } from 'vs/workbench/common/contextkeys';
import { OpenFolderViaWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions';
import { OpenRecentAction } from 'vs/workbench/browser/actions/windowActions';
import { Toggle } from 'vs/base/browser/ui/toggle/toggle';
@@ -817,6 +817,72 @@ export class GettingStartedPage extends
import { IEditorOpenContext, IEditorSerializer } from 'vs/workbench/common/editor';
import { IWebviewElement, IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { IFeaturedExtensionsService } from 'vs/workbench/contrib/welcomeGettingStarted/browser/featuredExtensionService';
@@ -793,6 +793,72 @@ export class GettingStartedPage extends
$('p.subtitle.description', {}, localize({ key: 'gettingStarted.editingEvolved', comment: ['Shown as subtitle on the Welcome page.'] }, "Editing evolved"))
);
@@ -92,62 +101,16 @@ 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', {},);
@@ -835,13 +901,23 @@ export class GettingStartedPage extends
const layoutLists = () => {
if (gettingStartedList.itemCount) {
this.container.classList.remove('noWalkthroughs');
- reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
- reset(rightColumn, featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
+ if (this.contextService.contextMatchesRules(IsEnabledCoderGettingStarted)) {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement(), featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
+ reset(rightColumn, gettingStartedCoder);
+ } else {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
+ reset(rightColumn, featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
+ }
@@ -842,6 +908,9 @@ export class GettingStartedPage extends
recentList.setLimit(5);
reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
}
else {
this.container.classList.add('noWalkthroughs');
- reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
- reset(rightColumn, featuredExtensionList.getDomElement());
+ if (this.contextService.contextMatchesRules(IsEnabledCoderGettingStarted)) {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement(), featuredExtensionList.getDomElement());
+ reset(rightColumn, gettingStartedCoder);
+ } else {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
+ reset(rightColumn, featuredExtensionList.getDomElement());
+ }
}
setTimeout(() => this.categoriesPageScrollbar?.scanDomNode(), 50);
};
@@ -849,13 +925,23 @@ export class GettingStartedPage extends
const layoutFeaturedExtension = () => {
if (featuredExtensionList.itemCount) {
this.container.classList.remove('noExtensions');
- reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
- reset(rightColumn, featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
+ if (this.contextService.contextMatchesRules(IsEnabledCoderGettingStarted)) {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement(), featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
+ reset(rightColumn, gettingStartedCoder);
+ } else {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
+ reset(rightColumn, featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
+ }
}
else {
this.container.classList.add('noExtensions');
- reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
- reset(rightColumn, gettingStartedList.getDomElement());
+ if (this.contextService.contextMatchesRules(IsEnabledCoderGettingStarted)) {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement(), gettingStartedList.getDomElement());
+ reset(rightColumn, gettingStartedCoder);
+ } else {
+ reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
+ reset(rightColumn, gettingStartedList.getDomElement());
+ }
}
setTimeout(() => this.categoriesPageScrollbar?.scanDomNode(), 50);
+ if (this.contextService.contextMatchesRules(IsEnabledCoderGettingStarted)) {
+ prepend(rightColumn, gettingStartedCoder)
+ }
};
featuredExtensionList.onDidChange(layoutFeaturedExtension);
Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css
@@ -160,21 +123,21 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/welcomeGettingStarted/bro
+ margin-bottom: 0.2em;
+}
+
+.monaco-workbench .part.editor>.content .gettingStartedContainer .coder-coder {
+.monaco-workbench .part.editor > .content .gettingStartedContainer .coder-coder {
+ font-size: 1em;
+ margin-top: 0.2em;
+}
+
.monaco-workbench.hc-black .part.editor>.content .gettingStartedContainer .subtitle,
.monaco-workbench.hc-light .part.editor>.content .gettingStartedContainer .subtitle {
.monaco-workbench.hc-black .part.editor > .content .gettingStartedContainer .subtitle,
.monaco-workbench.hc-light .part.editor > .content .gettingStartedContainer .subtitle {
font-weight: 200;
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
@@ -265,6 +265,11 @@ export interface IWorkbenchConstructionO
@@ -292,6 +292,11 @@ export interface IWorkbenchConstructionO
*/
readonly isEnabledFileDownloads?: boolean
readonly isEnabledFileUploads?: boolean
+ /**
+ * Whether to use Coder's custom Getting Started text.
@@ -188,20 +151,20 @@ Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/envi
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
@@ -37,6 +37,11 @@ export interface IBrowserWorkbenchEnviro
* Enable downloading files via menu actions.
*/
readonly isEnabledFileDownloads?: boolean;
+
+ /**
@@ -44,6 +44,11 @@ export interface IBrowserWorkbenchEnviro
readonly isEnabledFileUploads?: boolean;
/**
+ * Enable Coder's custom getting started text.
+ */
+ readonly isEnabledCoderGettingStarted?: boolean;
}
export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvironmentService {
@@ -113,6 +118,13 @@ export class BrowserWorkbenchEnvironment
return this.options.isEnabledFileDownloads;
+
+ /**
* Gets whether a resolver extension is expected for the environment.
*/
readonly expectsResolverExtension: boolean;
@@ -135,6 +140,13 @@ export class BrowserWorkbenchEnvironment
return this.options.isEnabledFileUploads;
}
+ get isEnabledCoderGettingStarted(): boolean {
@@ -218,17 +181,17 @@ 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
@@ -16,6 +16,7 @@ export const serverOptions: OptionDescri
'auth': { type: 'string' },
@@ -19,6 +19,7 @@ export const serverOptions: OptionDescri
'disable-file-downloads': { type: 'boolean' },
'disable-file-uploads': { type: 'boolean' },
'locale': { type: 'string' },
+ 'disable-getting-started-override': { type: 'boolean' },
/* ----- server setup ----- */
@@ -98,6 +99,7 @@ export interface ServerParsedArgs {
'auth'?: string
@@ -104,6 +105,7 @@ export interface ServerParsedArgs {
'disable-file-downloads'?: boolean;
'disable-file-uploads'?: boolean;
'locale'?: string
+ 'disable-getting-started-override'?: boolean,
@@ -238,10 +201,10 @@ 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
@@ -328,6 +328,7 @@ export class WebClientServer {
webviewEndpoint: vscodeBase + this._staticRoute + '/out/vs/workbench/contrib/webview/browser/pre',
@@ -336,6 +336,7 @@ export class WebClientServer {
userDataPath: this._environmentService.userDataPath,
isEnabledFileDownloads: !this._environmentService.args['disable-file-downloads'],
isEnabledFileUploads: !this._environmentService.args['disable-file-uploads'],
+ isEnabledCoderGettingStarted: !this._environmentService.args['disable-getting-started-override'],
_wrapWebWorkerExtHostInIframe,
developmentOptions: { enableSmokeTestDriver: this._environmentService.args['enable-smoke-test-driver'] ? true : undefined, logLevel: this._logService.getLevel() },
@@ -254,15 +217,15 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/contextkeys.ts
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey, setConstant as setConstantContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext, IsMobileContext } from 'vs/platform/contextkey/common/contextkeys';
-import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, IsEnabledFileDownloads } from 'vs/workbench/common/contextkeys';
+import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, IsEnabledFileDownloads, IsEnabledCoderGettingStarted } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
-import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, MainEditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsMainWindowFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, TitleBarVisibleContext, TitleBarStyleContext, MultipleEditorGroupsContext, IsAuxiliaryWindowFocusedContext, ActiveCompareEditorOriginalWriteableContext, IsEnabledFileDownloads, IsEnabledFileUploads } from 'vs/workbench/common/contextkeys';
+import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, MainEditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsMainWindowFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, TitleBarVisibleContext, TitleBarStyleContext, MultipleEditorGroupsContext, IsAuxiliaryWindowFocusedContext, ActiveCompareEditorOriginalWriteableContext, IsEnabledFileDownloads, IsEnabledFileUploads, IsEnabledCoderGettingStarted, } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType, onDidRegisterWindow, getActiveWindow } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
@@ -207,6 +207,7 @@ export class WorkbenchContextKeysHandler
@@ -227,6 +227,7 @@ export class WorkbenchContextKeysHandler
// code-server
IsEnabledFileDownloads.bindTo(this.contextKeyService).set(this.environmentService.isEnabledFileDownloads ?? true)
IsEnabledFileUploads.bindTo(this.contextKeyService).set(this.environmentService.isEnabledFileUploads ?? true)
+ IsEnabledCoderGettingStarted.bindTo(this.contextKeyService).set(this.environmentService.isEnabledCoderGettingStarted ?? true)
this.registerListeners();
@@ -271,10 +234,10 @@ Index: code-server/lib/vscode/src/vs/workbench/common/contextkeys.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/common/contextkeys.ts
+++ code-server/lib/vscode/src/vs/workbench/common/contextkeys.ts
@@ -36,6 +36,7 @@ export const HasWebFileSystemAccess = ne
export const EmbedderIdentifierContext = new RawContextKey<string | undefined>('embedderIdentifier', undefined, localize('embedderIdentifier', 'The identifier of the embedder according to the product service, if one is defined'));
@@ -42,6 +42,7 @@ export const EmbedderIdentifierContext =
export const IsEnabledFileDownloads = new RawContextKey<boolean>('isEnabledFileDownloads', true, true);
export const IsEnabledFileUploads = new RawContextKey<boolean>('isEnabledFileUploads', true, true);
+export const IsEnabledCoderGettingStarted = new RawContextKey<boolean>('isEnabledCoderGettingStarted', true, true);
//#endregion

View File

@@ -1,106 +0,0 @@
Add the ability to provide a GitHub token
To test install the GitHub PR extension and start code-server with GITHUB_TOKEN
or set github-auth in the config file. The extension should be authenticated.
Index: code-server/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts
+++ code-server/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts
@@ -5,9 +5,18 @@
import { InMemoryCredentialsProvider } from 'vs/platform/credentials/common/credentials';
import { ILogService } from 'vs/platform/log/common/log';
-import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
+import { IServerEnvironmentService } from 'vs/server/node/serverEnvironmentService';
import { IProductService } from 'vs/platform/product/common/productService';
import { BaseCredentialsMainService, KeytarModule } from 'vs/platform/credentials/common/credentialsMainService';
+import { generateUuid } from 'vs/base/common/uuid';
+import { equals as arrayEquals } from 'vs/base/common/arrays';
+
+interface IToken {
+ accessToken: string
+ account?: { label: string }
+ id: string
+ scopes: string[]
+}
export class CredentialsWebMainService extends BaseCredentialsMainService {
// Since we fallback to the in-memory credentials provider, we do not need to surface any Keytar load errors
@@ -16,10 +25,15 @@ export class CredentialsWebMainService e
constructor(
@ILogService logService: ILogService,
- @INativeEnvironmentService private readonly environmentMainService: INativeEnvironmentService,
+ @IServerEnvironmentService private readonly environmentMainService: IServerEnvironmentService,
@IProductService private readonly productService: IProductService,
) {
super(logService);
+ if (this.environmentMainService.args["github-auth"]) {
+ this.storeGitHubToken(this.environmentMainService.args["github-auth"]).catch((error) => {
+ this.logService.error('Failed to store provided GitHub token', error)
+ })
+ }
}
// If the credentials service is running on the server, we add a suffix -server to differentiate from the location that the
@@ -48,4 +62,59 @@ export class CredentialsWebMainService e
}
return this._keytarCache;
}
+
+ private async storeGitHubToken(githubToken: string): Promise<void> {
+ const extensionId = 'vscode.github-authentication';
+ const service = `${await this.getSecretStoragePrefix()}${extensionId}`;
+ const account = 'github.auth';
+ const scopes = [['read:user', 'user:email', 'repo']]
+
+ // Oddly the scopes need to match exactly so we cannot just have one token
+ // with all the scopes, instead we have to duplicate the token for each
+ // expected set of scopes.
+ const tokens: IToken[] = scopes.map((scopes) => ({
+ id: generateUuid(),
+ scopes: scopes.sort(), // Sort for comparing later.
+ accessToken: githubToken,
+ }));
+
+ const raw = await this.getPassword(service, account)
+
+ let existing: {
+ content: IToken[]
+ } | undefined;
+
+ if (raw) {
+ try {
+ const json = JSON.parse(raw);
+ json.content = JSON.parse(json.content);
+ existing = json;
+ } catch (error) {
+ this.logService.error('Failed to parse existing GitHub credentials', error)
+ }
+ }
+
+ // Keep tokens for account and scope combinations we do not have in case
+ // there is an extension that uses scopes we have not accounted for (in
+ // these cases the user will need to manually authenticate the extension
+ // through the UI) or the user has tokens for other accounts.
+ if (existing?.content) {
+ existing.content = existing.content.filter((existingToken) => {
+ const scopes = existingToken.scopes.sort();
+ return !(tokens.find((token) => {
+ return arrayEquals(scopes, token.scopes)
+ && token.account?.label === existingToken.account?.label;
+ }))
+ })
+ }
+
+ return this.setPassword(service, account, JSON.stringify({
+ extensionId,
+ ...(existing || {}),
+ content: JSON.stringify([
+ ...tokens,
+ ...(existing?.content || []),
+ ])
+ }));
+ }
}

View File

@@ -176,15 +176,15 @@ 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
@@ -69,6 +69,7 @@ import { IndexedDB } from 'vs/base/brows
import { BrowserCredentialsService } from 'vs/workbench/services/credentials/browser/credentialsService';
import { IWorkspace } from 'vs/workbench/services/host/browser/browserHostService';
@@ -64,6 +64,7 @@ import { IOpenerService } from 'vs/platf
import { mixin, safeStringify } from 'vs/base/common/objects';
import { IndexedDB } from 'vs/base/browser/indexedDB';
import { WebFileSystemAccess } from 'vs/platform/files/browser/webFileSystemAccess';
+import { CodeServerClient } from 'vs/workbench/browser/client';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { DelayedLogChannel } from 'vs/workbench/services/output/common/delayedLogChannel';
@@ -123,6 +124,9 @@ export class BrowserMain extends Disposa
@@ -130,6 +131,9 @@ export class BrowserMain extends Disposa
// Startup
const instantiationService = workbench.startup();
@@ -264,7 +264,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -299,6 +299,7 @@ export class WebClientServer {
@@ -306,6 +306,7 @@ export class WebClientServer {
} : undefined;
const productConfiguration = <Partial<IProductConfiguration>>{

View File

@@ -1,26 +1,24 @@
Make storage local to the remote server
This solves two problems:
1. Extensions running in the browser (like Vim) might use these paths
directly instead of using the file service and most likely can't write
to `/User` on disk.
2. Settings will be stored in the file system instead of in browser
storage. Using browser storage makes sharing or seeding settings
between browsers difficult. We may want to revisit this once/if we get
settings sync.
This makes user settings will be stored in the file system instead of in browser
storage. Using browser storage makes sharing or seeding settings between
browsers difficult and remote settings is not a sufficient replacement because
some settings are only allowed to be set on the user level.
Unfortunately this does not affect state which uses a separate method with
IndexedDB and does not appear nearly as easy to redirect to disk.
To test install the Vim extension and make sure something that uses file storage
works (history recall for example) and change settings from the UI and on disk
while making sure they appear on the other side.
To test change settings from the UI and on disk while making sure they appear on
the other side.
This patch also resolves a bug where a global value for workspace initialization
is used in a non async-safe way.
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
@@ -320,6 +320,7 @@ export class WebClientServer {
@@ -327,6 +327,7 @@ export class WebClientServer {
const workbenchWebConfiguration = {
remoteAuthority,
webviewEndpoint: vscodeBase + this._staticRoute + '/out/vs/workbench/contrib/webview/browser/pre',
@@ -32,7 +30,7 @@ Index: code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.api.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
@@ -255,6 +255,11 @@ export interface IWorkbenchConstructionO
@@ -277,6 +277,11 @@ export interface IWorkbenchConstructionO
*/
readonly configurationDefaults?: Record<string, any>;
@@ -48,7 +46,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/envi
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
@@ -92,7 +92,14 @@ export class BrowserWorkbenchEnvironment
@@ -102,7 +102,14 @@ export class BrowserWorkbenchEnvironment
get logFile(): URI { return joinPath(this.windowLogsPath, 'window.log'); }
@memoize
@@ -64,3 +62,33 @@ Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/envi
@memoize
get argvResource(): URI { return joinPath(this.userRoamingDataHome, 'argv.json'); }
Index: code-server/lib/vscode/src/vs/workbench/services/configuration/browser/configurationService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/configuration/browser/configurationService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/configuration/browser/configurationService.ts
@@ -145,8 +145,10 @@ export class WorkspaceService extends Di
this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, fileService, uriIdentityService, logService));
this._register(this.workspaceConfiguration.onDidUpdateConfiguration(fromCache => {
this.onWorkspaceConfigurationChanged(fromCache).then(() => {
- this.workspace.initialized = this.workspaceConfiguration.initialized;
- this.checkAndMarkWorkspaceComplete(fromCache);
+ if (this.workspace) { // The workspace may not have been created yet.
+ this.workspace.initialized = this.workspaceConfiguration.initialized;
+ this.checkAndMarkWorkspaceComplete(fromCache);
+ }
});
}));
@@ -552,6 +554,12 @@ export class WorkspaceService extends Di
previousFolders = this.workspace.folders;
this.workspace.update(workspace);
} else {
+ // It is possible for the configuration to become initialized in between
+ // when the workspace was created and this function was called, so check
+ // the configuration again now.
+ if (!workspace.initialized && this.workspaceConfiguration.initialized) {
+ workspace.initialized = true;
+ }
this.workspace = workspace;
}

View File

@@ -20,7 +20,7 @@ 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
@@ -13,6 +13,7 @@ import { IEnvironmentService, INativeEnv
@@ -15,6 +15,7 @@ import { URI } from 'vs/base/common/uri'
export const serverOptions: OptionDescriptions<Required<ServerParsedArgs>> = {
/* ----- code-server ----- */
'disable-update-check': { type: 'boolean' },
@@ -28,7 +28,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -92,6 +93,7 @@ export const serverOptions: OptionDescri
@@ -96,6 +97,7 @@ export const serverOptions: OptionDescri
export interface ServerParsedArgs {
/* ----- code-server ----- */
'disable-update-check'?: boolean;
@@ -40,7 +40,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -304,6 +304,7 @@ export class WebClientServer {
@@ -311,6 +311,7 @@ export class WebClientServer {
codeServerVersion: this._productService.codeServerVersion,
rootEndpoint: base,
updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,

View File

@@ -12,7 +12,7 @@ in-between and has web extensions install directly from the marketplace.
This can be tested by setting EXTENSIONS_GALLERY set to:
'{"serviceUrl": "https://extensions.coder.com/api"}'
'{"serviceUrl": "https://my-extensions/api"}'
Index: code-server/lib/vscode/src/vs/platform/product/common/product.ts
@@ -40,7 +40,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -111,7 +111,7 @@ export class WebClientServer {
@@ -113,7 +113,7 @@ export class WebClientServer {
const serverRootPath = getRemoteServerRootPath(_productService);
this._staticRoute = `${serverRootPath}/static`;
this._callbackRoute = `${serverRootPath}/callback`;
@@ -49,7 +49,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
}
/**
@@ -304,14 +304,7 @@ export class WebClientServer {
@@ -311,14 +311,7 @@ export class WebClientServer {
codeServerVersion: this._productService.codeServerVersion,
rootEndpoint: base,
embedderIdentifier: 'server-distro',
@@ -74,10 +74,10 @@ Index: code-server/lib/vscode/src/vs/platform/extensionResourceLoader/common/ext
import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';
import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
-import { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';
import { TargetPlatform } from 'vs/platform/extensions/common/extensions';
const WEB_EXTENSION_RESOURCE_END_POINT = 'web-extension-resource';
@@ -60,7 +59,7 @@ export abstract class AbstractExtensionR
@@ -77,7 +76,7 @@ export abstract class AbstractExtensionR
private readonly _environmentService: IEnvironmentService,
private readonly _configurationService: IConfigurationService,
) {

View File

@@ -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
@@ -260,10 +260,7 @@ function extensionDescriptionArrayToMap(
@@ -312,10 +312,7 @@ function extensionDescriptionArrayToMap(
}
export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {

View File

@@ -42,17 +42,8 @@ Index: code-server/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityReso
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
+++ code-server/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
@@ -11,7 +11,7 @@ import { StopWatch } from 'vs/base/commo
import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
-import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolvedOptions, ResolverResult, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { getRemoteServerRootPath, parseAuthorityWithOptionalPort } from 'vs/platform/remote/common/remoteHosts';
export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {
@@ -29,7 +29,7 @@ export class RemoteAuthorityResolverServ
constructor(
@@ -34,7 +34,7 @@ export class RemoteAuthorityResolverServ
isWorkbenchOptionsBasedResolution: boolean,
connectionToken: Promise<string> | string | undefined,
resourceUriProvider: ((uri: URI) => URI) | undefined,
- @IProductService productService: IProductService,
@@ -60,27 +51,27 @@ Index: code-server/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityReso
@ILogService private readonly _logService: ILogService,
) {
super();
@@ -75,9 +75,14 @@ export class RemoteAuthorityResolverServ
@@ -85,9 +85,14 @@ export class RemoteAuthorityResolverServ
const connectionToken = await Promise.resolve(this._connectionTokens.get(authority) || this._connectionToken);
performance.mark(`code/didResolveConnectionToken/${authorityPrefix}`);
this._logService.info(`Resolved connection token (${authorityPrefix}) after ${sw.elapsed()} ms`);
+ let options: ResolvedOptions | undefined;
+ if (this.productService.proxyEndpointTemplate) {
+ const proxyUrl = new URL(this.productService.proxyEndpointTemplate, window.location.href);
+ const proxyUrl = new URL(this.productService.proxyEndpointTemplate, mainWindow.location.href);
+ options = { extensionHostEnv: { VSCODE_PROXY_URI: decodeURIComponent(proxyUrl.toString()) }}
+ }
const defaultPort = (/^https:/.test(window.location.href) ? 443 : 80);
const defaultPort = (/^https:/.test(mainWindow.location.href) ? 443 : 80);
const { host, port } = parseAuthorityWithOptionalPort(authority, defaultPort);
- const result: ResolverResult = { authority: { authority, host: host, port: port, connectionToken } };
+ const result: ResolverResult = { authority: { authority, host: host, port: port, connectionToken }, options };
RemoteAuthorities.set(authority, result.authority.host, result.authority.port);
- const result: ResolverResult = { authority: { authority, connectTo: new WebSocketRemoteConnection(host, port), connectionToken } };
+ const result: ResolverResult = { authority: { authority, connectTo: new WebSocketRemoteConnection(host, port), connectionToken }, options };
RemoteAuthorities.set(authority, host, port);
this._cache.set(authority, result);
this._onDidChangeConnectionData.fire();
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
@@ -305,6 +305,7 @@ export class WebClientServer {
@@ -312,6 +312,7 @@ export class WebClientServer {
rootEndpoint: base,
updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,
logoutEndpoint: this._environmentService.args['auth'] && this._environmentService.args['auth'] !== "none" ? base + '/logout' : undefined,
@@ -92,7 +83,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalE
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts
@@ -383,7 +383,7 @@ export async function createTerminalEnvi
@@ -291,7 +291,7 @@ export async function createTerminalEnvi
// Sanitize the environment, removing any undesirable VS Code and Electron environment
// variables
@@ -105,33 +96,32 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -21,6 +21,7 @@ import type { ICredentialsProvider } fro
import type { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService';
import type { IWorkbenchConstructionOptions } from 'vs/workbench/browser/web.api';
import type { IWorkspace, IWorkspaceProvider } from 'vs/workbench/services/host/browser/browserHostService';
@@ -19,6 +19,7 @@ import { ISecretStorageProvider } from '
import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/window/common/window';
import type { IWorkbenchConstructionOptions, IWorkspace, IWorkspaceProvider } from 'vs/workbench/browser/web.api';
import { AuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService';
+import { extractLocalHostUriMetaDataForPortMapping, TunnelOptions, TunnelCreationOptions } from 'vs/platform/tunnel/common/tunnel';
import type { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService';
import { create } from 'vs/workbench/workbench.web.main';
interface ICredential {
service: string;
@@ -511,6 +512,38 @@ function doCreateUri(path: string, query
} : undefined,
@@ -571,6 +572,39 @@ class WorkspaceProvider implements IWork
settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined,
workspaceProvider: WorkspaceProvider.create(config),
urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute),
- credentialsProvider: config.remoteAuthority ? undefined : new LocalStorageCredentialsProvider() // with a remote, we don't use a local credentials provider
+ credentialsProvider: config.remoteAuthority ? undefined : new LocalStorageCredentialsProvider(), // with a remote, we don't use a local credentials provider
+ resolveExternalUri: (uri: URI): Promise<URI> => {
+ let resolvedUri = uri
+ const localhostMatch = extractLocalHostUriMetaDataForPortMapping(resolvedUri)
+
+ if (localhostMatch && resolvedUri.authority !== location.host) {
+ if (config.productConfiguration && config.productConfiguration.proxyEndpointTemplate) {
+ resolvedUri = URI.parse(new URL(config.productConfiguration.proxyEndpointTemplate.replace('{{port}}', localhostMatch.port.toString()), window.location.href).toString())
+ const renderedTemplate = config.productConfiguration.proxyEndpointTemplate
+ .replace('{{port}}', localhostMatch.port.toString())
+ .replace('{{host}}', window.location.host)
+ resolvedUri = URI.parse(new URL(renderedTemplate, window.location.href).toString())
+ } else {
+ throw new Error(`Failed to resolve external URI: ${uri.toString()}. Could not determine base url because productConfiguration missing.`)
+ }
+ }
+
+ // If not localhost, return unmodified
+ // If not localhost, return unmodified.
+ return Promise.resolve(resolvedUri)
+ },
+ tunnelProvider: {
@@ -150,19 +140,20 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+ }
+ })
+ }
+ }
});
})();
+ },
secretStorageProvider: config.remoteAuthority && !secretStorageKeyPath
? undefined /* with a remote without embedder-preferred storage, store on the remote */
: new LocalStorageSecretStorageProvider(secretStorageCrypto),
Index: code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
@@ -73,7 +73,7 @@ export class ForwardedPortsView extends
@@ -80,7 +80,7 @@ export class ForwardedPortsView extends
this.contextKeyListener = undefined;
}
- const viewEnabled: boolean = !!forwardedPortsViewEnabled.getValue(this.contextKeyService);
+ const viewEnabled: boolean = true;
if (this.environmentService.remoteAuthority && viewEnabled) {
if (viewEnabled) {
const viewContainer = await this.getViewContainer();

68
patches/safari.diff Normal file
View File

@@ -0,0 +1,68 @@
Revert back to es2020
es2022 outputs static blocks when using static properties that are not
compatible with Safari, or at least not older versions of Safari.
Index: code-server/lib/vscode/src/tsconfig.base.json
===================================================================
--- code-server.orig/lib/vscode/src/tsconfig.base.json
+++ code-server/lib/vscode/src/tsconfig.base.json
@@ -17,9 +17,30 @@
"./vs/*"
]
},
- "target": "es2022",
- "useDefineForClassFields": false,
+ "target": "es2020",
"lib": [
+ "ES2016",
+ "ES2017.Object",
+ "ES2017.String",
+ "ES2017.Intl",
+ "ES2017.TypedArrays",
+ "ES2018.AsyncIterable",
+ "ES2018.AsyncGenerator",
+ "ES2018.Promise",
+ "ES2018.Regexp",
+ "ES2018.Intl",
+ "ES2019.Array",
+ "ES2019.Object",
+ "ES2019.String",
+ "ES2019.Symbol",
+ "ES2020.BigInt",
+ "ES2020.Promise",
+ "ES2020.String",
+ "ES2020.Symbol.WellKnown",
+ "ES2020.Intl",
+ "ES2021.Promise",
+ "ES2021.String",
+ "ES2021.WeakRef",
"ES2022",
"DOM",
"DOM.Iterable",
Index: code-server/lib/vscode/build/lib/tsb/transpiler.js
===================================================================
--- code-server.orig/lib/vscode/build/lib/tsb/transpiler.js
+++ code-server/lib/vscode/build/lib/tsb/transpiler.js
@@ -293,7 +293,7 @@ class SwcTranspiler {
tsx: false,
decorators: true
},
- target: 'es2022',
+ target: 'es2020',
loose: false,
minify: {
compress: false,
Index: code-server/lib/vscode/build/lib/tsb/transpiler.ts
===================================================================
--- code-server.orig/lib/vscode/build/lib/tsb/transpiler.ts
+++ code-server/lib/vscode/build/lib/tsb/transpiler.ts
@@ -376,7 +376,7 @@ export class SwcTranspiler implements IT
tsx: false,
decorators: true
},
- target: 'es2022',
+ target: 'es2020',
loose: false,
minify: {
compress: false,

View File

@@ -9,13 +9,13 @@ update-check.diff
logout.diff
store-socket.diff
proxy-uri.diff
github-auth.diff
unique-db.diff
local-storage.diff
service-worker.diff
sourcemaps.diff
disable-downloads.diff
external-file-actions.diff
telemetry.diff
display-language.diff
cli-window-open.diff
getting-started.diff
safari.diff

View File

@@ -54,7 +54,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -306,6 +306,10 @@ export class WebClientServer {
@@ -313,6 +313,10 @@ export class WebClientServer {
updateEndpoint: !this._environmentService.args['disable-update-check'] ? base + '/update/check' : undefined,
logoutEndpoint: this._environmentService.args['auth'] && this._environmentService.args['auth'] !== "none" ? base + '/logout' : undefined,
proxyEndpointTemplate: process.env.VSCODE_PROXY_URI ?? base + '/proxy/{{port}}/',

View File

@@ -10,7 +10,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.js
===================================================================
--- code-server.orig/lib/vscode/build/gulpfile.reh.js
+++ code-server/lib/vscode/build/gulpfile.reh.js
@@ -197,8 +197,7 @@ function packageTask(type, platform, arc
@@ -236,8 +236,7 @@ function packageTask(type, platform, arc
const src = gulp.src(sourceFolderName + '/**', { base: '.' })
.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); }))
@@ -20,7 +20,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.js
const workspaceExtensionPoints = ['debuggers', 'jsonValidation'];
const isUIExtension = (manifest) => {
@@ -237,9 +236,9 @@ function packageTask(type, platform, arc
@@ -276,9 +275,9 @@ function packageTask(type, platform, arc
.map(name => `.build/extensions/${name}/**`);
const extensions = gulp.src(extensionPaths, { base: '.build', dot: true });
@@ -32,7 +32,7 @@ Index: code-server/lib/vscode/build/gulpfile.reh.js
let version = packageJson.version;
const quality = product.quality;
@@ -394,7 +393,7 @@ function tweakProductForServerWeb(produc
@@ -433,7 +432,7 @@ function tweakProductForServerWeb(produc
const minifyTask = task.define(`minify-vscode-${type}`, task.series(
optimizeTask,
util.rimraf(`out-vscode-${type}-min`),

View File

@@ -1,4 +1,4 @@
Store a static reference to the IPC socket
Store the IPC socket with workspace metadata.
This lets us use it to open files inside code-server from outside of
code-server.
@@ -9,29 +9,121 @@ To test this:
It should open in your existing code-server instance.
When the extension host is terminated, the socket is unregistered.
Index: code-server/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts
+++ code-server/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts
@@ -2,7 +2,9 @@
@@ -2,7 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-
+import { promises as fs } from 'fs';
+import * as os from 'os'
+import * as path from 'vs/base/common/path';
+import * as _http from 'http';
import * as performance from 'vs/base/common/performance';
import { createApiFactoryAndRegisterActors } from 'vs/workbench/api/common/extHost.api.impl';
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
@@ -72,6 +74,10 @@ export class ExtHostExtensionService ext
if (this._initData.remote.isRemote && this._initData.remote.authority) {
const cliServer = this._instaService.createInstance(CLIServer);
process.env['VSCODE_IPC_HOOK_CLI'] = cliServer.ipcHandlePath;
+
+ fs.writeFile(path.join(os.tmpdir(), 'vscode-ipc'), cliServer.ipcHandlePath).catch((error) => {
+ this._logService.error(error);
+ });
}
@@ -17,6 +17,7 @@ import { ExtensionRuntime } from 'vs/wor
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
import { realpathSync } from 'vs/base/node/extpath';
import { ExtHostConsoleForwarder } from 'vs/workbench/api/node/extHostConsoleForwarder';
+import { IExtHostWorkspace } from '../common/extHostWorkspace';
import { ExtHostDiskFileSystemProvider } from 'vs/workbench/api/node/extHostDiskFileSystemProvider';
// Module loading tricks
class NodeModuleRequireInterceptor extends RequireInterceptor {
@@ -83,6 +84,52 @@ export class ExtHostExtensionService ext
await interceptor.install();
performance.mark('code/extHost/didInitAPI');
+ (async () => {
+ const socketPath = process.env['VSCODE_IPC_HOOK_CLI'];
+ const codeServerSocketPath = process.env['CODE_SERVER_SESSION_SOCKET']
+ if (!socketPath || !codeServerSocketPath) {
+ return;
+ }
+ const workspace = this._instaService.invokeFunction((accessor) => {
+ const workspaceService = accessor.get(IExtHostWorkspace);
+ return workspaceService.workspace;
+ });
+ const entry = {
+ workspace,
+ socketPath
+ };
+ const message = JSON.stringify({entry});
+ await new Promise<void>((resolve, reject) => {
+ const opts: _http.RequestOptions = {
+ path: '/add-session',
+ socketPath: codeServerSocketPath,
+ method: 'POST',
+ headers: {
+ 'content-type': 'application/json',
+ }
+ };
+ const req = _http.request(opts, (res) => {
+ res.on('error', reject);
+ res.on('end', () => {
+ try {
+ if (res.statusCode === 200) {
+ resolve();
+ } else {
+ reject(new Error('Unexpected status code: ' + res.statusCode));
+ }
+ } catch (e: unknown) {
+ reject(e);
+ }
+ });
+ });
+ req.on('error', reject);
+ req.write(message);
+ req.end();
+ });
+ })().catch(error => {
+ this._logService.error(error);
+ });
+
// Do this when extension service exists, but extensions are not being activated yet.
const configProvider = await this._extHostConfiguration.getConfigProvider();
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._logService, this._mainThreadTelemetryProxy, this._initData);
Index: code-server/lib/vscode/src/vs/workbench/api/node/extensionHostProcess.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/api/node/extensionHostProcess.ts
+++ code-server/lib/vscode/src/vs/workbench/api/node/extensionHostProcess.ts
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
+import * as _http from 'http';
import * as nativeWatchdog from 'native-watchdog';
import * as net from 'net';
import * as minimist from 'minimist';
@@ -418,7 +419,28 @@ async function startExtensionHostProcess
);
// rewrite onTerminate-function to be a proper shutdown
- onTerminate = (reason: string) => extensionHostMain.terminate(reason);
+ onTerminate = (reason: string) => {
+ extensionHostMain.terminate(reason);
+
+ const socketPath = process.env['VSCODE_IPC_HOOK_CLI'];
+ const codeServerSocketPath = process.env['CODE_SERVER_SESSION_SOCKET']
+ if (!socketPath || !codeServerSocketPath) {
+ return;
+ }
+ const message = JSON.stringify({socketPath});
+ const opts: _http.RequestOptions = {
+ path: '/delete-session',
+ socketPath: codeServerSocketPath,
+ method: 'POST',
+ headers: {
+ 'content-type': 'application/json',
+ 'accept': 'application/json'
+ }
+ };
+ const req = _http.request(opts);
+ req.write(message);
+ req.end();
+ };
}
startExtensionHostProcess().catch((err) => console.log(err));

View File

@@ -12,30 +12,26 @@ 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
@@ -69,6 +69,7 @@ import { IExtensionsScannerService } fro
@@ -65,6 +65,7 @@ import { IExtensionsScannerService } fro
import { ExtensionsScannerService } from 'vs/server/node/extensionsScannerService';
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
+import { TelemetryClient } from "vs/server/node/telemetryClient";
+import { TelemetryClient } from 'vs/server/node/telemetryClient';
import { NullPolicyService } from 'vs/platform/policy/common/policy';
import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender';
import { LoggerService } from 'vs/platform/log/node/loggerService';
@@ -150,10 +151,13 @@ export async function setupServerService
@@ -149,7 +150,10 @@ export async function setupServerService
let oneDsAppender: ITelemetryAppender = NullAppender;
const isInternal = isInternalTelemetry(productService, configurationService);
if (supportsTelemetry(productService, environmentService)) {
- if (productService.aiConfig && productService.aiConfig.ariaKey) {
- if (!isLoggingOnly(productService, environmentService) && productService.aiConfig?.ariaKey) {
+ const telemetryEndpoint = process.env.CS_TELEMETRY_URL || "https://v1.telemetry.coder.com/track";
+ if (telemetryEndpoint) {
+ oneDsAppender = new OneDataSystemAppender(false, eventPrefix, null, () => new TelemetryClient(telemetryEndpoint));
+ } else if (productService.aiConfig && productService.aiConfig.ariaKey) {
oneDsAppender = new OneDataSystemAppender(isInternal, eventPrefix, null, productService.aiConfig.ariaKey);
- disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data
+ oneDsAppender = new OneDataSystemAppender(requestService, false, eventPrefix, null, () => new TelemetryClient(telemetryEndpoint));
+ } else if (!isLoggingOnly(productService, environmentService) && productService.aiConfig?.ariaKey) {
oneDsAppender = new OneDataSystemAppender(requestService, isInternal, eventPrefix, null, productService.aiConfig.ariaKey);
disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data
}
+ disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data
const config: ITelemetryServiceConfig = {
appenders: [oneDsAppender],
Index: code-server/lib/vscode/src/vs/server/node/telemetryClient.ts
===================================================================
--- /dev/null
@@ -94,7 +90,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -310,6 +310,7 @@ export class WebClientServer {
@@ -317,6 +317,7 @@ export class WebClientServer {
scope: vscodeBase + '/',
path: base + '/_static/out/browser/serviceWorker.js',
},

View File

@@ -13,7 +13,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/storage/browser/storageS
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/storage/browser/storageService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/storage/browser/storageService.ts
@@ -17,6 +17,7 @@ import { AbstractStorageService, isProfi
@@ -18,6 +18,7 @@ import { AbstractStorageService, isProfi
import { isUserDataProfile, IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
@@ -21,7 +21,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/storage/browser/storageS
export class BrowserStorageService extends AbstractStorageService {
@@ -297,7 +298,11 @@ export class IndexedDBStorageDatabase ex
@@ -298,7 +299,11 @@ export class IndexedDBStorageDatabase ex
}
static async createWorkspaceStorage(workspaceId: string, logService: ILogService): Promise<IIndexedDBStorageDatabase> {

View File

@@ -105,7 +105,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -303,6 +303,7 @@ export class WebClientServer {
@@ -310,6 +310,7 @@ export class WebClientServer {
const productConfiguration = <Partial<IProductConfiguration>>{
codeServerVersion: this._productService.codeServerVersion,
rootEndpoint: base,
@@ -117,8 +117,8 @@ 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
@@ -11,6 +11,8 @@ import { refineServiceDecorator } from '
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -13,6 +13,8 @@ import { memoize } from 'vs/base/common/
import { URI } from 'vs/base/common/uri';
export const serverOptions: OptionDescriptions<Required<ServerParsedArgs>> = {
+ /* ----- code-server ----- */
@@ -126,7 +126,7 @@ Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
/* ----- server setup ----- */
@@ -88,6 +90,8 @@ export const serverOptions: OptionDescri
@@ -92,6 +94,8 @@ export const serverOptions: OptionDescri
};
export interface ServerParsedArgs {

View File

@@ -41,7 +41,7 @@ Index: code-server/lib/vscode/src/vs/workbench/services/environment/browser/envi
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts
@@ -215,7 +215,7 @@ export class BrowserWorkbenchEnvironment
@@ -225,7 +225,7 @@ export class BrowserWorkbenchEnvironment
@memoize
get webviewExternalEndpoint(): string {
@@ -54,7 +54,7 @@ Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -316,6 +316,7 @@ export class WebClientServer {
@@ -323,6 +323,7 @@ export class WebClientServer {
const workbenchWebConfiguration = {
remoteAuthority,
@@ -70,12 +70,12 @@ 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-N4YFn5ze5crjPqMK/opogKs7bSGWtf3lmjV/3LfbSOs=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
+ content="default-src 'none'; script-src 'sha256-B5FRTRmagxqZ2yiS/ip5EgFZJPHAF0G0O3NgwgN6hhg=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
- content="default-src 'none'; script-src 'sha256-frEVWVmmI4TWHGHXZaCTWqGQI9jv+i8hv+sOa87Gqlc=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
+ content="default-src 'none'; script-src 'sha256-1BNp/IJ0Swu9k0gYe2BJz18zVYJ4emIdN3fjPgGScQI=' 'self'; frame-src 'self'; style-src 'unsafe-inline';">
<!-- Disable pinch zooming -->
<meta name="viewport"
@@ -334,6 +334,12 @@
@@ -339,6 +339,12 @@
const hostname = location.hostname;
@@ -92,7 +92,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-no-csp.html
+++ code-server/lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html
@@ -333,6 +333,12 @@
@@ -338,6 +338,12 @@
const hostname = location.hostname;
@@ -113,8 +113,8 @@ Index: code-server/lib/vscode/src/vs/workbench/services/extensions/worker/webWor
<meta http-equiv="Content-Security-Policy" content="
default-src 'none';
child-src 'self' data: blob:;
- script-src 'self' 'unsafe-eval' 'sha256-/r7rqQ+yrxt57sxLuQ6AMYcy/lUpvAIzHjIJt/OeLWU=' https:;
+ script-src 'self' 'unsafe-eval' 'sha256-TkIM/TmudlFEe0ZRp0ptvN54LClwk30Rql4ZPE0hm/I=' https:;
- script-src 'self' 'unsafe-eval' 'sha256-75NYUUvf+5++1WbfCZOV3PSWxBhONpaxwx+mkOFRv/Y=' https:;
+ script-src 'self' 'unsafe-eval' 'sha256-c7vPrYRaSLDtFSrI4CuHYgBQ3a4c4x2LSm/LefSZADQ=' https:;
connect-src 'self' https: wss: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*;"/>
</head>
<body>

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />

View File

@@ -46,7 +46,9 @@ button {
.card-box {
background-color: rgb(250, 253, 258);
border-radius: 5px;
box-shadow: rgba(60, 66, 87, 0.117647) 0px 7px 14px 0px, rgba(0, 0, 0, 0.117647) 0px 3px 6px 0px;
box-shadow:
rgba(60, 66, 87, 0.117647) 0px 7px 14px 0px,
rgba(0, 0, 0, 0.117647) 0px 3px 6px 0px;
max-width: 650px;
width: 100%;
}

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />

View File

@@ -14,7 +14,11 @@ export enum HttpCode {
* used in the HTTP response.
*/
export class HttpError extends Error {
public constructor(message: string, public readonly statusCode: HttpCode, public readonly details?: object) {
public constructor(
message: string,
public readonly statusCode: HttpCode,
public readonly details?: object,
) {
super(message)
this.name = this.constructor.name
}

View File

@@ -9,9 +9,11 @@ import * as util from "../common/util"
import { DefaultedArgs } from "./cli"
import { disposer } from "./http"
import { isNodeJSErrnoException } from "./util"
import { EditorSessionManager, makeEditorSessionManagerServer } from "./vscodeSocket"
import { handleUpgrade } from "./wsRouter"
type ListenOptions = Pick<DefaultedArgs, "socket-mode" | "socket" | "port" | "host">
type SocketOptions = { socket: string; "socket-mode"?: string }
type ListenOptions = DefaultedArgs | SocketOptions
export interface App extends Disposable {
/** Handles regular HTTP requests. */
@@ -20,12 +22,18 @@ export interface App extends Disposable {
wsRouter: Express
/** The underlying HTTP server. */
server: http.Server
/** Handles requests to the editor session management API. */
editorSessionManagerServer: http.Server
}
export const listen = async (server: http.Server, { host, port, socket, "socket-mode": mode }: ListenOptions) => {
if (socket) {
const isSocketOpts = (opts: ListenOptions): opts is SocketOptions => {
return !!(opts as SocketOptions).socket || !(opts as DefaultedArgs).host
}
export const listen = async (server: http.Server, opts: ListenOptions) => {
if (isSocketOpts(opts)) {
try {
await fs.unlink(socket)
await fs.unlink(opts.socket)
} catch (error: any) {
handleArgsSocketCatchError(error)
}
@@ -38,18 +46,20 @@ export const listen = async (server: http.Server, { host, port, socket, "socket-
server.on("error", (err) => util.logError(logger, "http server error", err))
resolve()
}
if (socket) {
server.listen(socket, onListen)
if (isSocketOpts(opts)) {
server.listen(opts.socket, onListen)
} else {
// [] is the correct format when using :: but Node errors with them.
server.listen(port, host.replace(/^\[|\]$/g, ""), onListen)
server.listen(opts.port, opts.host.replace(/^\[|\]$/g, ""), onListen)
}
})
// NOTE@jsjoeio: we need to chmod after the server is finished
// listening. Otherwise, the socket may not have been created yet.
if (socket && mode) {
await fs.chmod(socket, mode)
if (isSocketOpts(opts)) {
if (opts["socket-mode"]) {
await fs.chmod(opts.socket, opts["socket-mode"])
}
}
}
@@ -70,14 +80,22 @@ export const createApp = async (args: DefaultedArgs): Promise<App> => {
)
: http.createServer(router)
const dispose = disposer(server)
const disposeServer = disposer(server)
await listen(server, args)
const wsRouter = express()
handleUpgrade(wsRouter, server)
return { router, wsRouter, server, dispose }
const editorSessionManager = new EditorSessionManager()
const editorSessionManagerServer = await makeEditorSessionManagerServer(args["session-socket"], editorSessionManager)
const disposeEditorSessionManagerServer = disposer(editorSessionManagerServer)
const dispose = async () => {
await Promise.all([disposeServer(), disposeEditorSessionManagerServer()])
}
return { router, wsRouter, server, dispose, editorSessionManagerServer }
}
/**

View File

@@ -1,19 +1,9 @@
import { field, Level, logger } from "@coder/logger"
import { promises as fs } from "fs"
import { load } from "js-yaml"
import * as os from "os"
import * as path from "path"
import {
canConnect,
generateCertificate,
generatePassword,
humanPath,
paths,
isNodeJSErrnoException,
splitOnFirstEquals,
} from "./util"
const DEFAULT_SOCKET_PATH = path.join(os.tmpdir(), "vscode-ipc")
import { generateCertificate, generatePassword, paths, splitOnFirstEquals } from "./util"
import { EditorSessionManagerClient } from "./vscodeSocket"
export enum Feature {
// No current experimental features!
@@ -58,8 +48,11 @@ export interface UserProvidedCodeArgs {
"github-auth"?: string
"disable-update-check"?: boolean
"disable-file-downloads"?: boolean
"disable-file-uploads"?: boolean
"disable-workspace-trust"?: boolean
"disable-getting-started-override"?: boolean
"disable-proxy"?: boolean
"session-socket"?: string
}
/**
@@ -87,6 +80,7 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs {
"bind-addr"?: string
socket?: string
"socket-mode"?: string
"trusted-origins"?: string[]
version?: boolean
"proxy-domain"?: string[]
"reuse-window"?: boolean
@@ -169,11 +163,18 @@ export const options: Options<Required<UserProvidedArgs>> = {
"Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and \n" +
"then notifies you once every week that a new release is available.",
},
"session-socket": {
type: "string",
},
"disable-file-downloads": {
type: "boolean",
description:
"Disable file downloads from Code. This can also be set with CS_DISABLE_FILE_DOWNLOADS set to 'true' or '1'.",
},
"disable-file-uploads": {
type: "boolean",
description: "Disable file uploads.",
},
"disable-workspace-trust": {
type: "boolean",
description: "Disable Workspace Trust feature. This switch only affects the current session.",
@@ -182,6 +183,10 @@ export const options: Options<Required<UserProvidedArgs>> = {
type: "boolean",
description: "Disable the coder/coder override in the Help: Getting Started page.",
},
"disable-proxy": {
type: "boolean",
description: "Disable domain and path proxy routes.",
},
// --enable can be used to enable experimental features. These features
// provide no guarantees.
enable: { type: "string[]" },
@@ -213,6 +218,11 @@ export const options: Options<Required<UserProvidedArgs>> = {
socket: { type: "string", path: true, description: "Path to a socket (bind-addr will be ignored)." },
"socket-mode": { type: "string", description: "File mode of the socket." },
"trusted-origins": {
type: "string[]",
description:
"Disables authenticate origin check for trusted origin. Useful if not able to access reverse proxy configuration.",
},
version: { type: "boolean", short: "v", description: "Display version information." },
_: { type: "string[]" },
@@ -468,6 +478,7 @@ export interface DefaultedArgs extends ConfigArgs {
usingEnvHashedPassword: boolean
"extensions-dir": string
"user-data-dir": string
"session-socket": string
/* Positional arguments. */
_: string[]
}
@@ -488,6 +499,11 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
args["extensions-dir"] = path.join(args["user-data-dir"], "extensions")
}
if (!args["session-socket"]) {
args["session-socket"] = path.join(args["user-data-dir"], "code-server-ipc.sock")
}
process.env.CODE_SERVER_SESSION_SOCKET = args["session-socket"]
// --verbose takes priority over --log and --log takes priority over the
// environment variable.
if (args.verbose) {
@@ -557,6 +573,10 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
args["disable-getting-started-override"] = true
}
if (process.env.CS_DISABLE_PROXY?.match(/^(1|true)$/)) {
args["disable-proxy"] = true
}
const usingEnvHashedPassword = !!process.env.HASHED_PASSWORD
if (process.env.HASHED_PASSWORD) {
args["hashed-password"] = process.env.HASHED_PASSWORD
@@ -574,14 +594,24 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
// Filter duplicate proxy domains and remove any leading `*.`.
const proxyDomains = new Set((args["proxy-domain"] || []).map((d) => d.replace(/^\*\./, "")))
args["proxy-domain"] = Array.from(proxyDomains)
if (args["proxy-domain"].length > 0 && !process.env.VSCODE_PROXY_URI) {
process.env.VSCODE_PROXY_URI = `{{port}}.${args["proxy-domain"][0]}`
const finalProxies = []
for (const proxyDomain of proxyDomains) {
if (!proxyDomain.includes("{{port}}")) {
finalProxies.push("{{port}}." + proxyDomain)
} else {
finalProxies.push(proxyDomain)
}
}
if (typeof args._ === "undefined") {
args._ = []
// all proxies are of format anyprefix-{{port}}-anysuffix.{{host}}, where {{host}} is optional
// e.g. code-8080.domain.tld would match for code-{{port}}.domain.tld and code-{{port}}.{{host}}
if (finalProxies.length > 0 && !process.env.VSCODE_PROXY_URI) {
process.env.VSCODE_PROXY_URI = `//${finalProxies[0]}`
}
args["proxy-domain"] = finalProxies
args._ = getResolvedPathsFromArgs(args)
return {
...args,
@@ -590,6 +620,10 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
} as DefaultedArgs // TODO: Technically no guarantee this is fulfilled.
}
export function getResolvedPathsFromArgs(args: UserProvidedArgs): string[] {
return (args._ ?? []).map((p) => path.resolve(p))
}
/**
* Helper function to return the default config file.
*
@@ -633,7 +667,7 @@ export async function readConfigFile(configPath?: string): Promise<ConfigArgs> {
await fs.writeFile(configPath, defaultConfigFile(generatedPassword), {
flag: "wx", // wx means to fail if the path exists.
})
logger.info(`Wrote default config file to ${humanPath(os.homedir(), configPath)}`)
logger.info(`Wrote default config file to ${configPath}`)
} catch (error: any) {
// EEXIST is fine; we don't want to overwrite existing configurations.
if (error.code !== "EEXIST") {
@@ -703,6 +737,9 @@ export function bindAddrFromArgs(addr: Addr, args: UserProvidedArgs): Addr {
if (args["bind-addr"]) {
addr = parseBindAddr(args["bind-addr"])
}
if (process.env.CODE_SERVER_HOST) {
addr.host = process.env.CODE_SERVER_HOST
}
if (args.host) {
addr.host = args.host
}
@@ -729,47 +766,38 @@ function bindAddrFromAllSources(...argsConfig: UserProvidedArgs[]): Addr {
return addr
}
/**
* Reads the socketPath based on path passed in.
*
* The one usually passed in is the DEFAULT_SOCKET_PATH.
*
* If it can't read the path, it throws an error and returns undefined.
*/
export async function readSocketPath(path: string): Promise<string | undefined> {
try {
return await fs.readFile(path, "utf8")
} catch (error) {
// If it doesn't exist, we don't care.
// But if it fails for some reason, we should throw.
// We want to surface that to the user.
if (!isNodeJSErrnoException(error) || error.code !== "ENOENT") {
throw error
}
}
return undefined
}
/**
* Determine if it looks like the user is trying to open a file or folder in an
* existing instance. The arguments here should be the arguments the user
* explicitly passed on the command line, *NOT DEFAULTS* or the configuration.
*/
export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Promise<string | undefined> => {
export const shouldOpenInExistingInstance = async (
args: UserProvidedArgs,
sessionSocket: string,
): Promise<string | undefined> => {
// Always use the existing instance if we're running from VS Code's terminal.
if (process.env.VSCODE_IPC_HOOK_CLI) {
logger.debug("Found VSCODE_IPC_HOOK_CLI")
return process.env.VSCODE_IPC_HOOK_CLI
}
const paths = getResolvedPathsFromArgs(args)
const client = new EditorSessionManagerClient(sessionSocket)
// If these flags are set then assume the user is trying to open in an
// existing instance since these flags have no effect otherwise.
// existing instance since these flags have no effect otherwise. That means
// if there is no existing instance we should error rather than falling back
// to spawning code-server normally.
const openInFlagCount = ["reuse-window", "new-window"].reduce((prev, cur) => {
return args[cur as keyof UserProvidedArgs] ? prev + 1 : prev
}, 0)
if (openInFlagCount > 0) {
logger.debug("Found --reuse-window or --new-window")
return readSocketPath(DEFAULT_SOCKET_PATH)
const socketPath = await client.getConnectedSocketPath(paths[0])
if (!socketPath) {
throw new Error(`No opened code-server instances found to handle ${paths[0]}`)
}
return socketPath
}
// It's possible the user is trying to spawn another instance of code-server.
@@ -777,9 +805,13 @@ export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Prom
// code-server is invoked exactly like this: `code-server my-file`).
// 2. That a file or directory was passed.
// 3. That the socket is active.
// 4. That an instance exists to handle the path (implied by #3).
if (Object.keys(args).length === 1 && typeof args._ !== "undefined" && args._.length > 0) {
const socketPath = await readSocketPath(DEFAULT_SOCKET_PATH)
if (socketPath && (await canConnect(socketPath))) {
if (!(await client.canConnect())) {
return undefined
}
const socketPath = await client.getConnectedSocketPath(paths[0])
if (socketPath) {
logger.debug("Found existing code-server socket")
return socketPath
}

View File

@@ -51,7 +51,7 @@ async function entry(): Promise<void> {
return runCodeCli(args)
}
const socketPath = await shouldOpenInExistingInstance(cliArgs)
const socketPath = await shouldOpenInExistingInstance(cliArgs, args["session-socket"])
if (socketPath) {
logger.debug("Trying to open in existing instance")
return openInExistingInstance(args, socketPath)

View File

@@ -9,7 +9,10 @@ export class Heart {
private heartbeatInterval = 60000
public lastHeartbeat = 0
public constructor(private readonly heartbeatPath: string, private readonly isActive: () => Promise<boolean>) {
public constructor(
private readonly heartbeatPath: string,
private readonly isActive: () => Promise<boolean>,
) {
this.beat = this.beat.bind(this)
this.alive = this.alive.bind(this)
}
@@ -28,7 +31,7 @@ export class Heart {
return
}
logger.trace("heartbeat")
logger.debug("heartbeat")
this.lastHeartbeat = Date.now()
if (typeof this.heartbeatTimer !== "undefined") {
clearTimeout(this.heartbeatTimer)

View File

@@ -75,6 +75,25 @@ export const replaceTemplates = <T extends object>(
.replace("{{OPTIONS}}", () => escapeJSON(serverOptions))
}
/**
* Throw an error if proxy is not enabled. Call `next` if provided.
*/
export const ensureProxyEnabled = (req: express.Request, _?: express.Response, next?: express.NextFunction): void => {
if (!proxyEnabled(req)) {
throw new HttpError("Forbidden", HttpCode.Forbidden)
}
if (next) {
next()
}
}
/**
* Return true if proxy is enabled.
*/
export const proxyEnabled = (req: express.Request): boolean => {
return !req.args["disable-proxy"]
}
/**
* Throw an error if not authorized. Call `next` if provided.
*/
@@ -355,6 +374,11 @@ export function authenticateOrigin(req: express.Request): void {
throw new Error(`unable to parse malformed origin "${originRaw}"`)
}
const trustedOrigins = req.args["trusted-origins"] || []
if (trustedOrigins.includes(origin) || trustedOrigins.includes("*")) {
return
}
const host = getHost(req)
if (typeof host === "undefined") {
// A missing host likely means the reverse proxy has not been configured to
@@ -373,7 +397,7 @@ export function authenticateOrigin(req: express.Request): void {
/**
* Get the host from headers. It will be trimmed and lowercased.
*/
function getHost(req: express.Request): string | undefined {
export function getHost(req: express.Request): string | undefined {
// Honor Forwarded if present.
const forwardedRaw = getFirstHeader(req, "forwarded")
if (forwardedRaw) {

View File

@@ -1,7 +1,10 @@
import i18next, { init } from "i18next"
import * as en from "./locales/en.json"
import * as zhCn from "./locales/zh-cn.json"
import * as ja from "./locales/ja.json"
import * as th from "./locales/th.json"
import * as ur from "./locales/ur.json"
import * as zhCn from "./locales/zh-cn.json"
init({
lng: "en",
fallbackLng: "en", // language to use if translations in user language are not available.
@@ -18,6 +21,12 @@ init({
th: {
translation: th,
},
ja: {
translation: ja,
},
ur: {
translation: ur,
},
},
})

View File

@@ -0,0 +1,13 @@
{
"LOGIN_TITLE": "{{app}} ログイン",
"LOGIN_BELOW": "以下によりログインしてください。",
"WELCOME": "ようこそ {{app}} へ!",
"LOGIN_PASSWORD": "パスワードは設定ファイル( {{configFile}} )を確認してください。",
"LOGIN_USING_ENV_PASSWORD": "パスワードは環境変数 $PASSWORD で設定されています。",
"LOGIN_USING_HASHED_PASSWORD": "パスワードは環境変数 $HASHED_PASSWORD で設定されています。",
"SUBMIT": "実行",
"PASSWORD_PLACEHOLDER": "パスワード",
"LOGIN_RATE_LIMIT": "ログイン制限を超えました!",
"MISS_PASSWORD": "パスワードを入力してください。",
"INCORRECT_PASSWORD": "パスワードが間違っています。"
}

View File

@@ -0,0 +1,13 @@
{
"LOGIN_TITLE": "{{app}} لاگ ان کریں",
"LOGIN_BELOW": "براہ کرم نیچے لاگ ان کریں۔",
"WELCOME": "میں خوش آمدید {{app}}",
"LOGIN_PASSWORD": "پاس ورڈ کے لیے {{configFile}} پر کنفگ فائل چیک کریں۔",
"LOGIN_USING_ENV_PASSWORD": "پاس ورڈ $PASSWORD سے سیٹ کیا گیا تھا۔",
"LOGIN_USING_HASHED_PASSWORD": "پاس ورڈ $HASHED_PASSWORD سے سیٹ کیا گیا تھا۔",
"SUBMIT": "جمع کرائیں",
"PASSWORD_PLACEHOLDER": "پاس ورڈ",
"LOGIN_RATE_LIMIT": "لاگ ان کی شرح محدود!",
"MISS_PASSWORD": "پاس ورڈ غائب ہے۔",
"INCORRECT_PASSWORD": "غلط پاس ورڈ"
}

View File

@@ -1,14 +1,12 @@
import { field, logger } from "@coder/logger"
import http from "http"
import * as os from "os"
import path from "path"
import { Disposable } from "../common/emitter"
import { plural } from "../common/util"
import { createApp, ensureAddress } from "./app"
import { AuthType, DefaultedArgs, Feature, SpawnCodeCli, toCodeArgs, UserProvidedArgs } from "./cli"
import { commit, version } from "./constants"
import { register } from "./routes"
import { humanPath, isDirectory, loadAMDModule, open } from "./util"
import { isDirectory, loadAMDModule, open } from "./util"
/**
* Return true if the user passed an extension-related VS Code flag.
@@ -56,6 +54,7 @@ export const runCodeCli = async (args: DefaultedArgs): Promise<void> => {
await spawnCli(await toCodeArgs(args))
} catch (error: any) {
logger.error("Got error from Code", error)
process.exit(1)
}
process.exit(0)
@@ -70,9 +69,8 @@ export const openInExistingInstance = async (args: DefaultedArgs, socketPath: st
forceNewWindow: args["new-window"],
gotoLineMode: true,
}
const paths = args._ || []
for (let i = 0; i < paths.length; i++) {
const fp = path.resolve(paths[i])
for (let i = 0; i < args._.length; i++) {
const fp = args._[i]
if (await isDirectory(fp)) {
pipeArgs.folderURIs.push(fp)
} else {
@@ -111,8 +109,8 @@ export const runCodeServer = async (
): Promise<{ dispose: Disposable["dispose"]; server: http.Server }> => {
logger.info(`code-server ${version} ${commit}`)
logger.info(`Using user-data-dir ${humanPath(os.homedir(), args["user-data-dir"])}`)
logger.trace(`Using extensions-dir ${humanPath(os.homedir(), args["extensions-dir"])}`)
logger.info(`Using user-data-dir ${args["user-data-dir"]}`)
logger.debug(`Using extensions-dir ${args["extensions-dir"]}`)
if (args.auth === AuthType.Password && !args.password && !args["hashed-password"]) {
throw new Error(
@@ -125,9 +123,8 @@ export const runCodeServer = async (
const serverAddress = ensureAddress(app.server, protocol)
const disposeRoutes = await register(app, args)
logger.info(`Using config file ${humanPath(os.homedir(), args.config)}`)
logger.info(`Using config file ${args.config}`)
logger.info(`${protocol.toUpperCase()} server listening on ${serverAddress.toString()}`)
if (args.auth === AuthType.Password) {
logger.info(" - Authentication is enabled")
if (args.usingEnvPassword) {
@@ -135,21 +132,31 @@ export const runCodeServer = async (
} else if (args.usingEnvHashedPassword) {
logger.info(" - Using password from $HASHED_PASSWORD")
} else {
logger.info(` - Using password from ${humanPath(os.homedir(), args.config)}`)
logger.info(` - Using password from ${args.config}`)
}
} else {
logger.info(" - Authentication is disabled")
}
if (args.cert) {
logger.info(` - Using certificate for HTTPS: ${humanPath(os.homedir(), args.cert.value)}`)
logger.info(` - Using certificate for HTTPS: ${args.cert.value}`)
} else {
logger.info(" - Not serving HTTPS")
}
if (args["proxy-domain"].length > 0) {
if (args["disable-proxy"]) {
logger.info(" - Proxy disabled")
} else if (args["proxy-domain"].length > 0) {
logger.info(` - ${plural(args["proxy-domain"].length, "Proxying the following domain")}:`)
args["proxy-domain"].forEach((domain) => logger.info(` - *.${domain}`))
args["proxy-domain"].forEach((domain) => logger.info(` - ${domain}`))
}
if (process.env.VSCODE_PROXY_URI) {
logger.info(`Using proxy URI in PORTS tab: ${process.env.VSCODE_PROXY_URI}`)
}
const sessionServerAddress = app.editorSessionManagerServer.address()
if (sessionServerAddress) {
logger.info(`Session server listening on ${sessionServerAddress.toString()}`)
}
if (args.enable && args.enable.length > 0) {

View File

@@ -1,34 +1,56 @@
import { Request, Router } from "express"
import { HttpCode, HttpError } from "../../common/http"
import { authenticated, ensureAuthenticated, ensureOrigin, redirect, self } from "../http"
import { getHost, ensureProxyEnabled, authenticated, ensureAuthenticated, ensureOrigin, redirect, self } from "../http"
import { proxy } from "../proxy"
import { Router as WsRouter } from "../wsRouter"
export const router = Router()
const proxyDomainToRegex = (matchString: string): RegExp => {
const escapedMatchString = matchString.replace(/[.*+?^$()|[\]\\]/g, "\\$&")
// Replace {{port}} with a regex group to capture the port
// Replace {{host}} with .+ to allow any host match (so rely on DNS record here)
let regexString = escapedMatchString.replace("{{port}}", "(\\d+)")
regexString = regexString.replace("{{host}}", ".+")
regexString = regexString.replace(/[{}]/g, "\\$&") //replace any '{}' that might be left
return new RegExp("^" + regexString + "$")
}
let proxyRegexes: RegExp[] = []
const proxyDomainsToRegex = (proxyDomains: string[]): RegExp[] => {
if (proxyDomains.length !== proxyRegexes.length) {
proxyRegexes = proxyDomains.map(proxyDomainToRegex)
}
return proxyRegexes
}
/**
* Return the port if the request should be proxied. Anything that ends in a
* proxy domain and has a *single* subdomain should be proxied. Anything else
* should return `undefined` and will be handled as normal.
* Return the port if the request should be proxied.
*
* The proxy-domain should be of format anyprefix-{{port}}-anysuffix.{{host}}, where {{host}} is optional
* e.g. code-8080.domain.tld would match for code-{{port}}.domain.tld and code-{{port}}.{{host}}.
*
* For example if `coder.com` is specified `8080.coder.com` will be proxied
* but `8080.test.coder.com` and `test.8080.coder.com` will not.
*/
const maybeProxy = (req: Request): string | undefined => {
// Split into parts.
const host = req.headers.host || ""
const idx = host.indexOf(":")
const domain = idx !== -1 ? host.substring(0, idx) : host
const parts = domain.split(".")
// There must be an exact match.
const port = parts.shift()
const proxyDomain = parts.join(".")
if (!port || !req.args["proxy-domain"].includes(proxyDomain)) {
const reqDomain = getHost(req)
if (reqDomain === undefined) {
return undefined
}
return port
const regexs = proxyDomainsToRegex(req.args["proxy-domain"])
for (const regex of regexs) {
const match = reqDomain.match(regex)
if (match) {
return match[1] // match[1] contains the port
}
}
return undefined
}
router.all("*", async (req, res, next) => {
@@ -37,6 +59,8 @@ router.all("*", async (req, res, next) => {
return next()
}
ensureProxyEnabled(req)
// Must be authenticated to use the proxy.
const isAuthenticated = await authenticated(req)
if (!isAuthenticated) {
@@ -78,6 +102,8 @@ wsRouter.ws("*", async (req, _, next) => {
if (!port) {
return next()
}
ensureProxyEnabled(req)
ensureOrigin(req)
await ensureAuthenticated(req)
proxy.ws(req, req.ws, req.head, {

View File

@@ -1,13 +1,12 @@
import { Router, Request } from "express"
import { promises as fs } from "fs"
import { RateLimiter as Limiter } from "limiter"
import * as os from "os"
import * as path from "path"
import { CookieKeys } from "../../common/http"
import { rootPath } from "../constants"
import { authenticated, getCookieOptions, redirect, replaceTemplates } from "../http"
import { getPasswordMethod, handlePasswordValidation, humanPath, sanitizeString, escapeHtml } from "../util"
import i18n from "../i18n"
import { getPasswordMethod, handlePasswordValidation, sanitizeString, escapeHtml } from "../util"
// RateLimiter wraps around the limiter library for logins.
// It allows 2 logins every minute plus 12 logins every hour.
@@ -33,7 +32,7 @@ const getRoot = async (req: Request, error?: Error): Promise<string> => {
i18n.changeLanguage(locale)
const appName = req.args["app-name"] || "code-server"
const welcomeText = req.args["welcome-text"] || (i18n.t("WELCOME", { app: appName }) as string)
let passwordMsg = i18n.t("LOGIN_PASSWORD", { configFile: humanPath(os.homedir(), req.args.config) })
let passwordMsg = i18n.t("LOGIN_PASSWORD", { configFile: req.args.config })
if (req.args.usingEnvPassword) {
passwordMsg = i18n.t("LOGIN_USING_ENV_PASSWORD")
} else if (req.args.usingEnvHashedPassword) {

View File

@@ -1,17 +1,14 @@
import { Request, Response } from "express"
import * as path from "path"
import * as qs from "qs"
import * as pluginapi from "../../../typings/pluginapi"
import { HttpCode, HttpError } from "../../common/http"
import { authenticated, ensureAuthenticated, ensureOrigin, redirect, self } from "../http"
import { ensureProxyEnabled, authenticated, ensureAuthenticated, ensureOrigin, redirect, self } from "../http"
import { proxy as _proxy } from "../proxy"
const getProxyTarget = (req: Request, passthroughPath?: boolean): string => {
if (passthroughPath) {
return `http://0.0.0.0:${req.params.port}/${req.originalUrl}`
}
const query = qs.stringify(req.query)
return encodeURI(`http://0.0.0.0:${req.params.port}${req.params[0] || ""}${query ? `?${query}` : ""}`)
const getProxyTarget = (req: Request): string => {
// If there is a base path, strip it out.
const base = (req as any).base || ""
return `http://0.0.0.0:${req.params.port}/${req.originalUrl.slice(base.length)}`
}
export async function proxy(
@@ -21,6 +18,8 @@ export async function proxy(
passthroughPath?: boolean
},
): Promise<void> {
ensureProxyEnabled(req)
if (!(await authenticated(req))) {
// If visiting the root (/:port only) redirect to the login page.
if (!req.params[0] || req.params[0] === "/") {
@@ -32,15 +31,14 @@ export async function proxy(
throw new HttpError("Unauthorized", HttpCode.Unauthorized)
}
// The base is used for rewriting (redirects, target).
if (!opts?.passthroughPath) {
// Absolute redirects need to be based on the subpath when rewriting.
// See proxy.ts.
;(req as any).base = req.path.split(path.sep).slice(0, 3).join(path.sep)
}
_proxy.web(req, res, {
ignorePath: true,
target: getProxyTarget(req, opts?.passthroughPath),
target: getProxyTarget(req),
})
}
@@ -50,10 +48,17 @@ export async function wsProxy(
passthroughPath?: boolean
},
): Promise<void> {
ensureProxyEnabled(req)
ensureOrigin(req)
await ensureAuthenticated(req)
// The base is used for rewriting (redirects, target).
if (!opts?.passthroughPath) {
;(req as any).base = req.path.split(path.sep).slice(0, 3).join(path.sep)
}
_proxy.ws(req, req.ws, req.head, {
ignorePath: true,
target: getProxyTarget(req, opts?.passthroughPath),
target: getProxyTarget(req),
})
}

View File

@@ -1,5 +1,7 @@
import { logger } from "@coder/logger"
import * as crypto from "crypto"
import * as express from "express"
import { promises as fs } from "fs"
import * as http from "http"
import * as net from "net"
import * as path from "path"
@@ -32,6 +34,7 @@ export class CodeServerRouteWrapper {
private _wsRouterWrapper = WsRouter()
private _socketProxyProvider = new SocketProxyProvider()
public router = express.Router()
private mintKeyPromise: Promise<Buffer> | undefined
public get wsRouter() {
return this._wsRouterWrapper.router
@@ -52,6 +55,7 @@ export class CodeServerRouteWrapper {
short_name: appName,
start_url: ".",
display: "fullscreen",
display_override: ["window-controls-overlay"],
description: "Run Code on a remote server.",
icons: [192, 512].map((size) => ({
src: `{{BASE}}/_static/src/browser/media/pwa-icon-${size}.png`,
@@ -66,6 +70,33 @@ export class CodeServerRouteWrapper {
)
}
private mintKey: express.Handler = async (req, res, next) => {
if (!this.mintKeyPromise) {
this.mintKeyPromise = new Promise(async (resolve) => {
const keyPath = path.join(req.args["user-data-dir"], "serve-web-key-half")
logger.debug(`Reading server web key half from ${keyPath}`)
try {
resolve(await fs.readFile(keyPath))
return
} catch (error: any) {
if (error.code !== "ENOENT") {
logError(logger, `read ${keyPath}`, error)
}
}
// VS Code wants 256 bits.
const key = crypto.randomBytes(32)
try {
await fs.writeFile(keyPath, key)
} catch (error: any) {
logError(logger, `write ${keyPath}`, error)
}
resolve(key)
})
}
const key = await this.mintKeyPromise
res.end(key)
}
private $root: express.Handler = async (req, res, next) => {
const isAuthenticated = await authenticated(req)
const NO_FOLDER_OR_WORKSPACE_QUERY = !req.query.folder && !req.query.workspace
@@ -173,6 +204,7 @@ export class CodeServerRouteWrapper {
constructor() {
this.router.get("/", this.ensureCodeServerLoaded, this.$root)
this.router.get("/manifest.json", this.manifest)
this.router.post("/mint-key", this.mintKey)
this.router.all("*", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyRequest)
this._wsRouterWrapper.ws("*", ensureOrigin, ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyWebsocket)
}

View File

@@ -1,7 +1,7 @@
import { field, logger } from "@coder/logger"
import * as http from "http"
import * as https from "https"
import ProxyAgent from "proxy-agent"
import { ProxyAgent } from "proxy-agent"
import * as semver from "semver"
import * as url from "url"
import { httpProxyUri, version } from "./constants"
@@ -104,7 +104,9 @@ export class UpdateProvider {
const request = (uri: string): void => {
logger.debug("Making request", field("uri", uri))
const isHttps = uri.startsWith("https")
const agent = httpProxyUri ? new ProxyAgent(httpProxyUri) : undefined
const agent = new ProxyAgent({
getProxyForUrl: () => httpProxyUri || "",
})
const httpx = isHttps ? https : http
const client = httpx.get(uri, { headers: { "User-Agent": "code-server" }, agent }, (response) => {
if (!response.statusCode || response.statusCode < 200 || response.statusCode >= 400) {

View File

@@ -87,20 +87,6 @@ export function getEnvPaths(platform = process.platform): Paths {
}
}
/**
* humanPath replaces the home directory in path with ~.
* Makes it more readable.
*
* @param homedir - the home directory(i.e. `os.homedir()`)
* @param path - a file path
*/
export function humanPath(homedir: string, path?: string): string {
if (!path) {
return ""
}
return path.replace(homedir, "~")
}
export const generateCertificate = async (hostname: string): Promise<{ cert: string; certKey: string }> => {
const certPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.crt`)
const certKeyPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.key`)

206
src/node/vscodeSocket.ts Normal file
View File

@@ -0,0 +1,206 @@
import { logger } from "@coder/logger"
import express from "express"
import * as http from "http"
import * as path from "path"
import { HttpCode } from "../common/http"
import { listen } from "./app"
import { canConnect } from "./util"
export interface EditorSessionEntry {
workspace: {
id: string
folders: {
uri: {
path: string
}
}[]
}
socketPath: string
}
interface DeleteSessionRequest {
socketPath: string
}
interface AddSessionRequest {
entry: EditorSessionEntry
}
interface GetSessionResponse {
socketPath?: string
}
export async function makeEditorSessionManagerServer(
codeServerSocketPath: string,
editorSessionManager: EditorSessionManager,
): Promise<http.Server> {
const router = express()
// eslint-disable-next-line import/no-named-as-default-member
router.use(express.json())
router.get("/session", async (req, res) => {
const filePath = req.query.filePath as string
if (!filePath) {
res.status(HttpCode.BadRequest).send("filePath is required")
return
}
try {
const socketPath = await editorSessionManager.getConnectedSocketPath(filePath)
const response: GetSessionResponse = { socketPath }
res.json(response)
} catch (error: unknown) {
res.status(HttpCode.ServerError).send(error)
}
})
router.post("/add-session", async (req, res) => {
const request = req.body as AddSessionRequest
if (!request.entry) {
res.status(400).send("entry is required")
}
editorSessionManager.addSession(request.entry)
res.status(200).send()
})
router.post("/delete-session", async (req, res) => {
const request = req.body as DeleteSessionRequest
if (!request.socketPath) {
res.status(400).send("socketPath is required")
}
editorSessionManager.deleteSession(request.socketPath)
res.status(200).send()
})
const server = http.createServer(router)
try {
await listen(server, { socket: codeServerSocketPath })
} catch (e) {
logger.warn(`Could not create socket at ${codeServerSocketPath}`)
}
return server
}
export class EditorSessionManager {
// Map from socket path to EditorSessionEntry.
private entries = new Map<string, EditorSessionEntry>()
addSession(entry: EditorSessionEntry): void {
logger.debug(`Adding session to session registry: ${entry.socketPath}`)
this.entries.set(entry.socketPath, entry)
}
getCandidatesForFile(filePath: string): EditorSessionEntry[] {
const matchCheckResults = new Map<string, boolean>()
const checkMatch = (entry: EditorSessionEntry): boolean => {
if (matchCheckResults.has(entry.socketPath)) {
return matchCheckResults.get(entry.socketPath)!
}
const result = entry.workspace.folders.some((folder) => filePath.startsWith(folder.uri.path + path.sep))
matchCheckResults.set(entry.socketPath, result)
return result
}
return Array.from(this.entries.values())
.reverse() // Most recently registered first.
.sort((a, b) => {
// Matches first.
const aMatch = checkMatch(a)
const bMatch = checkMatch(b)
if (aMatch === bMatch) {
return 0
}
if (aMatch) {
return -1
}
return 1
})
}
deleteSession(socketPath: string): void {
logger.debug(`Deleting session from session registry: ${socketPath}`)
this.entries.delete(socketPath)
}
/**
* Returns the best socket path that we can connect to.
* We also delete any sockets that we can't connect to.
*/
async getConnectedSocketPath(filePath: string): Promise<string | undefined> {
const candidates = this.getCandidatesForFile(filePath)
let match: EditorSessionEntry | undefined = undefined
for (const candidate of candidates) {
if (await canConnect(candidate.socketPath)) {
match = candidate
break
}
this.deleteSession(candidate.socketPath)
}
return match?.socketPath
}
}
export class EditorSessionManagerClient {
constructor(private codeServerSocketPath: string) {}
async canConnect() {
return canConnect(this.codeServerSocketPath)
}
async getConnectedSocketPath(filePath: string): Promise<string | undefined> {
const response = await new Promise<GetSessionResponse>((resolve, reject) => {
const opts = {
path: "/session?filePath=" + encodeURIComponent(filePath),
socketPath: this.codeServerSocketPath,
method: "GET",
}
const req = http.request(opts, (res) => {
let rawData = ""
res.setEncoding("utf8")
res.on("data", (chunk) => {
rawData += chunk
})
res.on("end", () => {
try {
const obj = JSON.parse(rawData)
if (res.statusCode === 200) {
resolve(obj)
} else {
reject(new Error("Unexpected status code: " + res.statusCode))
}
} catch (e: unknown) {
reject(e)
}
})
})
req.on("error", reject)
req.end()
})
return response.socketPath
}
// Currently only used for tests.
async addSession(request: AddSessionRequest): Promise<void> {
await new Promise<void>((resolve, reject) => {
const opts = {
path: "/add-session",
socketPath: this.codeServerSocketPath,
method: "POST",
headers: {
"content-type": "application/json",
accept: "application/json",
},
}
const req = http.request(opts, () => {
resolve()
})
req.on("error", reject)
req.write(JSON.stringify(request))
req.end()
})
}
}

View File

@@ -78,7 +78,10 @@ type ChildMessage = RelaunchMessage | ChildHandshakeMessage
type ParentMessage = ParentHandshakeMessage
class ProcessError extends Error {
public constructor(message: string, public readonly code: number | undefined) {
public constructor(
message: string,
public readonly code: number | undefined,
) {
super(message)
this.name = this.constructor.name
Error.captureStackTrace(this, this.constructor)

View File

@@ -23,6 +23,41 @@ describe("Downloads (enabled)", ["--disable-workspace-trust"], {}, async () => {
expect(await codeServerPage.page.isVisible("text=Download...")).toBe(true)
})
test("should see the 'Show Local' button on Save As", async ({ codeServerPage }) => {
// Setup
const workspaceDir = await codeServerPage.workspaceDir
const fileName = "unique-file-save-as.txt"
const tmpFilePath = path.join(workspaceDir, fileName)
await fs.writeFile(tmpFilePath, "Hello World")
// Action
await codeServerPage.page.waitForSelector(`text=${fileName}`)
await codeServerPage.openFile(fileName)
await codeServerPage.page.click(".tab")
await codeServerPage.navigateMenus(["File", "Auto Save"])
await codeServerPage.page.keyboard.type("Making some edits.")
await codeServerPage.navigateMenus(["File", "Save As..."])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(true)
})
test("should see the 'Show Local' button on Save File", async ({ codeServerPage }) => {
// Action
await codeServerPage.navigateMenus(["File", "New Text File"])
await codeServerPage.waitForTab("Untitled-1")
await codeServerPage.navigateMenus(["File", "Save"])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(true)
})
test("should see the 'Show Local' button on Save Workspace As", async ({ codeServerPage }) => {
// Action
await codeServerPage.navigateMenus(["File", "Save Workspace As..."])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(true)
})
})
describe("Downloads (disabled)", ["--disable-workspace-trust", "--disable-file-downloads"], {}, async () => {
@@ -35,7 +70,7 @@ describe("Downloads (disabled)", ["--disable-workspace-trust", "--disable-file-d
// Setup
const workspaceDir = await codeServerPage.workspaceDir
const tmpFilePath = path.join(workspaceDir, "unique-file.txt")
await fs.writeFile(tmpFilePath, "hello world")
await fs.writeFile(tmpFilePath, "Hello World")
// Action
const fileInExplorer = await codeServerPage.page.waitForSelector("text=unique-file.txt")
@@ -45,4 +80,35 @@ describe("Downloads (disabled)", ["--disable-workspace-trust", "--disable-file-d
expect(await codeServerPage.page.isVisible("text=Download...")).toBe(false)
})
test("should not see the 'Show Local' button on Save as", async ({ codeServerPage }) => {
// Setup
const workspaceDir = await codeServerPage.workspaceDir
const fileName = "unique-file-save-as.txt"
const tmpFilePath = path.join(workspaceDir, fileName)
await fs.writeFile(tmpFilePath, "Hello World")
// Action
await codeServerPage.page.waitForSelector(`text=${fileName}`)
await codeServerPage.openFile(fileName)
await codeServerPage.page.click(".tab")
await codeServerPage.navigateMenus(["File", "Save As..."])
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(false)
})
test("should not see the 'Show Local' button on Save File", async ({ codeServerPage }) => {
// Action
await codeServerPage.navigateMenus(["File", "New Text File"])
await codeServerPage.waitForTab("Untitled-1")
await codeServerPage.navigateMenus(["File", "Save"])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(false)
})
test("should not see the 'Show Local' button on Save Workspace As", async ({ codeServerPage }) => {
// Action
await codeServerPage.navigateMenus(["File", "Save Workspace As..."])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(false)
})
})

View File

@@ -77,9 +77,9 @@ export class CodeServer {
*/
private async createWorkspace(): Promise<string> {
const dir = await this.workspaceDir
await fs.mkdir(path.join(dir, "User"), { recursive: true })
await fs.mkdir(path.join(dir, "Machine"), { recursive: true })
await fs.writeFile(
path.join(dir, "User/settings.json"),
path.join(dir, "Machine/settings.json"),
JSON.stringify({
"workbench.startupEditor": "none",
}),
@@ -117,40 +117,26 @@ export class CodeServer {
* directories.
*/
private async spawn(): Promise<CodeServerProcess> {
// This will be used both as the workspace and data directory to ensure
// instances don't bleed into each other.
const dir = await this.createWorkspace()
const args = await this.argsWithDefaults([
"--auth",
"none",
// The workspace to open.
...(this.args.includes("--ignore-last-opened") ? [] : [dir]),
...this.args,
// Using port zero will spawn on a random port.
"--bind-addr",
"127.0.0.1:0",
])
return new Promise((resolve, reject) => {
const args = [
this.entry,
"--extensions-dir",
path.join(dir, "extensions"),
"--auth",
"none",
// The workspace to open.
...(this.args.includes("--ignore-last-opened") ? [] : [dir]),
...this.args,
// Using port zero will spawn on a random port.
"--bind-addr",
"127.0.0.1:0",
// Setting the XDG variables would be easier and more thorough but the
// modules we import ignores those variables for non-Linux operating
// systems so use these flags instead.
"--config",
path.join(dir, "config.yaml"),
"--user-data-dir",
dir,
]
this.logger.debug("spawning `node " + args.join(" ") + "`")
const proc = cp.spawn("node", args, {
cwd: path.join(__dirname, "../../.."),
env: {
...process.env,
...this.env,
// Set to empty string to prevent code-server from
// using the existing instance when running the e2e tests
// from an integrated terminal.
// Prevent code-server from using the existing instance when running
// the e2e tests from an integrated terminal.
VSCODE_IPC_HOOK_CLI: "",
PASSWORD,
},
@@ -173,11 +159,15 @@ export class CodeServer {
reject(error)
})
// Tracks when the HTTP and session servers are ready.
let httpAddress: string | undefined
let sessionAddress: string | undefined
let resolved = false
proc.stdout.setEncoding("utf8")
onLine(proc, (line) => {
// As long as we are actively getting input reset the timer. If we stop
// getting input and still have not found the address the timer will
// getting input and still have not found the addresses the timer will
// reject.
timer.reset()
@@ -186,20 +176,69 @@ export class CodeServer {
if (resolved) {
return
}
const match = line.trim().match(/HTTPS? server listening on (https?:\/\/[.:\d]+)\/?$/)
let match = line.trim().match(/HTTPS? server listening on (https?:\/\/[.:\d]+)\/?$/)
if (match) {
// Cookies don't seem to work on IP address so swap to localhost.
// Cookies don't seem to work on IP addresses so swap to localhost.
// TODO: Investigate whether this is a bug with code-server.
const address = match[1].replace("127.0.0.1", "localhost")
this.logger.debug(`spawned on ${address}`)
httpAddress = match[1].replace("127.0.0.1", "localhost")
}
match = line.trim().match(/Session server listening on (.+)$/)
if (match) {
sessionAddress = match[1]
}
if (typeof httpAddress !== "undefined" && typeof sessionAddress !== "undefined") {
resolved = true
timer.dispose()
resolve({ process: proc, address })
this.logger.debug(`code-server is ready: ${httpAddress} ${sessionAddress}`)
resolve({ process: proc, address: httpAddress })
}
})
})
}
/**
* Execute a short-lived command.
*/
async run(args: string[]): Promise<void> {
args = await this.argsWithDefaults(args)
this.logger.debug("executing `node " + args.join(" ") + "`")
await util.promisify(cp.exec)("node " + args.join(" "), {
cwd: path.join(__dirname, "../../.."),
env: {
...process.env,
...this.env,
// Prevent code-server from using the existing instance when running
// the e2e tests from an integrated terminal.
VSCODE_IPC_HOOK_CLI: "",
},
})
}
/**
* Combine arguments with defaults.
*/
private async argsWithDefaults(args: string[]): Promise<string[]> {
// This will be used both as the workspace and data directory to ensure
// instances don't bleed into each other.
const dir = await this.workspaceDir
return [
this.entry,
"--extensions-dir",
path.join(dir, "extensions"),
...args,
// Setting the XDG variables would be easier and more thorough but the
// modules we import ignores those variables for non-Linux operating
// systems so use these flags instead.
"--config",
path.join(dir, "config.yaml"),
"--user-data-dir",
dir,
]
}
/**
* Close the code-server process.
*/
@@ -230,7 +269,10 @@ export class CodeServer {
export class CodeServerPage {
private readonly editorSelector = "div.monaco-workbench"
constructor(private readonly codeServer: CodeServer, public readonly page: Page) {
constructor(
private readonly codeServer: CodeServer,
public readonly page: Page,
) {
this.page.on("console", (message) => {
this.codeServer.logger.debug(message.text())
})
@@ -359,11 +401,18 @@ export class CodeServerPage {
* Open a file by using menus.
*/
async openFile(file: string) {
await this.navigateMenus(["File", "Open File"])
await this.navigateMenus(["File", "Open File..."])
await this.navigateQuickInput([path.basename(file)])
await this.waitForTab(file)
}
/**
* Open a file through an external command.
*/
async openFileExternally(file: string) {
await this.codeServer.run(["--reuse-window", file])
}
/**
* Wait for a tab to open for the specified file.
*/
@@ -383,7 +432,7 @@ export class CodeServerPage {
* it then clicking the match from the results.
*/
async executeCommandViaMenus(command: string) {
await this.navigateMenus(["View", "Command Palette"])
await this.navigateMenus(["View", "Command Palette..."])
await this.page.keyboard.type(command)
@@ -439,19 +488,19 @@ export class CodeServerPage {
// splitting them into two steps each we can cancel before running the
// action.
steps.push({
fn: () => this.page.hover(`${selector} :text("${item}")`, { trial: true }),
fn: () => this.page.hover(`${selector} :text-is("${item}")`, { trial: true }),
name: `${item}:hover:trial`,
})
steps.push({
fn: () => this.page.hover(`${selector} :text("${item}")`, { force: true }),
fn: () => this.page.hover(`${selector} :text-is("${item}")`, { force: true }),
name: `${item}:hover:force`,
})
steps.push({
fn: () => this.page.click(`${selector} :text("${item}")`, { trial: true }),
fn: () => this.page.click(`${selector} :text-is("${item}")`, { trial: true }),
name: `${item}:click:trial`,
})
steps.push({
fn: () => this.page.click(`${selector} :text("${item}")`, { force: true }),
fn: () => this.page.click(`${selector} :text-is("${item}")`, { force: true }),
name: `${item}:click:force`,
})
}

View File

@@ -1,5 +1,5 @@
import { describe, test, expect } from "./baseFixture"
import { clean, getMaybeProxiedPathname } from "../utils/helpers"
import { describe, test, expect } from "./baseFixture"
const routes = ["/", "/vscode", "/vscode/"]
@@ -103,7 +103,7 @@ describe("VS Code Routes with no workspace or folder", ["--disable-workspace-tru
// Closing the folder should stop the redirecting.
await codeServerPage.navigate("/?ew=true")
let url = new URL(codeServerPage.page.url())
const url = new URL(codeServerPage.page.url())
const pathname = getMaybeProxiedPathname(url)
expect(pathname).toBe("/")
expect(url.search).toBe("?ew=true")

View File

@@ -35,13 +35,19 @@ describe("Integrated Terminal", ["--disable-workspace-trust"], {}, () => {
const tmpFolderPath = await tmpdir(testName)
const tmpFile = path.join(tmpFolderPath, "test-file")
await fs.writeFile(tmpFile, "test")
const fileName = path.basename(tmpFile)
await codeServerPage.focusTerminal()
await codeServerPage.page.keyboard.type(`code-server ${tmpFile}`)
await codeServerPage.page.keyboard.press("Enter")
await codeServerPage.waitForTab(fileName)
await codeServerPage.waitForTab(path.basename(tmpFile))
const externalTmpFile = path.join(tmpFolderPath, "test-external-file")
await fs.writeFile(externalTmpFile, "foobar")
await codeServerPage.openFileExternally(externalTmpFile)
await codeServerPage.waitForTab(path.basename(externalTmpFile))
})
})

61
test/e2e/uploads.test.ts Normal file
View File

@@ -0,0 +1,61 @@
import { promises as fs } from "fs"
import * as path from "path"
import { clean } from "../utils/helpers"
import { describe, test, expect } from "./baseFixture"
describe("Uploads (enabled)", ["--disable-workspace-trust"], {}, () => {
const testName = "uploads-enabled"
test.beforeAll(async () => {
await clean(testName)
})
test("should see the 'Upload...' option", async ({ codeServerPage }) => {
// Setup
const workspaceDir = await codeServerPage.workspaceDir
const tmpDirPath = path.join(workspaceDir, "test-directory")
await fs.mkdir(tmpDirPath)
// Action
const fileInExplorer = await codeServerPage.page.waitForSelector('span:has-text("test-directory")')
await fileInExplorer.click({
button: "right",
})
expect(await codeServerPage.page.isVisible("text=Upload...")).toBe(true)
})
test("should see the 'Show Local' button on Open File", async ({ codeServerPage }) => {
// Action
await codeServerPage.navigateMenus(["File", "Open File..."])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(true)
})
})
describe("Uploads (disabled)", ["--disable-workspace-trust", "--disable-file-uploads"], {}, () => {
const testName = "uploads-disabled"
test.beforeAll(async () => {
await clean(testName)
})
test("should not see the 'Upload...' option", async ({ codeServerPage }) => {
// Setup
const workspaceDir = await codeServerPage.workspaceDir
const tmpDirPath = path.join(workspaceDir, "test-directory")
await fs.mkdir(tmpDirPath)
// Action
const fileInExplorer = await codeServerPage.page.waitForSelector('span:has-text("test-directory")')
await fileInExplorer.click({
button: "right",
})
expect(await codeServerPage.page.isVisible("text=Upload...")).toBe(false)
})
test("should not see the 'Show Local' button on Open File", async ({ codeServerPage }) => {
// Action
await codeServerPage.navigateMenus(["File", "Open File..."])
await codeServerPage.page.waitForSelector(".quick-input-widget")
expect(await codeServerPage.page.isVisible("text=Show Local")).toBe(false)
})
})

View File

@@ -17,7 +17,7 @@ describe("createApp", () => {
beforeAll(async () => {
mockLogger()
const testName = "unlink-socket"
const testName = "app"
await clean(testName)
tmpDirPath = await tmpdir(testName)
tmpFilePath = path.join(tmpDirPath, "unlink-socket-file")
@@ -92,7 +92,7 @@ describe("createApp", () => {
app.dispose()
}
expect(() => masterBall()).rejects.toThrow(`listen EACCES: permission denied 127.0.0.1:${port}`)
expect(() => masterBall()).rejects.toThrow("listen EACCES: permission denied")
})
it("should unlink a socket before listening on the socket", async () => {
@@ -103,7 +103,7 @@ describe("createApp", () => {
const app = await createApp(defaultArgs)
expect(unlinkSpy).toHaveBeenCalledTimes(1)
expect(unlinkSpy).toHaveBeenCalledWith(tmpFilePath)
app.dispose()
})

View File

@@ -1,14 +1,11 @@
import { Level, logger } from "@coder/logger"
import { promises as fs } from "fs"
import * as net from "net"
import * as os from "os"
import * as path from "path"
import {
UserProvidedArgs,
bindAddrFromArgs,
defaultConfigFile,
parse,
readSocketPath,
setDefaults,
shouldOpenInExistingInstance,
toCodeArgs,
@@ -20,7 +17,12 @@ import {
} from "../../../src/node/cli"
import { shouldSpawnCliProcess } from "../../../src/node/main"
import { generatePassword, paths } from "../../../src/node/util"
import { clean, useEnv, tmpdir } from "../../utils/helpers"
import {
EditorSessionManager,
EditorSessionManagerClient,
makeEditorSessionManagerServer,
} from "../../../src/node/vscodeSocket"
import { clean, useEnv, tmpdir, listenOn } from "../../utils/helpers"
// The parser should not set any defaults so the caller can determine what
// values the user actually set. These are only set after explicitly calling
@@ -34,6 +36,7 @@ const defaults = {
usingEnvHashedPassword: false,
"extensions-dir": path.join(paths.data, "extensions"),
"user-data-dir": paths.data,
"session-socket": path.join(paths.data, "code-server-ipc.sock"),
_: [],
}
@@ -44,6 +47,7 @@ describe("parser", () => {
delete process.env.CS_DISABLE_FILE_DOWNLOADS
delete process.env.CS_DISABLE_GETTING_STARTED_OVERRIDE
delete process.env.VSCODE_PROXY_URI
delete process.env.CS_DISABLE_PROXY
console.log = jest.fn()
})
@@ -100,6 +104,10 @@ describe("parser", () => {
"--disable-getting-started-override",
"--disable-proxy",
["--session-socket", "/tmp/override-code-server-ipc-socket"],
["--host", "0.0.0.0"],
"4",
"--",
@@ -118,6 +126,7 @@ describe("parser", () => {
},
"disable-file-downloads": true,
"disable-getting-started-override": true,
"disable-proxy": true,
enable: ["feature1", "feature2"],
help: true,
host: "0.0.0.0",
@@ -133,6 +142,7 @@ describe("parser", () => {
"welcome-text": "welcome to code",
version: true,
"bind-addr": "192.169.0.1:8080",
"session-socket": "/tmp/override-code-server-ipc-socket",
})
})
@@ -386,6 +396,30 @@ describe("parser", () => {
})
})
it("should use env var CS_DISABLE_PROXY", async () => {
process.env.CS_DISABLE_PROXY = "1"
const args = parse([])
expect(args).toEqual({})
const defaultArgs = await setDefaults(args)
expect(defaultArgs).toEqual({
...defaults,
"disable-proxy": true,
})
})
it("should use env var CS_DISABLE_PROXY set to true", async () => {
process.env.CS_DISABLE_PROXY = "true"
const args = parse([])
expect(args).toEqual({})
const defaultArgs = await setDefaults(args)
expect(defaultArgs).toEqual({
...defaults,
"disable-proxy": true,
})
})
it("should error if password passed in", () => {
expect(() => parse(["--password", "supersecret123"])).toThrowError(
"--password can only be set in the config file or passed in via $PASSWORD",
@@ -413,7 +447,7 @@ describe("parser", () => {
const defaultArgs = await setDefaults(args)
expect(defaultArgs).toEqual({
...defaults,
"proxy-domain": ["coder.com", "coder.org"],
"proxy-domain": ["{{port}}.coder.com", "{{port}}.coder.org"],
})
})
it("should allow '=,$/' in strings", async () => {
@@ -466,14 +500,14 @@ describe("parser", () => {
it("should set proxy uri", async () => {
await setDefaults(parse(["--proxy-domain", "coder.org"]))
expect(process.env.VSCODE_PROXY_URI).toEqual("{{port}}.coder.org")
expect(process.env.VSCODE_PROXY_URI).toEqual("//{{port}}.coder.org")
})
it("should set proxy uri to first domain", async () => {
await setDefaults(
parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "coder.com", "--proxy-domain", "coder.org"]),
)
expect(process.env.VSCODE_PROXY_URI).toEqual("{{port}}.coder.com")
expect(process.env.VSCODE_PROXY_URI).toEqual("//{{port}}.coder.com")
})
it("should not override existing proxy uri", async () => {
@@ -487,7 +521,7 @@ describe("parser", () => {
describe("cli", () => {
const testName = "cli"
const vscodeIpcPath = path.join(os.tmpdir(), "vscode-ipc")
let tmpDirPath: string
beforeAll(async () => {
await clean(testName)
@@ -495,68 +529,170 @@ describe("cli", () => {
beforeEach(async () => {
delete process.env.VSCODE_IPC_HOOK_CLI
await fs.rm(vscodeIpcPath, { force: true, recursive: true })
tmpDirPath = await tmpdir(testName)
})
it("should use existing if inside code-server", async () => {
process.env.VSCODE_IPC_HOOK_CLI = "test"
const args: UserProvidedArgs = {}
expect(await shouldOpenInExistingInstance(args)).toStrictEqual("test")
expect(await shouldOpenInExistingInstance(args, "")).toStrictEqual("test")
args.port = 8081
args._ = ["./file"]
expect(await shouldOpenInExistingInstance(args)).toStrictEqual("test")
expect(await shouldOpenInExistingInstance(args, "")).toStrictEqual("test")
})
it("should use existing if --reuse-window is set", async () => {
const sessionSocket = path.join(tmpDirPath, "session-socket")
const server = await makeEditorSessionManagerServer(sessionSocket, new EditorSessionManager())
const args: UserProvidedArgs = {}
args["reuse-window"] = true
await expect(shouldOpenInExistingInstance(args)).resolves.toStrictEqual(undefined)
await expect(shouldOpenInExistingInstance(args, sessionSocket)).rejects.toThrow()
await fs.writeFile(vscodeIpcPath, "test")
await expect(shouldOpenInExistingInstance(args)).resolves.toStrictEqual("test")
const socketPath = path.join(tmpDirPath, "socket")
const client = new EditorSessionManagerClient(sessionSocket)
await client.addSession({
entry: {
workspace: {
id: "aaa",
folders: [
{
uri: {
path: "/aaa",
},
},
],
},
socketPath,
},
})
const vscodeSockets = listenOn(socketPath)
await expect(shouldOpenInExistingInstance(args, sessionSocket)).resolves.toStrictEqual(socketPath)
args.port = 8081
await expect(shouldOpenInExistingInstance(args)).resolves.toStrictEqual("test")
await expect(shouldOpenInExistingInstance(args, sessionSocket)).resolves.toStrictEqual(socketPath)
server.close()
vscodeSockets.close()
})
it("should use existing if --new-window is set", async () => {
const sessionSocket = path.join(tmpDirPath, "session-socket")
const server = await makeEditorSessionManagerServer(sessionSocket, new EditorSessionManager())
const args: UserProvidedArgs = {}
args["new-window"] = true
expect(await shouldOpenInExistingInstance(args)).toStrictEqual(undefined)
await expect(shouldOpenInExistingInstance(args, sessionSocket)).rejects.toThrow()
await fs.writeFile(vscodeIpcPath, "test")
expect(await shouldOpenInExistingInstance(args)).toStrictEqual("test")
const socketPath = path.join(tmpDirPath, "socket")
const client = new EditorSessionManagerClient(sessionSocket)
await client.addSession({
entry: {
workspace: {
id: "aaa",
folders: [
{
uri: {
path: "/aaa",
},
},
],
},
socketPath,
},
})
const vscodeSockets = listenOn(socketPath)
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(socketPath)
args.port = 8081
expect(await shouldOpenInExistingInstance(args)).toStrictEqual("test")
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(socketPath)
server.close()
vscodeSockets.close()
})
it("should use existing if no unrelated flags are set, has positional, and socket is active", async () => {
const sessionSocket = path.join(tmpDirPath, "session-socket")
const server = await makeEditorSessionManagerServer(sessionSocket, new EditorSessionManager())
const args: UserProvidedArgs = {}
expect(await shouldOpenInExistingInstance(args)).toStrictEqual(undefined)
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(undefined)
args._ = ["./file"]
expect(await shouldOpenInExistingInstance(args)).toStrictEqual(undefined)
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(undefined)
const testDir = await tmpdir(testName)
const socketPath = path.join(testDir, "socket")
await fs.writeFile(vscodeIpcPath, socketPath)
expect(await shouldOpenInExistingInstance(args)).toStrictEqual(undefined)
await new Promise((resolve) => {
const server = net.createServer(() => {
// Close after getting the first connection.
server.close()
})
server.once("listening", () => resolve(server))
server.listen(socketPath)
const client = new EditorSessionManagerClient(sessionSocket)
const socketPath = path.join(tmpDirPath, "socket")
await client.addSession({
entry: {
workspace: {
id: "aaa",
folders: [
{
uri: {
path: "/aaa",
},
},
],
},
socketPath,
},
})
const vscodeSockets = listenOn(socketPath)
expect(await shouldOpenInExistingInstance(args)).toStrictEqual(socketPath)
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(socketPath)
args.port = 8081
expect(await shouldOpenInExistingInstance(args)).toStrictEqual(undefined)
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(undefined)
server.close()
vscodeSockets.close()
})
it("should prefer matching sessions for only the first path", async () => {
const sessionSocket = path.join(tmpDirPath, "session-socket")
const server = await makeEditorSessionManagerServer(sessionSocket, new EditorSessionManager())
const client = new EditorSessionManagerClient(sessionSocket)
await client.addSession({
entry: {
workspace: {
id: "aaa",
folders: [
{
uri: {
path: "/aaa",
},
},
],
},
socketPath: `${tmpDirPath}/vscode-ipc-aaa.sock`,
},
})
await client.addSession({
entry: {
workspace: {
id: "bbb",
folders: [
{
uri: {
path: "/bbb",
},
},
],
},
socketPath: `${tmpDirPath}/vscode-ipc-bbb.sock`,
},
})
listenOn(`${tmpDirPath}/vscode-ipc-aaa.sock`, `${tmpDirPath}/vscode-ipc-bbb.sock`)
const args: UserProvidedArgs = {}
args._ = ["/aaa/file", "/bbb/file"]
expect(await shouldOpenInExistingInstance(args, sessionSocket)).toStrictEqual(`${tmpDirPath}/vscode-ipc-aaa.sock`)
server.close()
})
})
@@ -653,6 +789,50 @@ describe("bindAddrFromArgs", () => {
expect(actual).toStrictEqual(expected)
})
it("should use process.env.CODE_SERVER_HOST if set", () => {
const [setValue, resetValue] = useEnv("CODE_SERVER_HOST")
setValue("coder")
const args: UserProvidedArgs = {}
const addr = {
host: "localhost",
port: 8080,
}
const actual = bindAddrFromArgs(addr, args)
const expected = {
host: "coder",
port: 8080,
}
expect(actual).toStrictEqual(expected)
resetValue()
})
it("should use the args.host over process.env.CODE_SERVER_HOST if both set", () => {
const [setValue, resetValue] = useEnv("CODE_SERVER_HOST")
setValue("coder")
const args: UserProvidedArgs = {
host: "123.123.123.123",
}
const addr = {
host: "localhost",
port: 8080,
}
const actual = bindAddrFromArgs(addr, args)
const expected = {
host: "123.123.123.123",
port: 8080,
}
expect(actual).toStrictEqual(expected)
resetValue()
})
it("should use process.env.PORT if set", () => {
const [setValue, resetValue] = useEnv("PORT")
setValue("8000")
@@ -729,44 +909,6 @@ cert: false`)
})
})
describe("readSocketPath", () => {
const fileContents = "readSocketPath file contents"
let tmpDirPath: string
let tmpFilePath: string
const testName = "readSocketPath"
beforeAll(async () => {
await clean(testName)
})
beforeEach(async () => {
tmpDirPath = await tmpdir(testName)
tmpFilePath = path.join(tmpDirPath, "readSocketPath.txt")
await fs.writeFile(tmpFilePath, fileContents)
})
it("should throw an error if it can't read the file", async () => {
// TODO@jsjoeio - implement
// Test it on a directory.... ESDIR
// TODO@jsjoeio - implement
expect(() => readSocketPath(tmpDirPath)).rejects.toThrow("EISDIR")
})
it("should return undefined if it can't read the file", async () => {
// TODO@jsjoeio - implement
const socketPath = await readSocketPath(path.join(tmpDirPath, "not-a-file"))
expect(socketPath).toBeUndefined()
})
it("should return the file contents", async () => {
const contents = await readSocketPath(tmpFilePath)
expect(contents).toBe(fileContents)
})
it("should return the same file contents for two different calls", async () => {
const contents1 = await readSocketPath(tmpFilePath)
const contents2 = await readSocketPath(tmpFilePath)
expect(contents2).toBe(contents1)
})
})
describe("toCodeArgs", () => {
const vscodeDefaults = {
...defaults,

View File

@@ -70,6 +70,7 @@ describe("http", () => {
origin: test.origin,
[key]: value,
},
args: {},
})
if (typeof test.expected === "string") {
expect(() => http.authenticateOrigin(req)).toThrow(test.expected)

View File

@@ -43,6 +43,7 @@ describe("plugin", () => {
usingEnvHashedPassword: false,
"extensions-dir": "",
"user-data-dir": "",
"session-socket": "",
}
next()
}

View File

@@ -1,4 +1,3 @@
import * as bodyParser from "body-parser"
import * as express from "express"
import * as http from "http"
import nodeFetch from "node-fetch"
@@ -45,6 +44,17 @@ describe("proxy", () => {
jest.clearAllMocks()
})
it("should return 403 Forbidden if proxy is disabled", async () => {
e.get("/wsup", (req, res) => {
res.json("you cannot see this")
})
codeServer = await integration.setup(["--auth=none", "--disable-proxy"], "")
const resp = await codeServer.fetch(proxyPath)
expect(resp.status).toBe(403)
const json = await resp.json()
expect(json).toEqual({ error: "Forbidden" })
})
it("should rewrite the base path", async () => {
e.get("/wsup", (req, res) => {
res.json("asher is the best")
@@ -99,7 +109,7 @@ describe("proxy", () => {
})
it("should allow post bodies", async () => {
e.use(bodyParser.json({ strict: false }))
e.use(express.json({ strict: false }))
e.post("/wsup", (req, res) => {
res.json(req.body)
})
@@ -116,7 +126,7 @@ describe("proxy", () => {
})
it("should handle bad requests", async () => {
e.use(bodyParser.json({ strict: false }))
e.use(express.json({ strict: false }))
e.post("/wsup", (req, res) => {
res.json(req.body)
})
@@ -143,7 +153,7 @@ describe("proxy", () => {
})
it("should handle errors", async () => {
e.use(bodyParser.json({ strict: false }))
e.use(express.json({ strict: false }))
e.post("/wsup", (req, res) => {
throw new Error("BROKEN")
})
@@ -198,6 +208,54 @@ describe("proxy", () => {
const json = await resp.json()
expect(json).toBe("ほげ")
})
it("should not double-encode query variables", async () => {
const spy = jest.fn()
e.get("*", (req, res) => {
spy([req.originalUrl, req.query])
res.end()
})
codeServer = await integration.setup(["--auth=none"], "")
for (const test of [
{
endpoint: proxyPath,
query: { foo: "bar with spaces" },
expected: "/wsup?foo=bar+with+spaces",
},
{
endpoint: absProxyPath,
query: { foo: "bar with spaces" },
expected: absProxyPath + "?foo=bar+with+spaces",
},
{
endpoint: proxyPath,
query: { foo: "with-&-ampersand" },
expected: "/wsup?foo=with-%26-ampersand",
},
{
endpoint: absProxyPath,
query: { foo: "with-&-ampersand" },
expected: absProxyPath + "?foo=with-%26-ampersand",
},
{
endpoint: absProxyPath,
query: { foo: "ほげ ほげ" },
expected: absProxyPath + "?foo=%E3%81%BB%E3%81%92+%E3%81%BB%E3%81%92",
},
{
endpoint: proxyPath,
query: { foo: "ほげ ほげ" },
expected: "/wsup?foo=%E3%81%BB%E3%81%92+%E3%81%BB%E3%81%92",
},
]) {
spy.mockClear()
const resp = await codeServer.fetch(test.endpoint, undefined, test.query)
expect(resp.status).toBe(200)
await resp.text()
expect(spy).toHaveBeenCalledTimes(1)
expect(spy).toHaveBeenCalledWith([test.expected, test.query])
}
})
})
// NOTE@jsjoeio

View File

@@ -1,6 +1,6 @@
import { mockLogger } from "../../../utils/helpers"
import * as httpserver from "../../../utils/httpserver"
import * as integration from "../../../utils/integration"
import { mockLogger } from "../../../utils/helpers"
describe("vscode", () => {
let codeServer: httpserver.HttpServer | undefined

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />

View File

@@ -1,10 +1,10 @@
import { logger } from "@coder/logger"
import * as http from "http"
import { AddressInfo } from "net"
import * as path from "path"
import { ensureAddress } from "../../../src/node/app"
import { SettingsProvider, UpdateSettings } from "../../../src/node/settings"
import { LatestResponse, UpdateProvider } from "../../../src/node/update"
import { clean, isAddressInfo, mockLogger, tmpdir } from "../../utils/helpers"
import { clean, mockLogger, tmpdir } from "../../utils/helpers"
describe("update", () => {
let version = "1.0.0"
@@ -79,7 +79,6 @@ describe("update", () => {
}
let _provider: UpdateProvider | undefined
let _address: string | AddressInfo | null
const provider = (): UpdateProvider => {
if (!_provider) {
throw new Error("Update provider has not been created")
@@ -87,6 +86,7 @@ describe("update", () => {
return _provider
}
let address = new URL("http://localhost")
beforeAll(async () => {
mockLogger()
@@ -105,12 +105,13 @@ describe("update", () => {
})
})
_address = server.address()
if (!isAddressInfo(_address)) {
throw new Error("unexpected address")
const addr = ensureAddress(server, "http")
if (typeof addr === "string") {
throw new Error("unable to run update tests with unix sockets")
}
_provider = new UpdateProvider(`http://${_address?.address}:${_address?.port}/latest`, _settings)
address = addr
address.pathname = "/latest"
_provider = new UpdateProvider(address.toString(), _settings)
})
afterAll(() => {
@@ -220,59 +221,51 @@ describe("update", () => {
})
it("should reject if response has status code 500", async () => {
if (isAddressInfo(_address)) {
const mockURL = `http://${_address.address}:${_address.port}/reject-status-code`
const provider = new UpdateProvider(mockURL, settings())
const update = await provider.getUpdate(true)
address.pathname = "/reject-status-code"
const provider = new UpdateProvider(address.toString(), settings())
const update = await provider.getUpdate(true)
expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error",
value: `${mockURL}: 500`,
})
}
expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error",
value: `${address.toString()}: 500`,
})
})
it("should reject if no location header provided", async () => {
if (isAddressInfo(_address)) {
const mockURL = `http://${_address.address}:${_address.port}/no-location-header`
const provider = new UpdateProvider(mockURL, settings())
const update = await provider.getUpdate(true)
address.pathname = "/no-location-header"
const provider = new UpdateProvider(address.toString(), settings())
const update = await provider.getUpdate(true)
expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error",
value: `received redirect with no location header`,
})
}
expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error",
value: `received redirect with no location header`,
})
})
it("should resolve the request with response.headers.location", async () => {
version = "4.1.1"
if (isAddressInfo(_address)) {
const mockURL = `http://${_address.address}:${_address.port}/with-location-header`
const provider = new UpdateProvider(mockURL, settings())
const update = await provider.getUpdate(true)
address.pathname = "/with-location-header"
const provider = new UpdateProvider(address.toString(), settings())
const update = await provider.getUpdate(true)
expect(logger.error).not.toHaveBeenCalled()
expect(update.version).toBe("4.1.1")
}
expect(logger.error).not.toHaveBeenCalled()
expect(update.version).toBe("4.1.1")
})
it("should reject if more than 10 redirects", async () => {
if (isAddressInfo(_address)) {
const mockURL = `http://${_address.address}:${_address.port}/redirect/11`
const provider = new UpdateProvider(mockURL, settings())
const update = await provider.getUpdate(true)
address.pathname = "/redirect/11"
const provider = new UpdateProvider(address.toString(), settings())
const update = await provider.getUpdate(true)
expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error",
value: `reached max redirects`,
})
}
expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error",
value: `reached max redirects`,
})
})
})

View File

@@ -491,22 +491,6 @@ describe("isDirectory", () => {
})
})
describe("humanPath", () => {
it("should return an empty string if no path provided", () => {
const mockHomedir = "/home/coder"
const actual = util.humanPath(mockHomedir)
const expected = ""
expect(actual).toBe(expected)
})
it("should replace the homedir with ~", () => {
const mockHomedir = "/home/coder"
const path = `${mockHomedir}/code-server`
const actual = util.humanPath(mockHomedir, path)
const expected = "~/code-server"
expect(actual).toBe(expected)
})
})
describe("isWsl", () => {
const testName = "wsl"

Some files were not shown because too many files have changed in this diff Show More