From bbb50b1397d26f85bb14d0e84878fd9cc476be17 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 7 Sep 2018 19:40:56 +0200 Subject: [PATCH] Better handle auth (#1637) * Better handle auth * Lint --- src/entrypoints/core.js | 42 ++++++++++---- src/layouts/app/connection-mixin.js | 11 +++- src/layouts/app/home-assistant.js | 6 +- src/layouts/ha-init-page.js | 88 +++++------------------------ 4 files changed, 59 insertions(+), 88 deletions(-) diff --git a/src/entrypoints/core.js b/src/entrypoints/core.js index adb0113d8d..08cf473952 100644 --- a/src/entrypoints/core.js +++ b/src/entrypoints/core.js @@ -4,6 +4,7 @@ import { subscribeConfig, subscribeEntities, subscribeServices, + ERR_INVALID_AUTH, } from 'home-assistant-js-websocket'; import { loadTokens, saveTokens } from '../common/auth/token_storage.js'; @@ -12,27 +13,44 @@ import { subscribeThemes } from '../data/ws-themes.js'; import { subscribeUser } from '../data/ws-user.js'; const hassUrl = `${location.protocol}//${location.host}`; +const isExternal = location.search.includes('external_auth=1'); -if (location.search.includes('external_auth=1')) { - window.hassAuth = import('../common/auth/external_auth.js') - .then(mod => new mod.default(hassUrl)); -} else { - window.hassAuth = getAuth({ +const authProm = isExternal ? + () => import('../common/auth/external_auth.js') + .then(mod => new mod.default(hassUrl)) : + () => getAuth({ hassUrl, saveTokens, loadTokens: () => Promise.resolve(loadTokens()), }); -} -window.hassConnection = window.hassAuth.then((auth) => { - if (location.search.includes('auth_callback=1')) { - history.replaceState(null, null, location.pathname); +const connProm = async (auth) => { + try { + const conn = await createConnection({ auth }); + + // Clear url if we have been able to establish a connection + if (location.search.includes('auth_callback=1')) { + history.replaceState(null, null, location.pathname); + } + + return { auth, conn }; + } catch (err) { + if (err !== ERR_INVALID_AUTH) { + throw err; + } + // We can get invalid auth if auth tokens were stored that are no longer valid + // Clear stored tokens. + if (!isExternal) saveTokens(null); + auth = await authProm(); + const conn = await createConnection({ auth }); + return { auth, conn }; } - return createConnection({ auth }); -}); +}; + +window.hassConnection = authProm().then(connProm); // Start fetching some of the data that we will need. -window.hassConnection.then((conn) => { +window.hassConnection.then(({ conn }) => { const noop = () => {}; subscribeEntities(conn, noop); subscribeConfig(conn, noop); diff --git a/src/layouts/app/connection-mixin.js b/src/layouts/app/connection-mixin.js index 78cebb5eb8..6cd8663b27 100644 --- a/src/layouts/app/connection-mixin.js +++ b/src/layouts/app/connection-mixin.js @@ -25,7 +25,16 @@ export default superClass => } async _handleConnProm() { - const [auth, conn] = await Promise.all([window.hassAuth, window.hassConnection]); + let auth; + let conn; + try { + const result = await window.hassConnection; + auth = result.auth; + conn = result.conn; + } catch (err) { + this._error = true; + return; + } this.hass = Object.assign({ auth, diff --git a/src/layouts/app/home-assistant.js b/src/layouts/app/home-assistant.js index 7bba5ad5b7..a52489fc1c 100644 --- a/src/layouts/app/home-assistant.js +++ b/src/layouts/app/home-assistant.js @@ -51,7 +51,7 @@ class HomeAssistant extends ext(PolymerElement, [ `; } @@ -73,6 +73,10 @@ class HomeAssistant extends ext(PolymerElement, [ computed: 'computePanelUrl(routeData)', observer: 'panelUrlChanged', }, + _error: { + type: Boolean, + value: false, + } }; } diff --git a/src/layouts/ha-init-page.js b/src/layouts/ha-init-page.js index fcb8d2a6a6..23725bee3d 100644 --- a/src/layouts/ha-init-page.js +++ b/src/layouts/ha-init-page.js @@ -1,12 +1,8 @@ import '@polymer/iron-flex-layout/iron-flex-layout-classes.js'; import '@polymer/paper-button/paper-button.js'; -import '@polymer/paper-checkbox/paper-checkbox.js'; -import '@polymer/paper-input/paper-input.js'; import '@polymer/paper-spinner/paper-spinner.js'; import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js'; -import { ERR_CANNOT_CONNECT, ERR_INVALID_AUTH } from 'home-assistant-js-websocket'; - import LocalizeMixin from '../mixins/localize-mixin.js'; import EventsMixin from '../mixins/events-mixin.js'; @@ -26,82 +22,26 @@ class HaInitPage extends EventsMixin(LocalizeMixin(PolymerElement)) {
- - Loading data + + +
`; } - ready() { - super.ready(); - this.addEventListener('keydown', ev => this.passwordKeyDown(ev)); + static get properties() { + return { + error: Boolean, + }; } - computeLoadingMsg(isValidating) { - return isValidating ? 'Connecting' : 'Loading data'; - } - - computeShowSpinner(forceShowLoading, isValidating) { - return forceShowLoading || isValidating; - } - - isValidatingChanged(newVal) { - if (!newVal) { - setTimeout(() => { - if (this.$.passwordInput.inputElement.inputElement) { - this.$.passwordInput.inputElement.inputElement.focus(); - } - }, 10); - } - } - - passwordKeyDown(ev) { - // validate on enter - if (ev.keyCode === 13) { - this.validatePassword(); - ev.preventDefault(); - // clear error after we start typing again - } else if (this.errorMessage) { - this.errorMessage = ''; - } - } - - validatePassword() { - var auth = this.password; - this.$.hideKeyboardOnFocus.focus(); - const connProm = window.createHassConnection(auth); - this.fire('try-connection', { connProm }); - - if (this.$.rememberLogin.checked) { - connProm.then(function () { - localStorage.authToken = auth; - }); - } - } - - handleConnectionPromiseChanged(newVal) { - if (!newVal) return; - - var el = this; - this.isValidating = true; - - this.connectionPromise.then( - function () { - el.isValidating = false; - el.password = ''; - }, - function (errCode) { - el.isValidating = false; - - if (errCode === ERR_CANNOT_CONNECT) { - el.errorMessage = 'Unable to connect'; - } else if (errCode === ERR_INVALID_AUTH) { - el.errorMessage = 'Invalid password'; - } else { - el.errorMessage = 'Unknown error: ' + errCode; - } - } - ); + _retry() { + location.reload(); } }