-
-
Notifications
You must be signed in to change notification settings - Fork 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
fix: solve issues with basic auth username:password in URLs #11179
Conversation
🦋 Changeset detectedLatest commit: c21b675 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Just converted this to a draft as some more manual testing revealed I just moved the problem from one exception to another. Now exceptions get thrown when prefetching pages and possibly in other places. |
My first commit solved the issues with the Chromium bug, but now reveals deeper problems: This means that to support basic auth with credentials embedded in the URL, it's necessary to add some logic that wraps around export const native_fetch = (input, init) => {
if (input instanceof URL || typeof input === 'string') {
input = new URL(input);
if (input.username || input.password) {
input.username = ''
input.password = ''
}
}
return window.fetch(input, init)
} This brings up a couple of discussion points:
|
After some more testing, I have found an alternative fix. If we create an anchor element and set the // create initial history entry, so we can return here
try {
history.replaceState(
{ ...history.state, [INDEX_KEY]: current_history_index },
'',
location.href
);
} catch (error) {
const a = document.createElement('a');
a.href = '/';
const url = new URL(a.href);
if (!(url.username || url.password)) {
throw error;
}
location.href = location.href;
} In case of an exception caused by the presence of credentials in the current URL, this reloads the page, using This solution feels less elegant, but it seems to me the most reliable and the less disruptive |
Even better, we can directly use // create initial history entry, so we can return here
try {
history.replaceState(
{ ...history.state, [INDEX_KEY]: current_history_index },
'',
location.href
);
} catch (error) {
const url = new URL(document.URL);
if (!(url.username || url.password)) {
throw error;
}
location.href = location.href;
} |
Thanks for diagnosing this — I had no idea this Chromium bug existed. It turns out that we can solve the first part very simply, just by omitting the third argument to That does leave the
Option 1 is definitely easier and more comprehensive, if we're okay with forcibly reloading the page |
Option one is in practice equivalent to my proposed solution, simplified even more. I don't know why I decided to test for exceptions instead of directly comparing On one hand, the second option seems like the most proper and official way to solve the issue, on the other hand, it adds complexity and may cause a lot of confusion when fetch requests initiated in the load function work and fetch requests initiated inside event handlers (as an example) don't. |
Workaround for chromium bug #10522
? 'a Response object' | ||
: Array.isArray(data) | ||
? 'an array' | ||
: 'a non-plain object' |
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.
looks like you'll need to pnpm install
to get the latest version of Prettier before running pnpm format
(annoying, I know)
try { | ||
original_replace_state.call( | ||
history, | ||
{ | ||
...history.state, | ||
[HISTORY_INDEX]: current_history_index, | ||
[NAVIGATION_INDEX]: current_navigation_index | ||
}, | ||
'' | ||
); | ||
} catch (error) { | ||
// detect if the issue has been created by basic auth credentials in the current URL | ||
// https://github.com/sveltejs/kit/issues/10522 | ||
// if so, refresh the page without credentials | ||
const url = new URL(document.URL); | ||
if (!(url.username || url.password)) { | ||
throw error; | ||
} | ||
location.href = `${location.href}`; | ||
} |
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.
we should remove the try-catch, and add the URL check (document.URL !== location.href
should work, I think) at the top of start
try { | |
original_replace_state.call( | |
history, | |
{ | |
...history.state, | |
[HISTORY_INDEX]: current_history_index, | |
[NAVIGATION_INDEX]: current_navigation_index | |
}, | |
'' | |
); | |
} catch (error) { | |
// detect if the issue has been created by basic auth credentials in the current URL | |
// https://github.com/sveltejs/kit/issues/10522 | |
// if so, refresh the page without credentials | |
const url = new URL(document.URL); | |
if (!(url.username || url.password)) { | |
throw error; | |
} | |
location.href = `${location.href}`; | |
} | |
original_replace_state.call( | |
history, | |
{ | |
...history.state, | |
[HISTORY_INDEX]: current_history_index, | |
[NAVIGATION_INDEX]: current_navigation_index | |
}, | |
'' | |
); |
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.
Should we keep the (url.username || url.password)
check, just in case we are missing another reason why location.href
and document.URL
? I really can't think of any other scenario, but I have to admit my knowledge of the spec is limited. It would result in something like
if (document.URL !== location.href) {
const url = new URL(document.URL);
if (url.username || url.password) {
location.href = `${location.href}`;
}
}
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.
My inclination in these cases is to do the simpler thing that we're fairly sure is correct, rather than the more defensive thing. If it turns out there are other cases where document.URL
and location.href
differ, we'll find out about them soon enough, but if the defensive code is unnecessary we'll never find out — we'll just ship extra code to every SvelteKit app user for no good reason
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.
Makes sense
When using basic auth and embedding credentials in the URL (user:password@host) exceptions are raised in Chrome when calling
history.replaceState
withlocation.href
as the URL. This is better documented in #10522The issue is also reported in the Chromium bug tracker https://bugs.chromium.org/p/chromium/issues/detail?id=675884 but considering the lack of updates it seems like fixing this issue in the browser is not a priority.
I propose to fix this issue with the workaround suggested on the Chromium thread, by replacing
location.href
withlocation.pathname + location.search + location.hash
.