+
+ [[localize('ui.auth_store.ask')]]
+
+
+
[[localize('ui.auth_store.decline')]]
+
[[localize('ui.auth_store.confirm')]]
+
+
+ `;
+ }
+
+ static get properties() {
+ return {
+ hass: Object,
+ };
+ }
+
+ ready() {
+ super.ready();
+ this.classList.toggle('small', window.innerWidth < 600);
+ }
+
+ _save() {
+ enableWrite();
+ this._done();
+ }
+
+ _done() {
+ const card = this.shadowRoot.querySelector('paper-card');
+ card.style.transition = 'bottom .25s';
+ card.style.bottom = `-${card.offsetHeight + 8}px`;
+ setTimeout(() => this.parentNode.removeChild(this), 300);
+ }
+}
+
+customElements.define('ha-store-auth-card', HaStoreAuth);
diff --git a/src/entrypoints/core.js b/src/entrypoints/core.js
index b0739a3ddc..3361d98d12 100644
--- a/src/entrypoints/core.js
+++ b/src/entrypoints/core.js
@@ -5,9 +5,10 @@ import {
subscribeEntities,
} from 'home-assistant-js-websocket';
-import fetchToken from '../common/auth/fetch_token.js';
-import refreshToken_ from '../common/auth/refresh_token.js';
+import { redirectLogin, resolveCode, refreshToken } from '../common/auth/token.js';
+// import refreshToken_ from '../common/auth/refresh_token.js';
import parseQuery from '../common/util/parse_query.js';
+import { loadTokens } from '../common/auth/token_storage.js';
const init = window.createHassConnection = function (password, accessToken) {
const proto = window.location.protocol === 'https:' ? 'wss' : 'ws';
@@ -29,68 +30,11 @@ const init = window.createHassConnection = function (password, accessToken) {
});
};
-function clientId() {
- return `${location.protocol}//${location.host}/`;
-}
-
-function redirectLogin() {
- document.location.href = `/auth/authorize?response_type=code&client_id=${encodeURIComponent(clientId())}&redirect_uri=${encodeURIComponent(location.toString())}`;
- return new Promise();
-}
-
-let tokenCache;
-
-function storeTokens(tokens) {
- tokenCache = tokens;
- try {
- localStorage.tokens = JSON.stringify(tokens);
- } catch (err) {} // eslint-disable-line
-}
-
-function loadTokens() {
- if (tokenCache === undefined) {
- try {
- const tokens = localStorage.tokens;
- tokenCache = tokens ? JSON.parse(tokens) : null;
- } catch (err) {
- tokenCache = null;
- }
- }
- return tokenCache;
-}
-
-window.refreshToken = () => {
- const tokens = loadTokens();
-
- if (tokens === null) {
- return redirectLogin();
- }
-
- return refreshToken_(clientId(), tokens.refresh_token).then((accessTokenResp) => {
- const newTokens = Object.assign({}, tokens, accessTokenResp);
- storeTokens(newTokens);
- return newTokens;
- }, () => redirectLogin());
-};
-
-function resolveCode(code) {
- fetchToken(clientId(), code).then((tokens) => {
- storeTokens(tokens);
- // Refresh the page and have tokens in place.
- document.location.href = location.pathname;
- }, (err) => {
- // eslint-disable-next-line
- console.error('Resolve token failed', err);
- alert('Unable to fetch tokens');
- redirectLogin();
- });
-}
-
function main() {
if (location.search) {
const query = parseQuery(location.search.substr(1));
if (query.code) {
- resolveCode(query.code);
+ window.hassConnection = resolveCode(query.code).then(newTokens => init(null, newTokens));
return;
}
}
@@ -103,14 +47,14 @@ function main() {
if (Date.now() + 30000 > tokens.expires) {
// refresh access token if it will expire in 30 seconds to avoid invalid auth event
- window.hassConnection = window.refreshToken().then(newTokens => init(null, newTokens));
+ window.hassConnection = refreshToken().then(newTokens => init(null, newTokens));
return;
}
window.hassConnection = init(null, tokens).catch((err) => {
if (err !== ERR_INVALID_AUTH) throw err;
- return window.refreshToken().then(newTokens => init(null, newTokens));
+ return refreshToken().then(newTokens => init(null, newTokens));
});
}
diff --git a/src/layouts/app/auth-mixin.js b/src/layouts/app/auth-mixin.js
index eafa3e35ea..a4de9e7f8c 100644
--- a/src/layouts/app/auth-mixin.js
+++ b/src/layouts/app/auth-mixin.js
@@ -1,9 +1,20 @@
+import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
import { clearState } from '../../util/ha-pref-storage.js';
+import { askWrite } from '../../common/auth/token_storage.js';
export default superClass => class extends superClass {
ready() {
super.ready();
this.addEventListener('hass-logout', () => this._handleLogout());
+
+ afterNextRender(null, () => {
+ if (askWrite()) {
+ const el = document.createElement('ha-store-auth-card');
+ this.shadowRoot.appendChild(el);
+ this.provideHass(el);
+ import(/* webpackChunkName: "ha-store-auth-card" */ '../../dialogs/ha-store-auth-card.js');
+ }
+ });
}
hassConnected() {
diff --git a/src/layouts/app/connection-mixin.js b/src/layouts/app/connection-mixin.js
index 69dba37d6e..40851476a5 100644
--- a/src/layouts/app/connection-mixin.js
+++ b/src/layouts/app/connection-mixin.js
@@ -9,6 +9,7 @@ import translationMetadata from '../../../build-translations/translationMetadata
import LocalizeMixin from '../../mixins/localize-mixin.js';
import EventsMixin from '../../mixins/events-mixin.js';
+import { refreshToken } from '../../common/auth/token.js';
import { getState } from '../../util/ha-pref-storage.js';
import { getActiveTranslation } from '../../util/hass-translation.js';
import hassCallApi from '../../util/hass-call-api.js';
@@ -103,7 +104,7 @@ export default superClass =>
try {
// Refresh token if it will expire in 30 seconds
if (auth.accessToken && Date.now() + 30000 > auth.expires) {
- const accessToken = await window.refreshToken();
+ const accessToken = await refreshToken();
conn.options.accessToken = accessToken.access_token;
conn.options.expires = accessToken.expires;
}
@@ -112,7 +113,7 @@ export default superClass =>
if (!err || err.status_code !== 401 || !auth.accessToken) throw err;
// If we connect with access token and get 401, refresh token and try again
- const accessToken = await window.refreshToken();
+ const accessToken = await refreshToken();
conn.options.accessToken = accessToken.access_token;
conn.options.expires = accessToken.expires;
return await hassCallApi(host, auth, method, path, parameters);
@@ -159,7 +160,7 @@ export default superClass =>
while (this.unsubFuncs.length) {
this.unsubFuncs.pop()();
}
- const accessToken = await window.refreshToken();
+ const accessToken = await refreshToken();
this._handleNewConnProm(window.createHassConnection(null, accessToken));
};
diff --git a/src/layouts/app/hass-base-mixin.js b/src/layouts/app/hass-base-mixin.js
index 7572491b57..421d9c659a 100644
--- a/src/layouts/app/hass-base-mixin.js
+++ b/src/layouts/app/hass-base-mixin.js
@@ -18,6 +18,7 @@ export default superClass => class extends superClass {
provideHass(el) {
this.__provideHass.push(el);
+ el.hass = this.hass;
}
async _updateHass(obj) {
diff --git a/src/resources/ha-style.js b/src/resources/ha-style.js
index 3666d6960e..868e6b8981 100644
--- a/src/resources/ha-style.js
+++ b/src/resources/ha-style.js
@@ -191,6 +191,12 @@ documentContainer.innerHTML = `