-
Notifications
You must be signed in to change notification settings - Fork 6k
Proxy path fixes #4548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proxy path fixes #4548
Changes from all commits
9e2c7a7
59db017
fcfb87d
5adc97d
ba87ecc
5e046f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,14 +3,11 @@ 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, getCookieDomain, redirect, replaceTemplates } from "../http" | ||
import { getPasswordMethod, handlePasswordValidation, humanPath, sanitizeString, escapeHtml } from "../util" | ||
|
||
export enum Cookie { | ||
Key = "key", | ||
} | ||
|
||
// RateLimiter wraps around the limiter library for logins. | ||
// It allows 2 logins every minute plus 12 logins every hour. | ||
export class RateLimiter { | ||
|
@@ -62,7 +59,7 @@ router.get("/", async (req, res) => { | |
res.send(await getRoot(req)) | ||
}) | ||
|
||
router.post("/", async (req, res) => { | ||
router.post<{}, string, { password: string; base?: string }, { to?: string }>("/", async (req, res) => { | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const password = sanitizeString(req.body.password) | ||
const hashedPasswordFromArgs = req.args["hashed-password"] | ||
|
||
|
@@ -87,13 +84,13 @@ router.post("/", async (req, res) => { | |
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(Cookie.Key, hashedPassword, { | ||
res.cookie(CookieKeys.Session, hashedPassword, { | ||
domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]), | ||
// Browsers do not appear to allow cookies to be set relatively so we | ||
// need to get the root path from the browser since the proxy rewrites | ||
// it out of the path. Otherwise code-server instances hosted on | ||
// separate sub-paths will clobber each other. | ||
path: req.body.base ? path.posix.join(req.body.base, "..") : "/", | ||
path: req.body.base ? path.posix.join(req.body.base, "..", "/") : "/", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously this would assign the cookie to a resource path instead of a route path (e.g.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I feel like this is a fair tradeoff but I didn't use proxies with code-server before so can't fully speak to that UX. @code-asher what are your thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the advantage of putting the cookie at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue with omitting the trailing slash from the cookie is that logging out from any arbitrary path requires that we send that very same path in the logout request. Trailing slashes denote the depth and access of a cookie, and while the spec is pretty forgiving on cookies to omit it, we can’t identify what part of the URL is where authenticated “starts” without knowing if the user first authenticated from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah so a cookie set to the path There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need the depth either way right? For example assuming the base path is If we log out from Maybe there is some way we can get rid of needing to know what the current depth is? Hmmmm... 🤔 In previous versions of code-server the way we made this work was to pass the relative path to the root to the frontend (so in the three examples above it would be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe where we pass things like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To summarize, @code-asher you're saying this change would break current behavior? I think you and I will need to test and verify this ourselves. If it does lead to a breaking change, we should see what our options are like you said. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sort of. This is mostly academic right now since you cannot host code-server at a base path without a trailing slash anyway because of the way browsers resolve relative paths (i.e. There is one area we could potentially be breaking which is if existing users have a cookie at I do still think we should avoid an arbitrary restriction though. If one day we decide to support a slash-less base path it would be nice if the cookie logic already works. So it is really just more about leaving support as broad as possible as long as there are no downsides in doing so. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is just this login portion though. My comments about the logout stuff are still relevant though and I think need to be implemented (see other comment for repro). |
||
sameSite: "lax", | ||
}) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,21 @@ | ||
import { Router } from "express" | ||
import { CookieKeys } from "../../common/http" | ||
import { getCookieDomain, redirect } from "../http" | ||
import { Cookie } from "./login" | ||
|
||
import { sanitizeString } from "../util" | ||
|
||
export const router = Router() | ||
|
||
router.get("/", async (req, res) => { | ||
router.get<{}, undefined, undefined, { base?: string; to?: string }>("/", async (req, res) => { | ||
const path = sanitizeString(req.query.base) || "/" | ||
const to = sanitizeString(req.query.to) || "/" | ||
|
||
// Must use the *identical* properties used to set the cookie. | ||
res.clearCookie(Cookie.Key, { | ||
res.clearCookie(CookieKeys.Session, { | ||
domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]), | ||
path: req.query.base || "/", | ||
path: decodeURIComponent(path), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is encoded on the VS Code side: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this path has to be the same as the other cookie in order to overwrite it? So I think we will need to apply the same logic here we did in the login, namely the whole I suppose we will want There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing we'll need to test that to verify. If you're correct, I think one of us will have to implement that then @code-asher. Do you want to or do you want me to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think if you go to If you get to it before I do feel free but otherwise I will take it on! |
||
sameSite: "lax", | ||
}) | ||
|
||
const to = (typeof req.query.to === "string" && req.query.to) || "/" | ||
return redirect(req, res, to, { to: undefined, base: undefined }) | ||
}) |
Uh oh!
There was an error while loading. Please reload this page.