Better handle auth (#1637)

* Better handle auth

* Lint
This commit is contained in:
Paulus Schoutsen 2018-09-07 19:40:56 +02:00 committed by GitHub
parent ae8724d699
commit bbb50b1397
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 88 deletions

View File

@ -4,6 +4,7 @@ import {
subscribeConfig, subscribeConfig,
subscribeEntities, subscribeEntities,
subscribeServices, subscribeServices,
ERR_INVALID_AUTH,
} from 'home-assistant-js-websocket'; } from 'home-assistant-js-websocket';
import { loadTokens, saveTokens } from '../common/auth/token_storage.js'; 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'; import { subscribeUser } from '../data/ws-user.js';
const hassUrl = `${location.protocol}//${location.host}`; const hassUrl = `${location.protocol}//${location.host}`;
const isExternal = location.search.includes('external_auth=1');
if (location.search.includes('external_auth=1')) { const authProm = isExternal ?
window.hassAuth = import('../common/auth/external_auth.js') () => import('../common/auth/external_auth.js')
.then(mod => new mod.default(hassUrl)); .then(mod => new mod.default(hassUrl)) :
} else { () => getAuth({
window.hassAuth = getAuth({
hassUrl, hassUrl,
saveTokens, saveTokens,
loadTokens: () => Promise.resolve(loadTokens()), loadTokens: () => Promise.resolve(loadTokens()),
}); });
}
window.hassConnection = window.hassAuth.then((auth) => { 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')) { if (location.search.includes('auth_callback=1')) {
history.replaceState(null, null, location.pathname); history.replaceState(null, null, location.pathname);
} }
return createConnection({ auth });
}); 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 };
}
};
window.hassConnection = authProm().then(connProm);
// Start fetching some of the data that we will need. // Start fetching some of the data that we will need.
window.hassConnection.then((conn) => { window.hassConnection.then(({ conn }) => {
const noop = () => {}; const noop = () => {};
subscribeEntities(conn, noop); subscribeEntities(conn, noop);
subscribeConfig(conn, noop); subscribeConfig(conn, noop);

View File

@ -25,7 +25,16 @@ export default superClass =>
} }
async _handleConnProm() { 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({ this.hass = Object.assign({
auth, auth,

View File

@ -51,7 +51,7 @@ class HomeAssistant extends ext(PolymerElement, [
</template> </template>
<template is="dom-if" if="[[!showMain]]" restamp> <template is="dom-if" if="[[!showMain]]" restamp>
<ha-init-page></ha-init-page> <ha-init-page error='[[_error]]'></ha-init-page>
</template> </template>
`; `;
} }
@ -73,6 +73,10 @@ class HomeAssistant extends ext(PolymerElement, [
computed: 'computePanelUrl(routeData)', computed: 'computePanelUrl(routeData)',
observer: 'panelUrlChanged', observer: 'panelUrlChanged',
}, },
_error: {
type: Boolean,
value: false,
}
}; };
} }

View File

@ -1,12 +1,8 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js'; import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/paper-button/paper-button.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 '@polymer/paper-spinner/paper-spinner.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.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 LocalizeMixin from '../mixins/localize-mixin.js';
import EventsMixin from '../mixins/events-mixin.js'; import EventsMixin from '../mixins/events-mixin.js';
@ -26,82 +22,26 @@ class HaInitPage extends EventsMixin(LocalizeMixin(PolymerElement)) {
<div class="layout vertical center center-center fit"> <div class="layout vertical center center-center fit">
<img src="/static/icons/favicon-192x192.png" height="192"> <img src="/static/icons/favicon-192x192.png" height="192">
<paper-spinner active="true"></paper-spinner> <paper-spinner active="[[!error]]"></paper-spinner>
<template is='dom-if' if='[[error]]'>
Unable to connect to Home Assistant.
<paper-button on-click='_retry'>Retry</paper-button>
</template>
<template is='dom-if' if='[[!error]]'>
Loading data Loading data
</template>
</div> </div>
`; `;
} }
ready() { static get properties() {
super.ready(); return {
this.addEventListener('keydown', ev => this.passwordKeyDown(ev)); error: Boolean,
};
} }
computeLoadingMsg(isValidating) { _retry() {
return isValidating ? 'Connecting' : 'Loading data'; location.reload();
}
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;
}
}
);
} }
} }