Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/common/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
}
}

export enum CookieKeys {
Session = "code-server-session",
export function getCookieSessionName(suffix?: string): string {
return suffix ? `code-server-session-${suffix.replace(/[^a-zA-Z0-9\-]/g, "-")}` : "code-server-session";

Check failure on line 28 in src/common/http.ts

View workflow job for this annotation

GitHub Actions / Lint TypeScript files

Unnecessary escape character: \-
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooo right good catch on the alphanumeric

}
11 changes: 11 additions & 0 deletions src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface UserProvidedCodeArgs {
"disable-getting-started-override"?: boolean
"disable-proxy"?: boolean
"session-socket"?: string
"cookie-suffix"?: string
"link-protection-trusted-domains"?: string[]
// locale is used by both VS Code and code-server.
locale?: string
Expand Down Expand Up @@ -172,6 +173,12 @@ export const options: Options<Required<UserProvidedArgs>> = {
"session-socket": {
type: "string",
},
"cookie-suffix": {
type: "string",
description:
"Adds a suffix to the cookie. This can prevent a collision of cookies for subdomains, making them explixit. \n" +
"Without this flag, no suffix is used. This can also be set with CODE_SERVER_COOKIE_SUFFIX set to any string.",
},
"disable-file-downloads": {
type: "boolean",
description:
Expand Down Expand Up @@ -616,6 +623,10 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
usingEnvPassword = false
}

if (process.env.CODE_SERVER_COOKIE_SUFFIX) {
args["cookie-suffix"] = process.env.CODE_SERVER_COOKIE_SUFFIX
}

if (process.env.GITHUB_TOKEN) {
args["github-auth"] = process.env.GITHUB_TOKEN
}
Expand Down
5 changes: 3 additions & 2 deletions src/node/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as http from "http"
import * as net from "net"
import qs from "qs"
import { Disposable } from "../common/emitter"
import { CookieKeys, HttpCode, HttpError } from "../common/http"
import { HttpCode, HttpError } from "../common/http"
import { normalize } from "../common/util"
import { AuthType, DefaultedArgs } from "./cli"
import { version as codeServerVersion } from "./constants"
Expand Down Expand Up @@ -40,6 +40,7 @@ declare global {
heart: Heart
settings: SettingsProvider<CoderSettings>
updater: UpdateProvider
cookieSessionName: string
}
}
}
Expand Down Expand Up @@ -124,7 +125,7 @@ export const authenticated = async (req: express.Request): Promise<boolean> => {
const passwordMethod = getPasswordMethod(hashedPasswordFromArgs)
const isCookieValidArgs: IsCookieValidArgs = {
passwordMethod,
cookieKey: sanitizeString(req.cookies[CookieKeys.Session]),
cookieKey: sanitizeString(req.cookies[req.cookieSessionName]),
passwordFromArgs: req.args.password || "",
hashedPasswordFromArgs: req.args["hashed-password"],
}
Expand Down
5 changes: 4 additions & 1 deletion src/node/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { promises as fs } from "fs"
import * as path from "path"
import * as tls from "tls"
import { Disposable } from "../../common/emitter"
import { HttpCode, HttpError } from "../../common/http"
import { getCookieSessionName, HttpCode, HttpError } from "../../common/http"
import { plural } from "../../common/util"
import { App } from "../app"
import { AuthType, DefaultedArgs } from "../cli"
Expand Down Expand Up @@ -61,6 +61,8 @@ export const register = async (
const settings = new SettingsProvider<CoderSettings>(path.join(args["user-data-dir"], "coder.json"))
const updater = new UpdateProvider("https://api.github.com/repos/coder/code-server/releases/latest", settings)

const cookieSessionName = getCookieSessionName(args["cookie-suffix"])

const common: express.RequestHandler = (req, _, next) => {
// /healthz|/healthz/ needs to be excluded otherwise health checks will make
// it look like code-server is always in use.
Expand All @@ -75,6 +77,7 @@ export const register = async (
req.heart = heart
req.settings = settings
req.updater = updater
req.cookieSessionName = cookieSessionName

next()
}
Expand Down
3 changes: 1 addition & 2 deletions src/node/routes/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Router, Request } from "express"
import { promises as fs } from "fs"
import { RateLimiter as Limiter } from "limiter"
import * as path from "path"
import { CookieKeys } from "../../common/http"
import { rootPath } from "../constants"
import { authenticated, getCookieOptions, redirect, replaceTemplates } from "../http"
import i18n from "../i18n"
Expand Down Expand Up @@ -95,7 +94,7 @@ router.post<{}, string, { password?: string; base?: string } | undefined, { to?:
if (isPasswordValid) {
// The hash does not add any actual security but we do it for
// obfuscation purposes (and as a side effect it handles escaping).
res.cookie(CookieKeys.Session, hashedPassword, getCookieOptions(req))
res.cookie(req.cookieSessionName, hashedPassword, getCookieOptions(req))

const to = (typeof req.query.to === "string" && req.query.to) || "/"
return redirect(req, res, to, { to: undefined })
Expand Down
3 changes: 1 addition & 2 deletions src/node/routes/logout.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Router } from "express"
import { CookieKeys } from "../../common/http"
import { getCookieOptions, redirect } from "../http"
import { sanitizeString } from "../util"

export const router = Router()

router.get<{}, undefined, undefined, { base?: string; to?: string }>("/", async (req, res) => {
// Must use the *identical* properties used to set the cookie.
res.clearCookie(CookieKeys.Session, getCookieOptions(req))
res.clearCookie(req.cookieSessionName, getCookieOptions(req))

const to = sanitizeString(req.query.to) || "/"
return redirect(req, res, to, { to: undefined, base: undefined, href: undefined })
Expand Down
Loading