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,
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) => {
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 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.
window.hassConnection.then((conn) => {
window.hassConnection.then(({ conn }) => {
const noop = () => {};
subscribeEntities(conn, noop);
subscribeConfig(conn, noop);

View File

@ -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,

View File

@ -51,7 +51,7 @@ class HomeAssistant extends ext(PolymerElement, [
</template>
<template is="dom-if" if="[[!showMain]]" restamp>
<ha-init-page></ha-init-page>
<ha-init-page error='[[_error]]'></ha-init-page>
</template>
`;
}
@ -73,6 +73,10 @@ class HomeAssistant extends ext(PolymerElement, [
computed: 'computePanelUrl(routeData)',
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/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)) {
<div class="layout vertical center center-center fit">
<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
</template>
</div>
`;
}
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();
}
}