You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-06 12:02:40 +03:00
Improve test coverage and modernize style for interactive-auth (#2574)
* style: address no-mixed-operators errors,minor style improvements
* test: Fix async interactive-auth tests, add test case
* tests: Fix incorrectly stringified mock response
* pushprocessor: style update
* use async primitives in interactive-auth-spec
* lint
* fixup: remove duplicate test
* add test case for no-flow-with-session for interactive-auth
* interactive-auth: handle non-existing error.data
* async test fix
* test: add dummyauth test
* add testing for errcode
* Revert "pushprocessor: style update"
This reverts commit 3ed0fdfb73
.
* add testcase for missing error data
* test: move sessionId assignment
* Add tests to improve coverage for interactive-auth
* pushprocessor: style update
This commit is contained in:
@@ -153,27 +153,26 @@ describe("AutoDiscovery", function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return FAIL_PROMPT when .well-known returns not-JSON", function() {
|
it("should return FAIL_PROMPT when .well-known returns not-JSON", async () => {
|
||||||
const httpBackend = getHttpBackend();
|
const httpBackend = getHttpBackend();
|
||||||
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, "abc");
|
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, "abc", true);
|
||||||
|
const expected = {
|
||||||
|
"m.homeserver": {
|
||||||
|
state: "FAIL_PROMPT",
|
||||||
|
error: AutoDiscovery.ERROR_INVALID,
|
||||||
|
base_url: null,
|
||||||
|
},
|
||||||
|
"m.identity_server": {
|
||||||
|
state: "PROMPT",
|
||||||
|
error: null,
|
||||||
|
base_url: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
httpBackend.flushAllExpected(),
|
httpBackend.flushAllExpected(),
|
||||||
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
AutoDiscovery.findClientConfig("example.org").then(
|
||||||
const expected = {
|
expect(expected).toEqual,
|
||||||
"m.homeserver": {
|
),
|
||||||
state: "FAIL_PROMPT",
|
|
||||||
error: AutoDiscovery.ERROR_INVALID,
|
|
||||||
base_url: null,
|
|
||||||
},
|
|
||||||
"m.identity_server": {
|
|
||||||
state: "PROMPT",
|
|
||||||
error: null,
|
|
||||||
base_url: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(conf).toEqual(expected);
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -32,8 +32,8 @@ class FakeClient {
|
|||||||
|
|
||||||
const getFakeClient = (): MatrixClient => new FakeClient() as unknown as MatrixClient;
|
const getFakeClient = (): MatrixClient => new FakeClient() as unknown as MatrixClient;
|
||||||
|
|
||||||
describe("InteractiveAuth", function() {
|
describe("InteractiveAuth", () => {
|
||||||
it("should start an auth stage and complete it", function() {
|
it("should start an auth stage and complete it", async () => {
|
||||||
const doRequest = jest.fn();
|
const doRequest = jest.fn();
|
||||||
const stateUpdated = jest.fn();
|
const stateUpdated = jest.fn();
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ describe("InteractiveAuth", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// first we expect a call here
|
// first we expect a call here
|
||||||
stateUpdated.mockImplementation(function(stage) {
|
stateUpdated.mockImplementation((stage) => {
|
||||||
logger.log('aaaa');
|
logger.log('aaaa');
|
||||||
expect(stage).toEqual(AuthType.Password);
|
expect(stage).toEqual(AuthType.Password);
|
||||||
ia.submitAuthDict({
|
ia.submitAuthDict({
|
||||||
@@ -69,23 +69,130 @@ describe("InteractiveAuth", function() {
|
|||||||
|
|
||||||
// .. which should trigger a call here
|
// .. which should trigger a call here
|
||||||
const requestRes = { "a": "b" };
|
const requestRes = { "a": "b" };
|
||||||
doRequest.mockImplementation(function(authData) {
|
doRequest.mockImplementation(async (authData) => {
|
||||||
logger.log('cccc');
|
logger.log('cccc');
|
||||||
expect(authData).toEqual({
|
expect(authData).toEqual({
|
||||||
session: "sessionId",
|
session: "sessionId",
|
||||||
type: AuthType.Password,
|
type: AuthType.Password,
|
||||||
});
|
});
|
||||||
return Promise.resolve(requestRes);
|
return requestRes;
|
||||||
});
|
});
|
||||||
|
|
||||||
return ia.attemptAuth().then(function(res) {
|
const res = await ia.attemptAuth();
|
||||||
expect(res).toBe(requestRes);
|
expect(res).toBe(requestRes);
|
||||||
expect(doRequest).toBeCalledTimes(1);
|
expect(doRequest).toBeCalledTimes(1);
|
||||||
expect(stateUpdated).toBeCalledTimes(1);
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should make a request if no authdata is provided", function() {
|
it("should handle auth errcode presence ", 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] },
|
||||||
|
],
|
||||||
|
errcode: "MockError0",
|
||||||
|
params: {
|
||||||
|
[AuthType.Password]: { param: "aa" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(ia.getSessionId()).toEqual("sessionId");
|
||||||
|
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
||||||
|
param: "aa",
|
||||||
|
});
|
||||||
|
|
||||||
|
// first we expect a call here
|
||||||
|
stateUpdated.mockImplementation((stage) => {
|
||||||
|
logger.log('aaaa');
|
||||||
|
expect(stage).toEqual(AuthType.Password);
|
||||||
|
ia.submitAuthDict({
|
||||||
|
type: AuthType.Password,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// .. which should trigger a call here
|
||||||
|
const requestRes = { "a": "b" };
|
||||||
|
doRequest.mockImplementation(async (authData) => {
|
||||||
|
logger.log('cccc');
|
||||||
|
expect(authData).toEqual({
|
||||||
|
session: "sessionId",
|
||||||
|
type: AuthType.Password,
|
||||||
|
});
|
||||||
|
return requestRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await ia.attemptAuth();
|
||||||
|
expect(res).toBe(requestRes);
|
||||||
|
expect(doRequest).toBeCalledTimes(1);
|
||||||
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle set emailSid for email flow", async () => {
|
||||||
|
const doRequest = jest.fn();
|
||||||
|
const stateUpdated = jest.fn();
|
||||||
|
const requestEmailToken = jest.fn();
|
||||||
|
|
||||||
|
const ia = new InteractiveAuth({
|
||||||
|
doRequest,
|
||||||
|
stateUpdated,
|
||||||
|
requestEmailToken,
|
||||||
|
matrixClient: getFakeClient(),
|
||||||
|
emailSid: 'myEmailSid',
|
||||||
|
authData: {
|
||||||
|
session: "sessionId",
|
||||||
|
flows: [
|
||||||
|
{ stages: [AuthType.Email, AuthType.Password] },
|
||||||
|
],
|
||||||
|
params: {
|
||||||
|
[AuthType.Email]: { param: "aa" },
|
||||||
|
[AuthType.Password]: { param: "bb" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(ia.getSessionId()).toEqual("sessionId");
|
||||||
|
expect(ia.getStageParams(AuthType.Email)).toEqual({
|
||||||
|
param: "aa",
|
||||||
|
});
|
||||||
|
|
||||||
|
// first we expect a call here
|
||||||
|
stateUpdated.mockImplementation((stage) => {
|
||||||
|
logger.log('husky');
|
||||||
|
expect(stage).toEqual(AuthType.Email);
|
||||||
|
ia.submitAuthDict({
|
||||||
|
type: AuthType.Email,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// .. which should trigger a call here
|
||||||
|
const requestRes = { "a": "b" };
|
||||||
|
doRequest.mockImplementation(async (authData) => {
|
||||||
|
logger.log('barfoo');
|
||||||
|
expect(authData).toEqual({
|
||||||
|
session: "sessionId",
|
||||||
|
type: AuthType.Email,
|
||||||
|
});
|
||||||
|
return requestRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await ia.attemptAuth();
|
||||||
|
expect(res).toBe(requestRes);
|
||||||
|
expect(doRequest).toBeCalledTimes(1);
|
||||||
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
|
expect(requestEmailToken).toBeCalledTimes(0);
|
||||||
|
expect(ia.getEmailSid()).toBe("myEmailSid");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should make a request if no authdata is provided", async () => {
|
||||||
const doRequest = jest.fn();
|
const doRequest = jest.fn();
|
||||||
const stateUpdated = jest.fn();
|
const stateUpdated = jest.fn();
|
||||||
const requestEmailToken = jest.fn();
|
const requestEmailToken = jest.fn();
|
||||||
@@ -101,7 +208,7 @@ describe("InteractiveAuth", function() {
|
|||||||
expect(ia.getStageParams(AuthType.Password)).toBe(undefined);
|
expect(ia.getStageParams(AuthType.Password)).toBe(undefined);
|
||||||
|
|
||||||
// first we expect a call to doRequest
|
// first we expect a call to doRequest
|
||||||
doRequest.mockImplementation(function(authData) {
|
doRequest.mockImplementation((authData) => {
|
||||||
logger.log("request1", authData);
|
logger.log("request1", authData);
|
||||||
expect(authData).toEqual(null); // first request should be null
|
expect(authData).toEqual(null); // first request should be null
|
||||||
const err = new MatrixError({
|
const err = new MatrixError({
|
||||||
@@ -119,7 +226,7 @@ describe("InteractiveAuth", function() {
|
|||||||
|
|
||||||
// .. which should be followed by a call to stateUpdated
|
// .. which should be followed by a call to stateUpdated
|
||||||
const requestRes = { "a": "b" };
|
const requestRes = { "a": "b" };
|
||||||
stateUpdated.mockImplementation(function(stage) {
|
stateUpdated.mockImplementation((stage) => {
|
||||||
expect(stage).toEqual(AuthType.Password);
|
expect(stage).toEqual(AuthType.Password);
|
||||||
expect(ia.getSessionId()).toEqual("sessionId");
|
expect(ia.getSessionId()).toEqual("sessionId");
|
||||||
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
||||||
@@ -127,13 +234,13 @@ describe("InteractiveAuth", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// submitAuthDict should trigger another call to doRequest
|
// submitAuthDict should trigger another call to doRequest
|
||||||
doRequest.mockImplementation(function(authData) {
|
doRequest.mockImplementation(async (authData) => {
|
||||||
logger.log("request2", authData);
|
logger.log("request2", authData);
|
||||||
expect(authData).toEqual({
|
expect(authData).toEqual({
|
||||||
session: "sessionId",
|
session: "sessionId",
|
||||||
type: AuthType.Password,
|
type: AuthType.Password,
|
||||||
});
|
});
|
||||||
return Promise.resolve(requestRes);
|
return requestRes;
|
||||||
});
|
});
|
||||||
|
|
||||||
ia.submitAuthDict({
|
ia.submitAuthDict({
|
||||||
@@ -141,14 +248,76 @@ describe("InteractiveAuth", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return ia.attemptAuth().then(function(res) {
|
const res = await ia.attemptAuth();
|
||||||
expect(res).toBe(requestRes);
|
expect(res).toBe(requestRes);
|
||||||
expect(doRequest).toBeCalledTimes(2);
|
expect(doRequest).toBeCalledTimes(2);
|
||||||
expect(stateUpdated).toBeCalledTimes(1);
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should start an auth stage and reject if no auth flow", function() {
|
it("should make a request if authdata is null", async () => {
|
||||||
|
const doRequest = jest.fn();
|
||||||
|
const stateUpdated = jest.fn();
|
||||||
|
const requestEmailToken = jest.fn();
|
||||||
|
|
||||||
|
const ia = new InteractiveAuth({
|
||||||
|
authData: null,
|
||||||
|
matrixClient: getFakeClient(),
|
||||||
|
stateUpdated,
|
||||||
|
doRequest,
|
||||||
|
requestEmailToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(ia.getSessionId()).toBe(undefined);
|
||||||
|
expect(ia.getStageParams(AuthType.Password)).toBe(undefined);
|
||||||
|
|
||||||
|
// first we expect a call to doRequest
|
||||||
|
doRequest.mockImplementation((authData) => {
|
||||||
|
logger.log("request1", authData);
|
||||||
|
expect(authData).toEqual(null); // first request should be null
|
||||||
|
const err = new MatrixError({
|
||||||
|
session: "sessionId",
|
||||||
|
flows: [
|
||||||
|
{ stages: [AuthType.Password] },
|
||||||
|
],
|
||||||
|
params: {
|
||||||
|
[AuthType.Password]: { param: "aa" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
err.httpStatus = 401;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// .. which should be followed by a call to stateUpdated
|
||||||
|
const requestRes = { "a": "b" };
|
||||||
|
stateUpdated.mockImplementation((stage) => {
|
||||||
|
expect(stage).toEqual(AuthType.Password);
|
||||||
|
expect(ia.getSessionId()).toEqual("sessionId");
|
||||||
|
expect(ia.getStageParams(AuthType.Password)).toEqual({
|
||||||
|
param: "aa",
|
||||||
|
});
|
||||||
|
|
||||||
|
// submitAuthDict should trigger another call to doRequest
|
||||||
|
doRequest.mockImplementation(async (authData) => {
|
||||||
|
logger.log("request2", authData);
|
||||||
|
expect(authData).toEqual({
|
||||||
|
session: "sessionId",
|
||||||
|
type: AuthType.Password,
|
||||||
|
});
|
||||||
|
return requestRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
ia.submitAuthDict({
|
||||||
|
type: AuthType.Password,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await ia.attemptAuth();
|
||||||
|
expect(res).toBe(requestRes);
|
||||||
|
expect(doRequest).toBeCalledTimes(2);
|
||||||
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should start an auth stage and reject if no auth flow", async () => {
|
||||||
const doRequest = jest.fn();
|
const doRequest = jest.fn();
|
||||||
const stateUpdated = jest.fn();
|
const stateUpdated = jest.fn();
|
||||||
const requestEmailToken = jest.fn();
|
const requestEmailToken = jest.fn();
|
||||||
@@ -160,7 +329,7 @@ describe("InteractiveAuth", function() {
|
|||||||
requestEmailToken,
|
requestEmailToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
doRequest.mockImplementation(function(authData) {
|
doRequest.mockImplementation((authData) => {
|
||||||
logger.log("request1", authData);
|
logger.log("request1", authData);
|
||||||
expect(authData).toEqual(null); // first request should be null
|
expect(authData).toEqual(null); // first request should be null
|
||||||
const err = new MatrixError({
|
const err = new MatrixError({
|
||||||
@@ -174,9 +343,108 @@ describe("InteractiveAuth", function() {
|
|||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
return ia.attemptAuth().catch(function(error) {
|
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
|
||||||
expect(error.message).toBe('No appropriate authentication flow found');
|
new Error('No appropriate authentication flow found'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should start an auth stage and reject if no auth flow but has session", async () => {
|
||||||
|
const doRequest = jest.fn();
|
||||||
|
const stateUpdated = jest.fn();
|
||||||
|
const requestEmailToken = jest.fn();
|
||||||
|
|
||||||
|
const ia = new InteractiveAuth({
|
||||||
|
matrixClient: getFakeClient(),
|
||||||
|
doRequest,
|
||||||
|
stateUpdated,
|
||||||
|
requestEmailToken,
|
||||||
|
authData: {
|
||||||
|
},
|
||||||
|
sessionId: "sessionId",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
doRequest.mockImplementation((authData) => {
|
||||||
|
logger.log("request1", authData);
|
||||||
|
expect(authData).toEqual({ "session": "sessionId" }); // has existing sessionId
|
||||||
|
const err = new MatrixError({
|
||||||
|
session: "sessionId",
|
||||||
|
flows: [],
|
||||||
|
params: {
|
||||||
|
[AuthType.Password]: { param: "aa" },
|
||||||
|
},
|
||||||
|
error: "Mock Error 1",
|
||||||
|
errcode: "MOCKERR1",
|
||||||
|
});
|
||||||
|
err.httpStatus = 401;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
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 () => {
|
||||||
|
const doRequest = jest.fn();
|
||||||
|
const stateUpdated = jest.fn();
|
||||||
|
const requestEmailToken = jest.fn();
|
||||||
|
|
||||||
|
const ia = new InteractiveAuth({
|
||||||
|
matrixClient: getFakeClient(),
|
||||||
|
doRequest,
|
||||||
|
stateUpdated,
|
||||||
|
requestEmailToken,
|
||||||
|
authData: {
|
||||||
|
session: "sessionId",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
doRequest.mockImplementation((authData) => {
|
||||||
|
logger.log("request1", authData);
|
||||||
|
expect(authData).toEqual({ "session": "sessionId" }); // has existing sessionId
|
||||||
|
const err = new Error('myerror');
|
||||||
|
(err as any).httpStatus = 401;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
|
||||||
|
new Error("myerror"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow dummy auth", async () => {
|
||||||
|
const doRequest = jest.fn();
|
||||||
|
const stateUpdated = jest.fn();
|
||||||
|
const requestEmailToken = jest.fn();
|
||||||
|
|
||||||
|
const ia = new InteractiveAuth({
|
||||||
|
matrixClient: getFakeClient(),
|
||||||
|
doRequest,
|
||||||
|
stateUpdated,
|
||||||
|
requestEmailToken,
|
||||||
|
authData: {
|
||||||
|
session: 'sessionId',
|
||||||
|
flows: [
|
||||||
|
{ stages: [AuthType.Dummy] },
|
||||||
|
],
|
||||||
|
params: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const requestRes = { "a": "b" };
|
||||||
|
doRequest.mockImplementation((authData) => {
|
||||||
|
logger.log("request1", authData);
|
||||||
|
expect(authData).toEqual({
|
||||||
|
session: "sessionId",
|
||||||
|
type: AuthType.Dummy,
|
||||||
|
});
|
||||||
|
return requestRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await ia.attemptAuth();
|
||||||
|
expect(res).toBe(requestRes);
|
||||||
|
expect(doRequest).toBeCalledTimes(1);
|
||||||
|
expect(stateUpdated).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("requestEmailToken", () => {
|
describe("requestEmailToken", () => {
|
||||||
@@ -247,7 +515,7 @@ describe("InteractiveAuth", function() {
|
|||||||
doRequest, stateUpdated, requestEmailToken,
|
doRequest, stateUpdated, requestEmailToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(async () => await ia.requestEmailToken()).rejects.toThrowError("unspecific network error");
|
await expect(ia.requestEmailToken.bind(ia)).rejects.toThrowError("unspecific network error");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("only starts one request at a time", async () => {
|
it("only starts one request at a time", async () => {
|
||||||
|
@@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
|
|
||||||
/** @module auto-discovery */
|
/** @module auto-discovery */
|
||||||
|
|
||||||
|
import { ServerResponse } from "http";
|
||||||
|
|
||||||
import { IClientWellKnown, IWellKnownConfig } from "./client";
|
import { IClientWellKnown, IWellKnownConfig } from "./client";
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
|
|
||||||
@@ -409,39 +411,41 @@ export class AutoDiscovery {
|
|||||||
* @return {Promise<object>} Resolves to the returned state.
|
* @return {Promise<object>} Resolves to the returned state.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private static fetchWellKnownObject(url: string): Promise<IWellKnownConfig> {
|
private static fetchWellKnownObject(uri: string): Promise<IWellKnownConfig> {
|
||||||
return new Promise(function(resolve) {
|
return new Promise((resolve) => {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const request = require("./matrix").getRequest();
|
const request = require("./matrix").getRequest();
|
||||||
if (!request) throw new Error("No request library available");
|
if (!request) throw new Error("No request library available");
|
||||||
request(
|
request(
|
||||||
{ method: "GET", uri: url, timeout: 5000 },
|
{ method: "GET", uri, timeout: 5000 },
|
||||||
(err, response, body) => {
|
(error: Error, response: ServerResponse, body: string) => {
|
||||||
if (err || response &&
|
if (error || response?.statusCode < 200 || response?.statusCode >= 300) {
|
||||||
(response.statusCode < 200 || response.statusCode >= 300)
|
const result = { error, raw: {} };
|
||||||
) {
|
return resolve(response?.statusCode === 404
|
||||||
let action = AutoDiscoveryAction.FAIL_PROMPT;
|
? {
|
||||||
let reason = (err ? err.message : null) || "General failure";
|
...result,
|
||||||
if (response && response.statusCode === 404) {
|
action: AutoDiscoveryAction.IGNORE,
|
||||||
action = AutoDiscoveryAction.IGNORE;
|
reason: AutoDiscovery.ERROR_MISSING_WELLKNOWN,
|
||||||
reason = AutoDiscovery.ERROR_MISSING_WELLKNOWN;
|
} : {
|
||||||
}
|
...result,
|
||||||
resolve({ raw: {}, action: action, reason: reason, error: err });
|
action: AutoDiscoveryAction.FAIL_PROMPT,
|
||||||
return;
|
reason: error?.message || "General failure",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
resolve({ raw: JSON.parse(body), action: AutoDiscoveryAction.SUCCESS });
|
return resolve({
|
||||||
} catch (e) {
|
raw: JSON.parse(body),
|
||||||
let reason = AutoDiscovery.ERROR_INVALID;
|
action: AutoDiscoveryAction.SUCCESS,
|
||||||
if (e.name === "SyntaxError") {
|
});
|
||||||
reason = AutoDiscovery.ERROR_INVALID_JSON;
|
} catch (err) {
|
||||||
}
|
return resolve({
|
||||||
resolve({
|
error: err,
|
||||||
raw: {},
|
raw: {},
|
||||||
action: AutoDiscoveryAction.FAIL_PROMPT,
|
action: AutoDiscoveryAction.FAIL_PROMPT,
|
||||||
reason: reason,
|
reason: err?.name === "SyntaxError"
|
||||||
error: e,
|
? AutoDiscovery.ERROR_INVALID_JSON
|
||||||
|
: AutoDiscovery.ERROR_INVALID,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -250,12 +250,9 @@ export class InteractiveAuth {
|
|||||||
if (!this.data?.flows) {
|
if (!this.data?.flows) {
|
||||||
this.busyChangedCallback?.(true);
|
this.busyChangedCallback?.(true);
|
||||||
// use the existing sessionId, if one is present.
|
// use the existing sessionId, if one is present.
|
||||||
let auth = null;
|
const auth = this.data.session
|
||||||
if (this.data.session) {
|
? { session: this.data.session }
|
||||||
auth = {
|
: null;
|
||||||
session: this.data.session,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this.doRequest(auth).finally(() => {
|
this.doRequest(auth).finally(() => {
|
||||||
this.busyChangedCallback?.(false);
|
this.busyChangedCallback?.(false);
|
||||||
});
|
});
|
||||||
@@ -312,7 +309,7 @@ export class InteractiveAuth {
|
|||||||
* @return {string} session id
|
* @return {string} session id
|
||||||
*/
|
*/
|
||||||
public getSessionId(): string {
|
public getSessionId(): string {
|
||||||
return this.data ? this.data.session : undefined;
|
return this.data?.session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -477,6 +474,9 @@ export class InteractiveAuth {
|
|||||||
logger.log("Background poll request failed doing UI auth: ignoring", error);
|
logger.log("Background poll request failed doing UI auth: ignoring", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!error.data) {
|
||||||
|
error.data = {};
|
||||||
|
}
|
||||||
// if the error didn't come with flows, completed flows or session ID,
|
// if the error didn't come with flows, completed flows or session ID,
|
||||||
// copy over the ones we have. Synapse sometimes sends responses without
|
// copy over the ones we have. Synapse sometimes sends responses without
|
||||||
// any UI auth data (eg. when polling for email validation, if the email
|
// any UI auth data (eg. when polling for email validation, if the email
|
||||||
@@ -539,19 +539,17 @@ export class InteractiveAuth {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.data && this.data.errcode || this.data.error) {
|
if (this.data?.errcode || this.data?.error) {
|
||||||
this.stateUpdatedCallback(nextStage, {
|
this.stateUpdatedCallback(nextStage, {
|
||||||
errcode: this.data.errcode || "",
|
errcode: this.data?.errcode || "",
|
||||||
error: this.data.error || "",
|
error: this.data?.error || "",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stageStatus: IStageStatus = {};
|
this.stateUpdatedCallback(nextStage, nextStage === EMAIL_STAGE_TYPE
|
||||||
if (nextStage == EMAIL_STAGE_TYPE) {
|
? { emailSid: this.emailSid }
|
||||||
stageStatus.emailSid = this.emailSid;
|
: {});
|
||||||
}
|
|
||||||
this.stateUpdatedCallback(nextStage, stageStatus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -362,13 +362,9 @@ export class PushProcessor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let regex;
|
const regex = cond.key === 'content.body'
|
||||||
|
? this.createCachedRegex('(^|\\W)', cond.pattern, '(\\W|$)')
|
||||||
if (cond.key == 'content.body') {
|
: this.createCachedRegex('^', cond.pattern, '$');
|
||||||
regex = this.createCachedRegex('(^|\\W)', cond.pattern, '(\\W|$)');
|
|
||||||
} else {
|
|
||||||
regex = this.createCachedRegex('^', cond.pattern, '$');
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!val.match(regex);
|
return !!val.match(regex);
|
||||||
}
|
}
|
||||||
|
30
src/utils.ts
30
src/utils.ts
@@ -328,22 +328,28 @@ export function escapeRegExp(string: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function globToRegexp(glob: string, extended?: any): string {
|
export function globToRegexp(glob: string, extended?: any): string {
|
||||||
extended = typeof(extended) === 'boolean' ? extended : true;
|
|
||||||
// From
|
// From
|
||||||
// https://github.com/matrix-org/synapse/blob/abbee6b29be80a77e05730707602f3bbfc3f38cb/synapse/push/__init__.py#L132
|
// https://github.com/matrix-org/synapse/blob/abbee6b29be80a77e05730707602f3bbfc3f38cb/synapse/push/__init__.py#L132
|
||||||
// Because micromatch is about 130KB with dependencies,
|
// Because micromatch is about 130KB with dependencies,
|
||||||
// and minimatch is not much better.
|
// and minimatch is not much better.
|
||||||
let pat = escapeRegExp(glob);
|
const replacements: ([RegExp, string | ((substring: string, ...args: any[]) => string) ])[] = [
|
||||||
pat = pat.replace(/\\\*/g, '.*');
|
[/\\\*/g, '.*'],
|
||||||
pat = pat.replace(/\?/g, '.');
|
[/\?/g, '.'],
|
||||||
if (extended) {
|
extended !== false && [
|
||||||
pat = pat.replace(/\\\[(!|)(.*)\\]/g, function(match, p1, p2, offset, string) {
|
/\\\[(!|)(.*)\\]/g,
|
||||||
const first = p1 && '^' || '';
|
(_match: string, neg: string, pat: string) => [
|
||||||
const second = p2.replace(/\\-/, '-');
|
'[',
|
||||||
return '[' + first + second + ']';
|
neg ? '^' : '',
|
||||||
});
|
pat.replace(/\\-/, '-'),
|
||||||
}
|
']',
|
||||||
return pat;
|
].join(''),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
return replacements.reduce(
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/30134
|
||||||
|
(pat, args) => args ? pat.replace(args[0], args[1] as any) : pat,
|
||||||
|
escapeRegExp(glob),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureNoTrailingSlash(url: string): string {
|
export function ensureNoTrailingSlash(url: string): string {
|
||||||
|
@@ -1865,10 +1865,10 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
|
|||||||
const shouldTerminate = (
|
const shouldTerminate = (
|
||||||
// reject events also end the call if it's ringing: it's another of
|
// reject events also end the call if it's ringing: it's another of
|
||||||
// our devices rejecting the call.
|
// our devices rejecting the call.
|
||||||
([CallState.InviteSent, CallState.Ringing].includes(this.state)) ||
|
[CallState.InviteSent, CallState.Ringing].includes(this.state) ||
|
||||||
// also if we're in the init state and it's an inbound call, since
|
// also if we're in the init state and it's an inbound call, since
|
||||||
// this means we just haven't entered the ringing state yet
|
// this means we just haven't entered the ringing state yet
|
||||||
this.state === CallState.Fledgling && this.direction === CallDirection.Inbound
|
(this.state === CallState.Fledgling && this.direction === CallDirection.Inbound)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (shouldTerminate) {
|
if (shouldTerminate) {
|
||||||
|
Reference in New Issue
Block a user