diff --git a/spec/unit/interactive-auth.spec.ts b/spec/unit/interactive-auth.spec.ts index ea11fc4c900..bd3c8e653bf 100644 --- a/spec/unit/interactive-auth.spec.ts +++ b/spec/unit/interactive-auth.spec.ts @@ -375,7 +375,7 @@ describe("InteractiveAuth", () => { await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(new Error("No appropriate authentication flow found")); }); - it("should handle unexpected error types without data propery set", async () => { + it("should handle unexpected error types without data property set", async () => { const doRequest = jest.fn(); const stateUpdated = jest.fn(); const requestEmailToken = jest.fn(); @@ -559,4 +559,40 @@ describe("InteractiveAuth", () => { ia.chooseStage(); expect(ia.getChosenFlow()?.stages).toEqual([AuthType.Password]); }); + + it("should fire stateUpdated callback if with error when encountered", async () => { + const doRequest = jest.fn(); + const stateUpdated = jest.fn(); + + const ia = new InteractiveAuth({ + matrixClient: getFakeClient(), + doRequest: doRequest, + stateUpdated: stateUpdated, + requestEmailToken: jest.fn(), + authData: { + session: "sessionId", + flows: [{ stages: [AuthType.Password] }], + params: { + [AuthType.Password]: { param: "aa" }, + }, + }, + }); + + // first we expect a call here + stateUpdated.mockImplementation((stage) => { + expect(stage).toEqual(AuthType.Password); + ia.submitAuthDict({ + type: AuthType.Password, + }); + }); + + // .. which should trigger a call here + doRequest.mockRejectedValue(new MatrixError({ errcode: "M_UNKNOWN", error: "This is an error" })); + + await Promise.allSettled([ia.attemptAuth()]); + expect(stateUpdated).toHaveBeenCalledWith("m.login.password", { + errcode: "M_UNKNOWN", + error: "This is an error", + }); + }); }); diff --git a/src/interactive-auth.ts b/src/interactive-auth.ts index 0a75ab5232f..3617ce1765f 100644 --- a/src/interactive-auth.ts +++ b/src/interactive-auth.ts @@ -264,8 +264,8 @@ export class InteractiveAuth { private readonly requestEmailTokenCallback: IOpts["requestEmailToken"]; private readonly supportedStages?: Set; - // The current latest data received from the server during the user interactive auth flow. - private data: IAuthData; + // The current latest data or error received from the server during the user interactive auth flow. + private data: IAuthData & MatrixError["data"]; private emailSid?: string; private requestingEmailToken = false; private attemptAuthDeferred: IDeferred | null = null; @@ -549,7 +549,7 @@ export class InteractiveAuth { matrixError.data.session = (this.data as IAuthData).session; } if (matrixError) { - this.data = matrixError.data as IAuthData; + this.data = matrixError.data; } try { this.startNextAuthStage(); @@ -602,6 +602,14 @@ export class InteractiveAuth { return; } + if (this.data?.errcode || this.data?.error) { + this.stateUpdatedCallback(nextStage, { + errcode: this.data?.errcode || "", + error: this.data?.error || "", + }); + return; + } + this.stateUpdatedCallback(nextStage, nextStage === EMAIL_STAGE_TYPE ? { emailSid: this.emailSid } : {}); }