web/flows: fix helper form not being removed from identification stage (improve password manager compatibility)

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-01-02 20:03:34 +01:00
parent ab17a12184
commit e72097292c
3 changed files with 33 additions and 9 deletions

View file

@ -131,7 +131,7 @@ export class FlowExecutor extends LitElement implements StageHost {
});
}
submit(payload?: FlowChallengeResponseRequest): Promise<void> {
submit(payload?: FlowChallengeResponseRequest): Promise<boolean> {
if (!payload) return Promise.reject();
if (!this.challenge) return Promise.reject();
// @ts-ignore
@ -153,12 +153,18 @@ export class FlowExecutor extends LitElement implements StageHost {
);
}
this.challenge = data;
if (this.challenge.responseErrors) {
return false;
}
return true;
})
.catch((e: Error | Response) => {
this.errorMessage(e);
return false;
})
.finally(() => {
this.loading = false;
return false;
});
}

View file

@ -7,7 +7,7 @@ export interface StageHost {
challenge?: unknown;
flowSlug: string;
loading: boolean;
submit(payload: unknown): Promise<void>;
submit(payload: unknown): Promise<boolean>;
}
export class BaseStage<Tin, Tout> extends LitElement {
@ -16,14 +16,19 @@ export class BaseStage<Tin, Tout> extends LitElement {
@property({ attribute: false })
challenge!: Tin;
submitForm(e: Event): void {
async submitForm(e: Event): Promise<boolean> {
e.preventDefault();
const object: {
[key: string]: unknown;
} = {};
const form = new FormData(this.shadowRoot?.querySelector("form") || undefined);
form.forEach((value, key) => (object[key] = value));
this.host?.submit(object as unknown as Tout);
return this.host?.submit(object as unknown as Tout).then((successful) => {
if (successful) {
this.cleanup();
}
return successful;
});
}
renderNonFieldErrors(errors: ErrorDetail[]): TemplateResult {
@ -41,4 +46,9 @@ export class BaseStage<Tin, Tout> extends LitElement {
})}
</div>`;
}
cleanup(): void {
// Method that can be overridden by stages
return;
}
}

View file

@ -41,6 +41,8 @@ export class IdentificationStage extends BaseStage<
IdentificationChallenge,
IdentificationChallengeResponseRequest
> {
form?: HTMLFormElement;
static get styles(): CSSResult[] {
return [
PFBase,
@ -72,8 +74,8 @@ export class IdentificationStage extends BaseStage<
}
firstUpdated(): void {
const wrapperForm = document.createElement("form");
document.documentElement.appendChild(wrapperForm);
this.form = document.createElement("form");
document.documentElement.appendChild(this.form);
// This is a workaround for the fact that we're in a shadow dom
// adapted from https://github.com/home-assistant/frontend/issues/3133
const username = document.createElement("input");
@ -91,7 +93,7 @@ export class IdentificationStage extends BaseStage<
input.focus();
});
};
wrapperForm.appendChild(username);
this.form.appendChild(username);
const password = document.createElement("input");
password.setAttribute("type", "password");
password.setAttribute("name", "password");
@ -115,7 +117,7 @@ export class IdentificationStage extends BaseStage<
input.focus();
});
};
wrapperForm.appendChild(password);
this.form.appendChild(password);
const totp = document.createElement("input");
totp.setAttribute("type", "text");
totp.setAttribute("name", "code");
@ -139,7 +141,13 @@ export class IdentificationStage extends BaseStage<
input.focus();
});
};
wrapperForm.appendChild(totp);
this.form.appendChild(totp);
}
cleanup(): void {
if (this.form) {
document.documentElement.removeChild(this.form);
}
}
renderSource(source: LoginSource): TemplateResult {