-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
Use spec-compliant URL parser to parse next
URL parameter.
#183521
Changes from all commits
7410e34
8fea2be
3e55db9
96772c3
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 |
---|---|---|
|
@@ -6,37 +6,35 @@ | |
* Side Public License, v 1. | ||
*/ | ||
|
||
import { parse as parseUrl } from 'url'; | ||
|
||
/** | ||
* Determine if url is outside of this Kibana install. | ||
*/ | ||
export function isInternalURL(url: string, basePath = '') { | ||
const { protocol, hostname, port, pathname } = parseUrl( | ||
url, | ||
false /* parseQueryString */, | ||
true /* slashesDenoteHost */ | ||
); | ||
|
||
// We should explicitly compare `protocol`, `port` and `hostname` to null to make sure these are not | ||
// detected in the URL at all. For example `hostname` can be empty string for Node URL parser, but | ||
// browser (because of various bwc reasons) processes URL differently (e.g. `///abc.com` - for browser | ||
// hostname is `abc.com`, but for Node hostname is an empty string i.e. everything between schema (`//`) | ||
// and the first slash that belongs to path. | ||
if (protocol !== null || hostname !== null || port !== null) { | ||
// We use the WHATWG parser TWICE with completely different dummy base URLs to ensure that the parsed URL always | ||
// inherits the origin of the base URL. This means that the specified URL isn't an absolute URL, or a scheme-relative | ||
// URL (//), or a scheme-relative URL with an empty host (///). Browsers may process such URLs unexpectedly due to | ||
// backward compatibility reasons (e.g., a browser may treat `///abc.com` as just `abc.com`). For more details, refer | ||
// to https://url.spec.whatwg.org/#concept-basic-url-parser and https://url.spec.whatwg.org/#url-representation. | ||
let normalizedURL: URL; | ||
try { | ||
for (const baseURL of ['http://example.org:5601', 'https://example.com']) { | ||
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. QQ: why do we need the one with the port there? isn't 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. Based on what we know today, it's redundant, agreed. The idea was to have two base URLs that differ in all three parts of the origin (protocol, host, and port) just to ensure there is no way to exploit any backward compatibility browser quirk that we're not aware of yet to make the browser treat a relative URL as an absolute one. |
||
normalizedURL = new URL(url, baseURL); | ||
if (normalizedURL.origin !== baseURL) { | ||
return false; | ||
} | ||
} | ||
} catch { | ||
return false; | ||
} | ||
|
||
// Now we need to normalize URL to make sure any relative path segments (`..`) cannot escape expected base path. | ||
if (basePath) { | ||
// Now we need to normalize URL to make sure any relative path segments (`..`) cannot escape expected | ||
// base path. We can rely on `URL` with a localhost to automatically "normalize" the URL. | ||
const normalizedPathname = new URL(String(pathname), 'https://localhost').pathname; | ||
|
||
return ( | ||
// Normalized pathname can add a leading slash, but we should also make sure it's included in | ||
// the original URL too | ||
pathname?.startsWith('/') && | ||
(normalizedPathname === basePath || normalizedPathname.startsWith(`${basePath}/`)) | ||
// the original URL too. We can safely use non-null assertion operator here since we know `normalizedURL` is | ||
// always defined, otherwise we would have returned `false` already. | ||
url.startsWith('/') && | ||
(normalizedURL!.pathname === basePath || normalizedURL!.pathname.startsWith(`${basePath}/`)) | ||
); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: hopefully, we can get rid of this trickery when/if this is accepted and implemented: whatwg/url#531