mirror of https://github.com/coder/code-server.git
Add --disable-proxy option (#6349)
This commit is contained in:
parent
daac46b3cf
commit
74da5167a2
14
docs/FAQ.md
14
docs/FAQ.md
|
@ -34,6 +34,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 -->
|
||||
|
@ -453,6 +454,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`
|
||||
|
|
|
@ -51,6 +51,7 @@ export interface UserProvidedCodeArgs {
|
|||
"disable-file-downloads"?: boolean
|
||||
"disable-workspace-trust"?: boolean
|
||||
"disable-getting-started-override"?: boolean
|
||||
"disable-proxy"?: boolean
|
||||
"session-socket"?: string
|
||||
}
|
||||
|
||||
|
@ -178,6 +179,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[]" },
|
||||
|
@ -564,6 +569,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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Request, Router } from "express"
|
||||
import { HttpCode, HttpError } from "../../common/http"
|
||||
import { getHost, 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"
|
||||
|
||||
|
@ -59,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) {
|
||||
|
@ -100,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, {
|
||||
|
|
|
@ -3,7 +3,7 @@ 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 => {
|
||||
|
@ -21,6 +21,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] === "/") {
|
||||
|
@ -50,6 +52,7 @@ export async function wsProxy(
|
|||
passthroughPath?: boolean
|
||||
},
|
||||
): Promise<void> {
|
||||
ensureProxyEnabled(req)
|
||||
ensureOrigin(req)
|
||||
await ensureAuthenticated(req)
|
||||
_proxy.ws(req, req.ws, req.head, {
|
||||
|
|
|
@ -47,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()
|
||||
})
|
||||
|
||||
|
@ -103,6 +104,8 @@ describe("parser", () => {
|
|||
|
||||
"--disable-getting-started-override",
|
||||
|
||||
"--disable-proxy",
|
||||
|
||||
["--session-socket", "/tmp/override-code-server-ipc-socket"],
|
||||
|
||||
["--host", "0.0.0.0"],
|
||||
|
@ -123,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",
|
||||
|
@ -392,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",
|
||||
|
|
|
@ -45,6 +45,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")
|
||||
|
|
Loading…
Reference in New Issue