ha-frontend/src/auth/ha-auth-flow.html

144 lines
3.9 KiB
HTML

<link rel='import' href='../../bower_components/polymer/polymer-element.html'>
<link rel="import" href='../../bower_components/paper-button/paper-button.html'>
<link rel='import' href='../components/ha-form.html'>
<link rel='import' href='../util/hass-mixins.html'>
<dom-module id='ha-auth-flow'>
<template>
<template is='dom-if' if='[[_equals(_state, "loading")]]'>
Please wait
</template>
<template is='dom-if' if='[[_equals(_state, "error")]]'>
Something went wrong
</template>
<template is='dom-if' if='[[_equals(_state, "step")]]'>
<template is='dom-if' if='[[_equals(_step.type, "abort")]]'>
Aborted
</template>
<template is='dom-if' if='[[_equals(_step.type, "create_entry")]]'>
Success!
</template>
<template is='dom-if' if='[[_equals(_step.type, "form")]]'>
<ha-form
data='{{_stepData}}'
schema='[[_step.data_schema]]'
error='[[_step.errors]]'
></ha-form>
</template>
<paper-button on-click='_handleSubmit'>[[_computeSubmitCaption(_step.type)]]</paper-button>
</template>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaAuthFlow extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'ha-auth-flow'; }
static get properties() {
return {
authProvider: Object,
clientId: String,
clientSecret: String,
redirectUri: String,
oauth2State: String,
_state: {
type: String,
value: 'loading'
},
_stepData: {
type: Object,
value: () => ({}),
},
_step: Object,
};
}
connectedCallback() {
super.connectedCallback();
fetch('/auth/login_flow', {
method: 'POST',
headers: {
Authorization: `Basic ${btoa(`${this.clientId}:${this.clientSecret}`)}`
},
body: JSON.stringify({
handler: [this.authProvider.type, this.authProvider.id],
redirect_uri: this.redirectUri,
})
}).then((response) => {
if (!response.ok) throw new Error();
return response.json();
}).then(step => this.setProperties({
_step: step,
_state: 'step',
})).catch((err) => {
// eslint-disable-next-line
console.error('Error starting auth flow', err);
this._state = 'error';
});
}
_equals(a, b) {
return a === b;
}
_computeSubmitCaption(stepType) {
return stepType === 'form' ? 'Submit' : 'Start over';
}
_handleSubmit() {
if (this._step.type !== 'form') {
this.fire('reset');
return;
}
this._state = 'loading';
fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: 'POST',
headers: {
Authorization: `Basic ${btoa(`${this.clientId}:${this.clientSecret}`)}`
},
body: JSON.stringify(this._stepData)
}).then((response) => {
if (!response.ok) throw new Error();
return response.json();
}).then((newStep) => {
if (newStep.type === 'create_entry') {
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
let url = this.redirectUri;
if (!url.includes('?')) {
url += '?';
} else if (!url.endsWith('&')) {
url += '&';
}
url += `code=${encodeURIComponent(newStep.result)}`;
if (this.oauth2State) {
url += `&state=${encodeURIComponent(this.oauth2State)}`;
}
document.location = url;
return;
}
const props = {
_step: newStep,
_state: 'step',
};
if (newStep.step_id !== this._step.step_id) {
props._stepData = {};
}
this.setProperties(props);
}).catch((err) => {
// eslint-disable-next-line
console.error('Error loading auth providers', err);
this._state = 'error-loading';
});
}
}
customElements.define(HaAuthFlow.is, HaAuthFlow);
</script>