Only handle exact domain matches
This simplifies the logic a bit.
This commit is contained in:
parent
3a98d856a5
commit
2086648c87
@ -6,8 +6,15 @@ import { HttpProvider, HttpProviderOptions, HttpProxyProvider, HttpResponse, Rou
|
|||||||
* Proxy HTTP provider.
|
* Proxy HTTP provider.
|
||||||
*/
|
*/
|
||||||
export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider {
|
export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider {
|
||||||
|
/**
|
||||||
|
* Proxy domains are stored here without the leading `*.`
|
||||||
|
*/
|
||||||
public readonly proxyDomains: string[]
|
public readonly proxyDomains: string[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domains can be provided in the form `coder.com` or `*.coder.com`. Either
|
||||||
|
* way, `<number>.coder.com` will be proxied to `number`.
|
||||||
|
*/
|
||||||
public constructor(options: HttpProviderOptions, proxyDomains: string[] = []) {
|
public constructor(options: HttpProviderOptions, proxyDomains: string[] = []) {
|
||||||
super(options)
|
super(options)
|
||||||
this.proxyDomains = proxyDomains.map((d) => d.replace(/^\*\./, "")).filter((d, i, arr) => arr.indexOf(d) === i)
|
this.proxyDomains = proxyDomains.map((d) => d.replace(/^\*\./, "")).filter((d, i, arr) => arr.indexOf(d) === i)
|
||||||
@ -29,12 +36,14 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
|
|||||||
throw new HttpError("Not found", HttpCode.NotFound)
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getProxyDomain(host?: string): string | undefined {
|
public getCookieDomain(host: string): string {
|
||||||
if (!host || !this.proxyDomains) {
|
let current: string | undefined
|
||||||
return undefined
|
this.proxyDomains.forEach((domain) => {
|
||||||
}
|
if (host.endsWith(domain) && (!current || domain.length < current.length)) {
|
||||||
|
current = domain
|
||||||
return this.proxyDomains.find((d) => host.endsWith(d))
|
}
|
||||||
|
})
|
||||||
|
return current || host
|
||||||
}
|
}
|
||||||
|
|
||||||
public maybeProxy(request: http.IncomingMessage): HttpResponse | undefined {
|
public maybeProxy(request: http.IncomingMessage): HttpResponse | undefined {
|
||||||
@ -44,23 +53,21 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At minimum there needs to be sub.domain.tld.
|
||||||
const host = request.headers.host
|
const host = request.headers.host
|
||||||
const proxyDomain = this.getProxyDomain(host)
|
const parts = host && host.split(".")
|
||||||
if (!host || !proxyDomain) {
|
if (!parts || parts.length < 3) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const proxyDomainLength = proxyDomain.split(".").length
|
// There must be an exact match.
|
||||||
const portStr = host
|
const port = parts.shift()
|
||||||
.split(".")
|
const proxyDomain = parts.join(".")
|
||||||
.slice(0, -proxyDomainLength)
|
if (!port || !this.proxyDomains.includes(proxyDomain)) {
|
||||||
.pop()
|
|
||||||
|
|
||||||
if (!portStr) {
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.proxy(portStr)
|
return this.proxy(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
private proxy(portStr: string): HttpResponse {
|
private proxy(portStr: string): HttpResponse {
|
||||||
|
@ -397,27 +397,20 @@ export interface HttpProvider3<A1, A2, A3, T> {
|
|||||||
export interface HttpProxyProvider {
|
export interface HttpProxyProvider {
|
||||||
/**
|
/**
|
||||||
* Return a response if the request should be proxied. Anything that ends in a
|
* Return a response if the request should be proxied. Anything that ends in a
|
||||||
* proxy domain and has a subdomain should be proxied. The port is found in
|
* proxy domain and has a *single* subdomain should be proxied. Anything else
|
||||||
* the top-most subdomain.
|
* should return `undefined` and will be handled as normal.
|
||||||
*
|
*
|
||||||
* For example, if the proxy domain is `coder.com` then `8080.coder.com` and
|
* For example if `coder.com` is specified `8080.coder.com` will be proxied
|
||||||
* `test.8080.coder.com` will both proxy to `8080` but `8080.test.coder.com`
|
* but `8080.test.coder.com` and `test.8080.coder.com` will not.
|
||||||
* will have an error because `test` isn't a port. If the proxy domain was
|
|
||||||
* `test.coder.com` then it would work.
|
|
||||||
*/
|
*/
|
||||||
maybeProxy(request: http.IncomingMessage): HttpResponse | undefined
|
maybeProxy(request: http.IncomingMessage): HttpResponse | undefined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the matching proxy domain based on the provided host.
|
* Get the domain that should be used for setting a cookie. This will allow
|
||||||
|
* the user to authenticate only once. This will return the highest level
|
||||||
|
* domain (e.g. `coder.com` over `test.coder.com` if both are specified).
|
||||||
*/
|
*/
|
||||||
getProxyDomain(host: string): string | undefined
|
getCookieDomain(host: string): string | undefined
|
||||||
|
|
||||||
/**
|
|
||||||
* Domains can be provided in the form `coder.com` or `*.coder.com`. Either
|
|
||||||
* way, `<number>.coder.com` will be proxied to `number`. The domains are
|
|
||||||
* stored here without the `*.`.
|
|
||||||
*/
|
|
||||||
readonly proxyDomains: string[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -560,12 +553,8 @@ export class HttpServer {
|
|||||||
"Set-Cookie": [
|
"Set-Cookie": [
|
||||||
`${payload.cookie.key}=${payload.cookie.value}`,
|
`${payload.cookie.key}=${payload.cookie.value}`,
|
||||||
`Path=${normalize(payload.cookie.path || "/", true)}`,
|
`Path=${normalize(payload.cookie.path || "/", true)}`,
|
||||||
// Set the cookie against the host so it can be used in
|
|
||||||
// subdomains. Use a matching proxy domain if possible so
|
|
||||||
// requests to any of those subdomains will already be
|
|
||||||
// authenticated.
|
|
||||||
request.headers.host
|
request.headers.host
|
||||||
? `Domain=${(this.proxy && this.proxy.getProxyDomain(request.headers.host)) || request.headers.host}`
|
? `Domain=${(this.proxy && this.proxy.getCookieDomain(request.headers.host)) || request.headers.host}`
|
||||||
: undefined,
|
: undefined,
|
||||||
// "HttpOnly",
|
// "HttpOnly",
|
||||||
"SameSite=strict",
|
"SameSite=strict",
|
||||||
|
Reference in New Issue
Block a user