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)
|
- [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 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 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)
|
- [How do I disable file download?](#how-do-i-disable-file-download)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- 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
|
you can set the environment variable `CS_DISABLE_GETTING_STARTED_OVERRIDE=1` or
|
||||||
`CS_DISABLE_GETTING_STARTED_OVERRIDE=true`.
|
`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?
|
## How do I disable file download?
|
||||||
|
|
||||||
You can pass the flag `--disable-file-downloads` to `code-server`
|
You can pass the flag `--disable-file-downloads` to `code-server`
|
||||||
|
|
|
@ -51,6 +51,7 @@ export interface UserProvidedCodeArgs {
|
||||||
"disable-file-downloads"?: boolean
|
"disable-file-downloads"?: boolean
|
||||||
"disable-workspace-trust"?: boolean
|
"disable-workspace-trust"?: boolean
|
||||||
"disable-getting-started-override"?: boolean
|
"disable-getting-started-override"?: boolean
|
||||||
|
"disable-proxy"?: boolean
|
||||||
"session-socket"?: string
|
"session-socket"?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +179,10 @@ export const options: Options<Required<UserProvidedArgs>> = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
description: "Disable the coder/coder override in the Help: Getting Started page.",
|
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
|
// --enable can be used to enable experimental features. These features
|
||||||
// provide no guarantees.
|
// provide no guarantees.
|
||||||
enable: { type: "string[]" },
|
enable: { type: "string[]" },
|
||||||
|
@ -564,6 +569,10 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
|
||||||
args["disable-getting-started-override"] = true
|
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
|
const usingEnvHashedPassword = !!process.env.HASHED_PASSWORD
|
||||||
if (process.env.HASHED_PASSWORD) {
|
if (process.env.HASHED_PASSWORD) {
|
||||||
args["hashed-password"] = 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))
|
.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.
|
* Throw an error if not authorized. Call `next` if provided.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Request, Router } from "express"
|
import { Request, Router } from "express"
|
||||||
import { HttpCode, HttpError } from "../../common/http"
|
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 { proxy } from "../proxy"
|
||||||
import { Router as WsRouter } from "../wsRouter"
|
import { Router as WsRouter } from "../wsRouter"
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ router.all("*", async (req, res, next) => {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureProxyEnabled(req)
|
||||||
|
|
||||||
// Must be authenticated to use the proxy.
|
// Must be authenticated to use the proxy.
|
||||||
const isAuthenticated = await authenticated(req)
|
const isAuthenticated = await authenticated(req)
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
|
@ -100,6 +102,8 @@ wsRouter.ws("*", async (req, _, next) => {
|
||||||
if (!port) {
|
if (!port) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureProxyEnabled(req)
|
||||||
ensureOrigin(req)
|
ensureOrigin(req)
|
||||||
await ensureAuthenticated(req)
|
await ensureAuthenticated(req)
|
||||||
proxy.ws(req, req.ws, req.head, {
|
proxy.ws(req, req.ws, req.head, {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as path from "path"
|
||||||
import * as qs from "qs"
|
import * as qs from "qs"
|
||||||
import * as pluginapi from "../../../typings/pluginapi"
|
import * as pluginapi from "../../../typings/pluginapi"
|
||||||
import { HttpCode, HttpError } from "../../common/http"
|
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"
|
import { proxy as _proxy } from "../proxy"
|
||||||
|
|
||||||
const getProxyTarget = (req: Request, passthroughPath?: boolean): string => {
|
const getProxyTarget = (req: Request, passthroughPath?: boolean): string => {
|
||||||
|
@ -21,6 +21,8 @@ export async function proxy(
|
||||||
passthroughPath?: boolean
|
passthroughPath?: boolean
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
ensureProxyEnabled(req)
|
||||||
|
|
||||||
if (!(await authenticated(req))) {
|
if (!(await authenticated(req))) {
|
||||||
// If visiting the root (/:port only) redirect to the login page.
|
// If visiting the root (/:port only) redirect to the login page.
|
||||||
if (!req.params[0] || req.params[0] === "/") {
|
if (!req.params[0] || req.params[0] === "/") {
|
||||||
|
@ -50,6 +52,7 @@ export async function wsProxy(
|
||||||
passthroughPath?: boolean
|
passthroughPath?: boolean
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
ensureProxyEnabled(req)
|
||||||
ensureOrigin(req)
|
ensureOrigin(req)
|
||||||
await ensureAuthenticated(req)
|
await ensureAuthenticated(req)
|
||||||
_proxy.ws(req, req.ws, req.head, {
|
_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_FILE_DOWNLOADS
|
||||||
delete process.env.CS_DISABLE_GETTING_STARTED_OVERRIDE
|
delete process.env.CS_DISABLE_GETTING_STARTED_OVERRIDE
|
||||||
delete process.env.VSCODE_PROXY_URI
|
delete process.env.VSCODE_PROXY_URI
|
||||||
|
delete process.env.CS_DISABLE_PROXY
|
||||||
console.log = jest.fn()
|
console.log = jest.fn()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -103,6 +104,8 @@ describe("parser", () => {
|
||||||
|
|
||||||
"--disable-getting-started-override",
|
"--disable-getting-started-override",
|
||||||
|
|
||||||
|
"--disable-proxy",
|
||||||
|
|
||||||
["--session-socket", "/tmp/override-code-server-ipc-socket"],
|
["--session-socket", "/tmp/override-code-server-ipc-socket"],
|
||||||
|
|
||||||
["--host", "0.0.0.0"],
|
["--host", "0.0.0.0"],
|
||||||
|
@ -123,6 +126,7 @@ describe("parser", () => {
|
||||||
},
|
},
|
||||||
"disable-file-downloads": true,
|
"disable-file-downloads": true,
|
||||||
"disable-getting-started-override": true,
|
"disable-getting-started-override": true,
|
||||||
|
"disable-proxy": true,
|
||||||
enable: ["feature1", "feature2"],
|
enable: ["feature1", "feature2"],
|
||||||
help: true,
|
help: true,
|
||||||
host: "0.0.0.0",
|
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", () => {
|
it("should error if password passed in", () => {
|
||||||
expect(() => parse(["--password", "supersecret123"])).toThrowError(
|
expect(() => parse(["--password", "supersecret123"])).toThrowError(
|
||||||
"--password can only be set in the config file or passed in via $PASSWORD",
|
"--password can only be set in the config file or passed in via $PASSWORD",
|
||||||
|
|
|
@ -45,6 +45,17 @@ describe("proxy", () => {
|
||||||
jest.clearAllMocks()
|
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 () => {
|
it("should rewrite the base path", async () => {
|
||||||
e.get("/wsup", (req, res) => {
|
e.get("/wsup", (req, res) => {
|
||||||
res.json("asher is the best")
|
res.json("asher is the best")
|
||||||
|
|
Loading…
Reference in New Issue