Skip to content

Commit

Permalink
Handle DOM storage being disabled (#197798)
Browse files Browse the repository at this point in the history
## Summary

This PR aims to improve the message shown to users when Kibana can't be
started due to disabled DOM storage (#121189).
The visuals here follow the same pattern as other fatal errors (see
#186609)

![image](https://github.com/user-attachments/assets/19832830-49e3-4789-9b83-0c1f14d7980d)

The `isDomStorageDisabled` check has to be done before `CoreService`
gets instantiated because of issues described below.

Closes: #121189

## The issue

What actually happens when you disable all cookies in a browser? Aside
from cookies, the browser disables the whole DOM storage -
`localStorage` and `sessionStorage`. Trying to access those will result
in an error.


`getSessionId`https://github.com/elastic/kibana/blob/3bc5e2db73799dc9c7831b6f9da4a52063cf112f/packages/core/analytics/core-analytics-browser-internal/src/get_session_id.ts#L17
and
`isSidenavCollapsed$`https://github.com/elastic/kibana/blob/3bc5e2db73799dc9c7831b6f9da4a52063cf112f/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx#L91

Both of those try to access either `localStorage` or `sessionStorage`
and both of those are triggered when you create an instance of
`CoreSystem` which gets instantiated in `kbn_bootstrap`
https://github.com/elastic/kibana/blob/6ef03697460aba0d3774c0c03fb7fb58c76c00bd/packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts#L42

Trying to access DOM storage in `CoreSystem` will cause it to throw an
error and this means that
`FatalErrorService`https://github.com/elastic/kibana/blob/6ef03697460aba0d3774c0c03fb7fb58c76c00bd/packages/core/fatal-errors/core-fatal-errors-browser-internal/src/fatal_errors_service.tsx#L32
will never instantiate and the
`failure`https://github.com/elastic/kibana/blob/6ef03697460aba0d3774c0c03fb7fb58c76c00bd/packages/core/rendering/core-rendering-server-internal/src/bootstrap/render_template.ts#L68
function which styles the errors and makes them visible will never
trigger and all the user will see is permament `Loading Kibana` spinner.

Wrapping `getSessionId` and `isSidenavCollapsed$` in `try-catch` block
allows `FatalErrorService` to work properly, which will catch an
unhandled exception (`Detected an unhandled Promise rejection.`) with an
error about `sessionStorage` being disabled, which gets thrown by
`LicensingPlugin` (and possibly in other places). This is not an actual
solution though - this behavior would happen again if another line of
code trying to access DOM storage gets added to `CoreSystem`.

I think it would be best to handle this directly in `kbn_bootstrap.ts`
by some check like the one below:
```javascript
const isDOMStorageDisabled = () => {
    try {
      const key = 'kbn_bootrasrap_domStorageEnabled';
      sessionStorage.setItem(key, 'true');
      sessionStorage.removeItem(key);
      return false;
    } catch (e) {
      return true;
    }
  };
const domStorageDisabled = isDOMStorageDisabled()
/* 
  ...some additonal logic
*/
```
This would then require some error displaying logic that doesn't use
`FatalErrorService`.

Looking for some feedback on how to properly solve this.
  • Loading branch information
kowalczyk-krzysztof authored Oct 30, 2024
1 parent 79e64b8 commit 3a8bd70
Showing 1 changed file with 70 additions and 0 deletions.
70 changes: 70 additions & 0 deletions packages/core/root/core-root-browser-internal/src/kbn_bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,76 @@ export async function __kbnBootstrap__() {
}),
]);

const isDomStorageDisabled = () => {
try {
const key = 'kbn_bootstrap_domStorageEnabled';
sessionStorage.setItem(key, 'true');
sessionStorage.removeItem(key);
localStorage.setItem(key, 'true');
localStorage.removeItem(key);
return false;
} catch (e) {
return true;
}
};

if (isDomStorageDisabled()) {
const defaultErrorTitle = `Couldn't load the page`;
const defaultErrorText = `Update your browser's settings to allow storage of cookies and site data, and reload the page.`;
const defaultErrorReload = 'Reload';

const errorTitle = i18nError
? defaultErrorTitle
: i18n.translate('core.ui.welcomeErrorCouldNotLoadPage', {
defaultMessage: defaultErrorTitle,
});

const errorText = i18nError
? defaultErrorText
: i18n.translate('core.ui.welcomeErrorDomStorageDisabled', {
defaultMessage: defaultErrorText,
});

const errorReload = i18nError
? defaultErrorReload
: i18n.translate('core.ui.welcomeErrorReloadButton', {
defaultMessage: defaultErrorReload,
});

const err = document.createElement('div');
err.style.textAlign = 'center';
err.style.padding = '120px 20px';
err.style.fontFamily = 'Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif';

const errorTitleEl = document.createElement('h1');
errorTitleEl.innerText = errorTitle;
errorTitleEl.style.margin = '20px';
errorTitleEl.style.color = '#1a1c21';

const errorTextEl = document.createElement('p');
errorTextEl.innerText = errorText;
errorTextEl.style.margin = '20px';
errorTextEl.style.color = '#343741';

const errorReloadEl = document.createElement('button');
errorReloadEl.innerText = errorReload;
errorReloadEl.onclick = function () {
location.reload();
};
errorReloadEl.setAttribute(
'style',
'cursor: pointer; padding-inline: 12px; block-size: 40px; font-size: 1rem; line-height: 1.4286rem; border-radius: 6px; min-inline-size: 112px; color: rgb(255, 255, 255); background-color: rgb(0, 119, 204); outline-color: rgb(0, 0, 0); border:none'
);

err.appendChild(errorTitleEl);
err.appendChild(errorTextEl);
err.appendChild(errorReloadEl);

document.body.innerHTML = '';
document.body.appendChild(err);
return;
}

const coreSystem = new CoreSystem({
injectedMetadata,
rootDomElement: document.body,
Expand Down

0 comments on commit 3a8bd70

Please sign in to comment.