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:
		| @ -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 (!payload) return Promise.reject(); | ||||||
|         if (!this.challenge) return Promise.reject(); |         if (!this.challenge) return Promise.reject(); | ||||||
|         // @ts-ignore |         // @ts-ignore | ||||||
| @ -153,12 +153,18 @@ export class FlowExecutor extends LitElement implements StageHost { | |||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 this.challenge = data; |                 this.challenge = data; | ||||||
|  |                 if (this.challenge.responseErrors) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 return true; | ||||||
|             }) |             }) | ||||||
|             .catch((e: Error | Response) => { |             .catch((e: Error | Response) => { | ||||||
|                 this.errorMessage(e); |                 this.errorMessage(e); | ||||||
|  |                 return false; | ||||||
|             }) |             }) | ||||||
|             .finally(() => { |             .finally(() => { | ||||||
|                 this.loading = false; |                 this.loading = false; | ||||||
|  |                 return false; | ||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ export interface StageHost { | |||||||
|     challenge?: unknown; |     challenge?: unknown; | ||||||
|     flowSlug: string; |     flowSlug: string; | ||||||
|     loading: boolean; |     loading: boolean; | ||||||
|     submit(payload: unknown): Promise<void>; |     submit(payload: unknown): Promise<boolean>; | ||||||
| } | } | ||||||
|  |  | ||||||
| export class BaseStage<Tin, Tout> extends LitElement { | export class BaseStage<Tin, Tout> extends LitElement { | ||||||
| @ -16,14 +16,19 @@ export class BaseStage<Tin, Tout> extends LitElement { | |||||||
|     @property({ attribute: false }) |     @property({ attribute: false }) | ||||||
|     challenge!: Tin; |     challenge!: Tin; | ||||||
|  |  | ||||||
|     submitForm(e: Event): void { |     async submitForm(e: Event): Promise<boolean> { | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|         const object: { |         const object: { | ||||||
|             [key: string]: unknown; |             [key: string]: unknown; | ||||||
|         } = {}; |         } = {}; | ||||||
|         const form = new FormData(this.shadowRoot?.querySelector("form") || undefined); |         const form = new FormData(this.shadowRoot?.querySelector("form") || undefined); | ||||||
|         form.forEach((value, key) => (object[key] = value)); |         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 { |     renderNonFieldErrors(errors: ErrorDetail[]): TemplateResult { | ||||||
| @ -41,4 +46,9 @@ export class BaseStage<Tin, Tout> extends LitElement { | |||||||
|             })} |             })} | ||||||
|         </div>`; |         </div>`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     cleanup(): void { | ||||||
|  |         // Method that can be overridden by stages | ||||||
|  |         return; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -41,6 +41,8 @@ export class IdentificationStage extends BaseStage< | |||||||
|     IdentificationChallenge, |     IdentificationChallenge, | ||||||
|     IdentificationChallengeResponseRequest |     IdentificationChallengeResponseRequest | ||||||
| > { | > { | ||||||
|  |     form?: HTMLFormElement; | ||||||
|  |  | ||||||
|     static get styles(): CSSResult[] { |     static get styles(): CSSResult[] { | ||||||
|         return [ |         return [ | ||||||
|             PFBase, |             PFBase, | ||||||
| @ -72,8 +74,8 @@ export class IdentificationStage extends BaseStage< | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     firstUpdated(): void { |     firstUpdated(): void { | ||||||
|         const wrapperForm = document.createElement("form"); |         this.form = document.createElement("form"); | ||||||
|         document.documentElement.appendChild(wrapperForm); |         document.documentElement.appendChild(this.form); | ||||||
|         // This is a workaround for the fact that we're in a shadow dom |         // This is a workaround for the fact that we're in a shadow dom | ||||||
|         // adapted from https://github.com/home-assistant/frontend/issues/3133 |         // adapted from https://github.com/home-assistant/frontend/issues/3133 | ||||||
|         const username = document.createElement("input"); |         const username = document.createElement("input"); | ||||||
| @ -91,7 +93,7 @@ export class IdentificationStage extends BaseStage< | |||||||
|                     input.focus(); |                     input.focus(); | ||||||
|                 }); |                 }); | ||||||
|         }; |         }; | ||||||
|         wrapperForm.appendChild(username); |         this.form.appendChild(username); | ||||||
|         const password = document.createElement("input"); |         const password = document.createElement("input"); | ||||||
|         password.setAttribute("type", "password"); |         password.setAttribute("type", "password"); | ||||||
|         password.setAttribute("name", "password"); |         password.setAttribute("name", "password"); | ||||||
| @ -115,7 +117,7 @@ export class IdentificationStage extends BaseStage< | |||||||
|                     input.focus(); |                     input.focus(); | ||||||
|                 }); |                 }); | ||||||
|         }; |         }; | ||||||
|         wrapperForm.appendChild(password); |         this.form.appendChild(password); | ||||||
|         const totp = document.createElement("input"); |         const totp = document.createElement("input"); | ||||||
|         totp.setAttribute("type", "text"); |         totp.setAttribute("type", "text"); | ||||||
|         totp.setAttribute("name", "code"); |         totp.setAttribute("name", "code"); | ||||||
| @ -139,7 +141,13 @@ export class IdentificationStage extends BaseStage< | |||||||
|                     input.focus(); |                     input.focus(); | ||||||
|                 }); |                 }); | ||||||
|         }; |         }; | ||||||
|         wrapperForm.appendChild(totp); |         this.form.appendChild(totp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     cleanup(): void { | ||||||
|  |         if (this.form) { | ||||||
|  |             document.documentElement.removeChild(this.form); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderSource(source: LoginSource): TemplateResult { |     renderSource(source: LoginSource): TemplateResult { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer