[MM-39885] Migrate unit tests to Jest, fleshed out tests for common/util, a bunch of cleanup (#1852)
* [MM-39885] Migrate unit tests to Jest, fleshed out tests for common/util/url * Typo fix * Oops * I found more tests! * Fixed a bug * Oops again * Tests for common/utils/util * A bunch of cleanup * Oops
This commit is contained in:
parent
fbb3c9c705
commit
38270fcfe8
|
@ -11,6 +11,3 @@ import './window_test.js';
|
|||
import './browser/index_test.js';
|
||||
import './browser/modal_test.js';
|
||||
import './browser/settings_test.js';
|
||||
|
||||
import './main/user_activity_monitor_test.js';
|
||||
import './utils/util_test.js';
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
'use strict';
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import urlUtils from '../../../src/common/utils/url';
|
||||
|
||||
describe('Utils', () => {
|
||||
describe('isValidURL', () => {
|
||||
it('should be true for a valid web url', () => {
|
||||
const testURL = 'https://developers.mattermost.com/';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a valid, non-https web url', () => {
|
||||
const testURL = 'http://developers.mattermost.com/';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for an invalid, self-defined, top-level domain', () => {
|
||||
const testURL = 'https://www.example.x';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a file download url', () => {
|
||||
const testURL = 'https://community.mattermost.com/api/v4/files/ka3xbfmb3ffnmgdmww8otkidfw?download=1';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a permalink url', () => {
|
||||
const testURL = 'https://community.mattermost.com/test-channel/pl/pdqowkij47rmbyk78m5hwc7r6r';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a valid, internal domain', () => {
|
||||
const testURL = 'https://mattermost.company-internal';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a second, valid internal domain', () => {
|
||||
const testURL = 'https://serverXY/mattermost';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a valid, non-https internal domain', () => {
|
||||
const testURL = 'http://mattermost.local';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
it('should be true for a valid, non-https, ip address with port number', () => {
|
||||
const testURL = 'http://localhost:8065';
|
||||
assert.equal(urlUtils.isValidURL(testURL), true);
|
||||
});
|
||||
});
|
||||
describe('isValidURI', () => {
|
||||
it('should be true for a deeplink url', () => {
|
||||
const testURL = 'mattermost://community-release.mattermost.com/core/channels/developers';
|
||||
assert.equal(urlUtils.isValidURI(testURL), true);
|
||||
});
|
||||
it('should be false for a malicious url', () => {
|
||||
const testURL = String.raw`mattermost:///" --data-dir "\\deans-mbp\mattermost`;
|
||||
assert.equal(urlUtils.isValidURI(testURL), false);
|
||||
});
|
||||
});
|
||||
describe('isInternalURL', () => {
|
||||
it('should be false for different hosts', () => {
|
||||
const currentURL = new URL('http://localhost/team/channel1');
|
||||
const targetURL = new URL('http://example.com/team/channel2');
|
||||
const basename = '/';
|
||||
assert.equal(urlUtils.isInternalURL(targetURL, currentURL, basename), false);
|
||||
});
|
||||
|
||||
it('should be false for same hosts, non-matching basename', () => {
|
||||
const currentURL = new URL('http://localhost/subpath/team/channel1');
|
||||
const targetURL = new URL('http://localhost/team/channel2');
|
||||
const basename = '/subpath';
|
||||
assert.equal(urlUtils.isInternalURL(targetURL, currentURL, basename), false);
|
||||
});
|
||||
|
||||
it('should be true for same hosts, matching basename', () => {
|
||||
const currentURL = new URL('http://localhost/subpath/team/channel1');
|
||||
const targetURL = new URL('http://localhost/subpath/team/channel2');
|
||||
const basename = '/subpath';
|
||||
assert.equal(urlUtils.isInternalURL(targetURL, currentURL, basename), true);
|
||||
});
|
||||
|
||||
it('should be true for same hosts, default basename', () => {
|
||||
const currentURL = new URL('http://localhost/team/channel1');
|
||||
const targetURL = new URL('http://localhost/team/channel2');
|
||||
const basename = '/';
|
||||
assert.equal(urlUtils.isInternalURL(targetURL, currentURL, basename), true);
|
||||
});
|
||||
|
||||
it('should be true for same hosts, default basename, empty target path', () => {
|
||||
const currentURL = new URL('http://localhost/team/channel1');
|
||||
const targetURL = new URL('http://localhost/');
|
||||
const basename = '/';
|
||||
assert.equal(urlUtils.isInternalURL(targetURL, currentURL, basename), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getHost', () => {
|
||||
it('should return the origin of a well formed url', () => {
|
||||
const myurl = 'https://mattermost.com/download';
|
||||
assert.equal(urlUtils.getHost(myurl), 'https://mattermost.com');
|
||||
});
|
||||
|
||||
it('shoud raise an error on malformed urls', () => {
|
||||
const myurl = 'http://example.com:-80/';
|
||||
assert.throws(() => urlUtils.getHost(myurl), Error);
|
||||
});
|
||||
});
|
||||
});
|
6664
package-lock.json
generated
6664
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -43,7 +43,7 @@
|
|||
"test:e2e:nobuild": "cross-env NODE_ENV=test npm-run-all test:e2e:build test:e2e:run",
|
||||
"test:e2e:build": "webpack-cli --bail --config webpack.config.test.js",
|
||||
"test:e2e:run": "electron-mocha -r @babel/register --reporter mocha-circleci-reporter dist/tests/e2e_bundle.js",
|
||||
"test:unit": "npm-run-all test:unit:build test:unit:run",
|
||||
"test:unit": "jest",
|
||||
"test:unit:build": "cross-env NODE_ENV=test webpack-cli --bail --config webpack.config.test.js",
|
||||
"test:unit:run": "cross-env NODE_ENV=test mocha --reporter mocha-circleci-reporter dist/tests/test_bundle.js",
|
||||
"package:all": "cross-env NODE_ENV=production npm-run-all check-build-config package:windows package:mac package:mac-universal package:linux",
|
||||
|
@ -59,6 +59,20 @@
|
|||
"check-build-config:run": "node -r @babel/register scripts/check_build_config.js",
|
||||
"check-types": "tsc"
|
||||
},
|
||||
"jest": {
|
||||
"moduleDirectories": [
|
||||
"",
|
||||
"node_modules"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"jsx",
|
||||
"json"
|
||||
],
|
||||
"testMatch": ["**/src/**/*.test.js"]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.14.5",
|
||||
"@babel/core": "^7.2.0",
|
||||
|
@ -108,6 +122,7 @@
|
|||
"eslint-plugin-react": "7.22.0",
|
||||
"file-loader": "^2.0.0",
|
||||
"image-webpack-loader": "5.0.0",
|
||||
"jest": "^27.3.1",
|
||||
"mdi-react": "^6.2.0",
|
||||
"mini-css-extract-plugin": "1.6.0",
|
||||
"mocha": "^5.2.0",
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import deepmerge from 'deepmerge';
|
||||
|
||||
export default function deepMergeProxy<T>(x: Partial<T>, y: Partial<T>, options: deepmerge.Options) {
|
||||
return deepmerge(x, y, options); // due to webpack conversion
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
'use strict';
|
||||
|
||||
import os from 'os';
|
||||
const releaseSplit = os.release().split('.');
|
||||
|
||||
export default {
|
||||
major: parseInt(releaseSplit[0], 10),
|
||||
minor: parseInt(releaseSplit[1], 10),
|
||||
isLowerThanOrEqualWindows8_1(): boolean {
|
||||
if (process.platform !== 'win32') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// consider Windows 7 and later.
|
||||
return (this.major <= 6 && this.minor <= 3);
|
||||
},
|
||||
};
|
|
@ -13,20 +13,4 @@ export class MattermostServer {
|
|||
throw new Error('Invalid url for creating a server');
|
||||
}
|
||||
}
|
||||
|
||||
getServerInfo = () => {
|
||||
// does the server have a subpath?
|
||||
const normalizedPath = this.url.pathname.toLowerCase();
|
||||
const subpath = normalizedPath.endsWith('/') ? normalizedPath : `${normalizedPath}/`;
|
||||
return {origin: this.url.origin, subpath, url: this.url.toString()};
|
||||
}
|
||||
|
||||
sameOrigin = (otherURL: string) => {
|
||||
const parsedUrl = urlUtils.parseURL(otherURL);
|
||||
return parsedUrl && this.url.origin === parsedUrl.origin;
|
||||
}
|
||||
|
||||
equals = (otherServer: MattermostServer) => {
|
||||
return (this.name === otherServer.name) && (this.url.toString() === otherServer.url.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,31 @@ export const DEFAULT_WINDOW_HEIGHT = 700;
|
|||
export const MINIMUM_WINDOW_WIDTH = 700;
|
||||
export const MINIMUM_WINDOW_HEIGHT = 240;
|
||||
|
||||
// supported custom login paths (oath, saml)
|
||||
export const customLoginRegexPaths = [
|
||||
/^\/oauth\/authorize$/i,
|
||||
/^\/oauth\/deauthorize$/i,
|
||||
/^\/oauth\/access_token$/i,
|
||||
/^\/oauth\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/oauth\/[A-Za-z0-9]+\/login$/i,
|
||||
/^\/oauth\/[A-Za-z0-9]+\/signup$/i,
|
||||
/^\/api\/v3\/oauth\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/signup\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/login\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/login\/sso\/saml$/i,
|
||||
];
|
||||
|
||||
export const nonTeamUrlPaths = [
|
||||
'plugins',
|
||||
'signup',
|
||||
'login',
|
||||
'admin',
|
||||
'channel',
|
||||
'post',
|
||||
'oauth',
|
||||
'admin_console',
|
||||
];
|
||||
|
||||
export const localeTranslations: Record<string, string> = {
|
||||
'af': 'Afrikaans',
|
||||
'af-ZA': 'Afrikaans (South Africa)',
|
||||
|
|
|
@ -2,17 +2,415 @@
|
|||
// See LICENSE.txt for license information.
|
||||
'use strict';
|
||||
|
||||
import assert from 'assert';
|
||||
import urlUtils, {getFormattedPathName, isUrlType, equalUrlsIgnoringSubpath, equalUrlsWithSubpath} from 'common/utils/url';
|
||||
|
||||
import urlUtils from 'common/utils/url';
|
||||
jest.mock('common/tabs/TabView', () => ({
|
||||
getServerView: (srv, tab) => {
|
||||
return {
|
||||
name: `${srv.name}_${tab.name}`,
|
||||
url: `${srv.url}${srv.url.toString().endsWith('/') ? '' : '/'}${tab.name.split('-')[1] || ''}`,
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
describe('common/utils/url', () => {
|
||||
describe('isValidURL', () => {
|
||||
it('should be true for a valid web url', () => {
|
||||
const testURL = 'https://developers.mattermost.com/';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a valid, non-https web url', () => {
|
||||
const testURL = 'http://developers.mattermost.com/';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for an invalid, self-defined, top-level domain', () => {
|
||||
const testURL = 'https://www.example.x';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a file download url', () => {
|
||||
const testURL = 'https://community.mattermost.com/api/v4/files/ka3xbfmb3ffnmgdmww8otkidfw?download=1';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a permalink url', () => {
|
||||
const testURL = 'https://community.mattermost.com/test-channel/pl/pdqowkij47rmbyk78m5hwc7r6r';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a valid, internal domain', () => {
|
||||
const testURL = 'https://mattermost.company-internal';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a second, valid internal domain', () => {
|
||||
const testURL = 'https://serverXY/mattermost';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a valid, non-https internal domain', () => {
|
||||
const testURL = 'http://mattermost.local';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
it('should be true for a valid, non-https, ip address with port number', () => {
|
||||
const testURL = 'http://localhost:8065';
|
||||
expect(urlUtils.isValidURL(testURL)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('isValidURI', () => {
|
||||
it('should be true for a deeplink url', () => {
|
||||
const testURL = 'mattermost://community-release.mattermost.com/core/channels/developers';
|
||||
expect(urlUtils.isValidURI(testURL)).toBe(true);
|
||||
});
|
||||
it('should be false for a malicious url', () => {
|
||||
const testURL = String.raw`mattermost:///" --data-dir "\\deans-mbp\mattermost`;
|
||||
expect(urlUtils.isValidURI(testURL)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getHost', () => {
|
||||
it('should return the origin of a well formed url', () => {
|
||||
const myurl = 'https://mattermost.com/download';
|
||||
expect(urlUtils.getHost(myurl)).toBe('https://mattermost.com');
|
||||
});
|
||||
|
||||
it('shoud raise an error on malformed urls', () => {
|
||||
const myurl = 'http://example.com:-80/';
|
||||
expect(() => {
|
||||
urlUtils.getHost(myurl);
|
||||
}).toThrow(SyntaxError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('URL', () => {
|
||||
describe('parseURL', () => {
|
||||
it('should return the URL if it is already a URL', () => {
|
||||
const url = new URL('http://mattermost.com');
|
||||
expect(urlUtils.parseURL(url)).toBe(url);
|
||||
});
|
||||
|
||||
it('should return undefined when a bad url is passed', () => {
|
||||
const badURL = 'not-a-real-url-at-all';
|
||||
expect(urlUtils.parseURL(badURL)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should remove duplicate slashes in a URL when parsing', () => {
|
||||
const urlWithExtraSlashes = 'https://mattermost.com//sub//path//example';
|
||||
const parsedURL = urlUtils.parseURL(urlWithExtraSlashes);
|
||||
|
||||
assert.strictEqual(parsedURL.toString(), 'https://mattermost.com/sub/path/example');
|
||||
expect(parsedURL.toString()).toBe('https://mattermost.com/sub/path/example');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInternalURL', () => {
|
||||
it('should return false on different hosts', () => {
|
||||
const baseURL = new URL('http://mattermost.com');
|
||||
const externalURL = new URL('http://google.com');
|
||||
|
||||
expect(urlUtils.isInternalURL(externalURL, baseURL)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false on different ports', () => {
|
||||
const baseURL = new URL('http://mattermost.com:8080');
|
||||
const externalURL = new URL('http://mattermost.com:9001');
|
||||
|
||||
expect(urlUtils.isInternalURL(externalURL, baseURL)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false on different subpaths', () => {
|
||||
const baseURL = new URL('http://mattermost.com/sub/path/');
|
||||
const externalURL = new URL('http://mattermost.com/different/sub/path');
|
||||
|
||||
expect(urlUtils.isInternalURL(externalURL, baseURL)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if matching', () => {
|
||||
const baseURL = new URL('http://mattermost.com/');
|
||||
const externalURL = new URL('http://mattermost.com');
|
||||
|
||||
expect(urlUtils.isInternalURL(externalURL, baseURL)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if matching with subpath', () => {
|
||||
const baseURL = new URL('http://mattermost.com/sub/path/');
|
||||
const externalURL = new URL('http://mattermost.com/sub/path');
|
||||
|
||||
expect(urlUtils.isInternalURL(externalURL, baseURL)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if subpath of', () => {
|
||||
const baseURL = new URL('http://mattermost.com/');
|
||||
const externalURL = new URL('http://mattermost.com/sub/path');
|
||||
|
||||
expect(urlUtils.isInternalURL(externalURL, baseURL)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFormattedPathName', () => {
|
||||
it('should format all to lower case', () => {
|
||||
const unformattedPathName = '/aAbBbB/cC/DdeR/';
|
||||
expect(getFormattedPathName(unformattedPathName)).toBe('/aabbbb/cc/dder/');
|
||||
});
|
||||
|
||||
it('should add trailing slash', () => {
|
||||
const unformattedPathName = '/aAbBbB/cC/DdeR';
|
||||
expect(getFormattedPathName(unformattedPathName)).toBe('/aabbbb/cc/dder/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUrlType', () => {
|
||||
const serverURL = new URL('http://mattermost.com');
|
||||
const urlType = 'url-type';
|
||||
|
||||
it('should identify base url', () => {
|
||||
const adminURL = new URL(`http://mattermost.com/${urlType}`);
|
||||
expect(isUrlType('url-type', serverURL, adminURL)).toBe(true);
|
||||
});
|
||||
|
||||
it('should identify url of correct type', () => {
|
||||
const adminURL = new URL(`http://mattermost.com/${urlType}/some/path`);
|
||||
expect(isUrlType('url-type', serverURL, adminURL)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not identify other url', () => {
|
||||
const adminURL = new URL('http://mattermost.com/some/other/path');
|
||||
expect(isUrlType('url-type', serverURL, adminURL)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getView', () => {
|
||||
const servers = [
|
||||
{
|
||||
name: 'server-1',
|
||||
url: 'http://server-1.com',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
{
|
||||
name: 'tab-type1',
|
||||
},
|
||||
{
|
||||
name: 'tab-type2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'server-2',
|
||||
url: 'http://server-2.com/subpath',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab-type1',
|
||||
},
|
||||
{
|
||||
name: 'tab-type2',
|
||||
},
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
it('should match the correct server - base URL', () => {
|
||||
const inputURL = new URL('http://server-1.com');
|
||||
expect(urlUtils.getView(inputURL, servers)).toStrictEqual({name: 'server-1_tab', url: 'http://server-1.com/'});
|
||||
});
|
||||
|
||||
it('should match the correct server - base tab', () => {
|
||||
const inputURL = new URL('http://server-1.com/team');
|
||||
expect(urlUtils.getView(inputURL, servers)).toStrictEqual({name: 'server-1_tab', url: 'http://server-1.com/'});
|
||||
});
|
||||
|
||||
it('should match the correct server - different tab', () => {
|
||||
const inputURL = new URL('http://server-1.com/type1/app');
|
||||
expect(urlUtils.getView(inputURL, servers)).toStrictEqual({name: 'server-1_tab-type1', url: 'http://server-1.com/type1'});
|
||||
});
|
||||
|
||||
it('should return undefined for server with subpath and URL without', () => {
|
||||
const inputURL = new URL('http://server-2.com');
|
||||
expect(urlUtils.getView(inputURL, servers)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return undefined for server with subpath and URL with wrong subpath', () => {
|
||||
const inputURL = new URL('http://server-2.com/different/subpath');
|
||||
expect(urlUtils.getView(inputURL, servers)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should match the correct server with a subpath - base URL', () => {
|
||||
const inputURL = new URL('http://server-2.com/subpath');
|
||||
expect(urlUtils.getView(inputURL, servers)).toStrictEqual({name: 'server-2_tab', url: 'http://server-2.com/subpath/'});
|
||||
});
|
||||
|
||||
it('should match the correct server with a subpath - base tab', () => {
|
||||
const inputURL = new URL('http://server-2.com/subpath/team');
|
||||
expect(urlUtils.getView(inputURL, servers)).toStrictEqual({name: 'server-2_tab', url: 'http://server-2.com/subpath/'});
|
||||
});
|
||||
|
||||
it('should match the correct server with a subpath - different tab', () => {
|
||||
const inputURL = new URL('http://server-2.com/subpath/type2/team');
|
||||
expect(urlUtils.getView(inputURL, servers)).toStrictEqual({name: 'server-2_tab-type2', url: 'http://server-2.com/subpath/type2'});
|
||||
});
|
||||
|
||||
it('should return undefined for wrong server', () => {
|
||||
const inputURL = new URL('http://server-3.com');
|
||||
expect(urlUtils.getView(inputURL, servers)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('equalUrls', () => {
|
||||
it('base urls', () => {
|
||||
const url1 = new URL('http://server-1.com');
|
||||
const url2 = new URL('http://server-1.com');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2)).toBe(true);
|
||||
expect(equalUrlsWithSubpath(url1, url2)).toBe(true);
|
||||
});
|
||||
|
||||
it('different urls', () => {
|
||||
const url1 = new URL('http://server-1.com');
|
||||
const url2 = new URL('http://server-2.com');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2)).toBe(false);
|
||||
expect(equalUrlsWithSubpath(url1, url2)).toBe(false);
|
||||
});
|
||||
|
||||
it('same host, different subpath', () => {
|
||||
const url1 = new URL('http://server-1.com/subpath');
|
||||
const url2 = new URL('http://server-1.com');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2)).toBe(true);
|
||||
expect(equalUrlsWithSubpath(url1, url2)).toBe(false);
|
||||
});
|
||||
|
||||
it('same host and subpath', () => {
|
||||
const url1 = new URL('http://server-1.com/subpath');
|
||||
const url2 = new URL('http://server-1.com/subpath');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2)).toBe(true);
|
||||
expect(equalUrlsWithSubpath(url1, url2)).toBe(true);
|
||||
});
|
||||
|
||||
it('same host, different URL scheme', () => {
|
||||
const url1 = new URL('http://server-1.com');
|
||||
const url2 = new URL('mattermost://server-1.com');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2)).toBe(false);
|
||||
expect(equalUrlsWithSubpath(url1, url2)).toBe(false);
|
||||
});
|
||||
|
||||
it('same host, different URL scheme, with ignore scheme', () => {
|
||||
const url1 = new URL('http://server-1.com');
|
||||
const url2 = new URL('mattermost://server-1.com');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2, true)).toBe(true);
|
||||
expect(equalUrlsWithSubpath(url1, url2, true)).toBe(true);
|
||||
});
|
||||
|
||||
it('same host, different ports', () => {
|
||||
const url1 = new URL('http://server-1.com:8080');
|
||||
const url2 = new URL('http://server-1.com');
|
||||
expect(equalUrlsIgnoringSubpath(url1, url2, true)).toBe(false);
|
||||
expect(equalUrlsWithSubpath(url1, url2, true)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCustomLoginURL', () => {
|
||||
it('should match correct URL', () => {
|
||||
expect(urlUtils.isCustomLoginURL(
|
||||
'http://server.com/oauth/authorize',
|
||||
{
|
||||
url: 'http://server.com',
|
||||
},
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
url: 'http://server.com',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
])).toBe(true);
|
||||
});
|
||||
it('should not match incorrect URL', () => {
|
||||
expect(urlUtils.isCustomLoginURL(
|
||||
'http://server.com/oauth/notauthorize',
|
||||
{
|
||||
url: 'http://server.com',
|
||||
},
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
url: 'http://server.com',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
])).toBe(false);
|
||||
});
|
||||
it('should not match base URL', () => {
|
||||
expect(urlUtils.isCustomLoginURL(
|
||||
'http://server.com/',
|
||||
{
|
||||
url: 'http://server.com',
|
||||
},
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
url: 'http://server.com',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
])).toBe(false);
|
||||
});
|
||||
it('should match with subpath', () => {
|
||||
expect(urlUtils.isCustomLoginURL(
|
||||
'http://server.com/subpath/oauth/authorize',
|
||||
{
|
||||
url: 'http://server.com/subpath',
|
||||
},
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
url: 'http://server.com/subpath',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
])).toBe(true);
|
||||
});
|
||||
it('should not match with different subpath', () => {
|
||||
expect(urlUtils.isCustomLoginURL(
|
||||
'http://server.com/subpath/oauth/authorize',
|
||||
{
|
||||
url: 'http://server.com/different/subpath',
|
||||
},
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
url: 'http://server.com/different/subpath',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
])).toBe(false);
|
||||
});
|
||||
it('should not match with oauth subpath', () => {
|
||||
expect(urlUtils.isCustomLoginURL(
|
||||
'http://server.com/oauth/authorize',
|
||||
{
|
||||
url: 'http://server.com/oauth/authorize',
|
||||
},
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
url: 'http://server.com/oauth/authorize',
|
||||
tabs: [
|
||||
{
|
||||
name: 'tab',
|
||||
},
|
||||
],
|
||||
},
|
||||
])).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,28 +6,10 @@ import {isHttpsUri, isHttpUri, isUri} from 'valid-url';
|
|||
import {TeamWithTabs} from 'types/config';
|
||||
import {ServerFromURL} from 'types/utils';
|
||||
|
||||
import buildConfig from '../config/buildConfig';
|
||||
import {MattermostServer} from '../servers/MattermostServer';
|
||||
import {getServerView} from '../tabs/TabView';
|
||||
|
||||
// supported custom login paths (oath, saml)
|
||||
const customLoginRegexPaths = [
|
||||
/^\/oauth\/authorize$/i,
|
||||
/^\/oauth\/deauthorize$/i,
|
||||
/^\/oauth\/access_token$/i,
|
||||
/^\/oauth\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/oauth\/[A-Za-z0-9]+\/login$/i,
|
||||
/^\/oauth\/[A-Za-z0-9]+\/signup$/i,
|
||||
/^\/api\/v3\/oauth\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/signup\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/login\/[A-Za-z0-9]+\/complete$/i,
|
||||
/^\/login\/sso\/saml$/i,
|
||||
];
|
||||
|
||||
function getDomain(inputURL: URL | string) {
|
||||
const parsedURL = parseURL(inputURL);
|
||||
return parsedURL?.origin;
|
||||
}
|
||||
import buildConfig from 'common/config/buildConfig';
|
||||
import {MattermostServer} from 'common/servers/MattermostServer';
|
||||
import {getServerView} from 'common/tabs/TabView';
|
||||
import {customLoginRegexPaths, nonTeamUrlPaths} from 'common/utils/constants';
|
||||
|
||||
function isValidURL(testURL: string) {
|
||||
return Boolean(isHttpUri(testURL) || isHttpsUri(testURL)) && Boolean(parseURL(testURL));
|
||||
|
@ -53,18 +35,17 @@ function getHost(inputURL: URL | string) {
|
|||
if (parsedURL) {
|
||||
return parsedURL.origin;
|
||||
}
|
||||
throw new Error(`Couldn't parse url: ${inputURL}`);
|
||||
throw new SyntaxError(`Couldn't parse url: ${inputURL}`);
|
||||
}
|
||||
|
||||
// isInternalURL determines if the target url is internal to the application.
|
||||
// - currentURL is the current url inside the webview
|
||||
// - basename is the global export from the Mattermost application defining the subpath, if any
|
||||
function isInternalURL(targetURL: URL, currentURL: URL, basename = '/') {
|
||||
function isInternalURL(targetURL: URL, currentURL: URL) {
|
||||
if (targetURL.host !== currentURL.host) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(targetURL.pathname || '/').startsWith(basename)) {
|
||||
if (!equalUrlsWithSubpath(targetURL, currentURL) && !(targetURL.pathname || '/').startsWith(currentURL.pathname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -84,7 +65,7 @@ function getServerInfo(serverUrl: URL | string) {
|
|||
}
|
||||
|
||||
export function getFormattedPathName(pn: string) {
|
||||
return pn.endsWith('/') ? pn.toLowerCase() : `${pn}/`;
|
||||
return pn.endsWith('/') ? pn.toLowerCase() : `${pn.toLowerCase()}/`;
|
||||
}
|
||||
|
||||
function getManagedResources() {
|
||||
|
@ -95,72 +76,46 @@ function getManagedResources() {
|
|||
return buildConfig.managedResources || [];
|
||||
}
|
||||
|
||||
function isAdminUrl(serverUrl: URL | string, inputUrl: URL | string) {
|
||||
const parsedURL = parseURL(inputUrl);
|
||||
const server = getServerInfo(serverUrl);
|
||||
if (!parsedURL || !server || (!equalUrlsIgnoringSubpath(server.url, parsedURL))) {
|
||||
return null;
|
||||
}
|
||||
return (parsedURL.pathname.toLowerCase().startsWith(`${server.subpath}/admin_console/`) ||
|
||||
parsedURL.pathname.toLowerCase().startsWith('/admin_console/'));
|
||||
}
|
||||
|
||||
function isTeamUrl(serverUrl: URL | string, inputUrl: URL | string, withApi?: boolean) {
|
||||
if (!serverUrl || !inputUrl) {
|
||||
export function isUrlType(urlType: string, serverUrl: URL | string, inputURL: URL | string) {
|
||||
if (!serverUrl || !inputURL) {
|
||||
return false;
|
||||
}
|
||||
const parsedURL = parseURL(inputUrl);
|
||||
|
||||
const parsedURL = parseURL(inputURL);
|
||||
const server = getServerInfo(serverUrl);
|
||||
if (!parsedURL || !server || (!equalUrlsIgnoringSubpath(server.url, parsedURL))) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
return (getFormattedPathName(parsedURL.pathname).startsWith(`${server.subpath}${urlType}/`) ||
|
||||
getFormattedPathName(parsedURL.pathname).startsWith(`/${urlType}/`));
|
||||
}
|
||||
|
||||
function isAdminUrl(serverUrl: URL | string, inputURL: URL | string) {
|
||||
return isUrlType('admin_console', serverUrl, inputURL);
|
||||
}
|
||||
|
||||
function isTeamUrl(serverUrl: URL | string, inputURL: URL | string, withApi?: boolean) {
|
||||
const parsedURL = parseURL(inputURL);
|
||||
const server = getServerInfo(serverUrl);
|
||||
if (!parsedURL || !server || (!equalUrlsIgnoringSubpath(server.url, parsedURL))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre process nonTeamUrlPaths
|
||||
let nonTeamUrlPaths = [
|
||||
'plugins',
|
||||
'signup',
|
||||
'login',
|
||||
'admin',
|
||||
'channel',
|
||||
'post',
|
||||
'oauth',
|
||||
'admin_console',
|
||||
];
|
||||
const managedResources = getManagedResources();
|
||||
nonTeamUrlPaths = nonTeamUrlPaths.concat(managedResources);
|
||||
const paths = [...getManagedResources(), ...nonTeamUrlPaths];
|
||||
|
||||
if (withApi) {
|
||||
nonTeamUrlPaths.push('api');
|
||||
paths.push('api');
|
||||
}
|
||||
return !(nonTeamUrlPaths.some((testPath) => (
|
||||
parsedURL.pathname.toLowerCase().startsWith(`${server.subpath}${testPath}/`) ||
|
||||
parsedURL.pathname.toLowerCase().startsWith(`/${testPath}/`))));
|
||||
return !(paths.some((testPath) => isUrlType(testPath, serverUrl, inputURL)));
|
||||
}
|
||||
|
||||
function isPluginUrl(serverUrl: URL | string, inputURL: URL | string) {
|
||||
const server = getServerInfo(serverUrl);
|
||||
const parsedURL = parseURL(inputURL);
|
||||
if (!parsedURL || !server) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
equalUrlsIgnoringSubpath(server.url, parsedURL) &&
|
||||
(parsedURL.pathname.toLowerCase().startsWith(`${server.subpath}plugins/`) ||
|
||||
parsedURL.pathname.toLowerCase().startsWith('/plugins/')));
|
||||
return isUrlType('plugins', serverUrl, inputURL);
|
||||
}
|
||||
|
||||
function isManagedResource(serverUrl: URL | string, inputURL: URL | string) {
|
||||
const server = getServerInfo(serverUrl);
|
||||
const parsedURL = parseURL(inputURL);
|
||||
if (!parsedURL || !server) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const managedResources = getManagedResources();
|
||||
|
||||
return (
|
||||
equalUrlsIgnoringSubpath(server.url, parsedURL) && managedResources && managedResources.length &&
|
||||
managedResources.some((managedResource) => (parsedURL.pathname.toLowerCase().startsWith(`${server.subpath}${managedResource}/`) || parsedURL.pathname.toLowerCase().startsWith(`/${managedResource}/`))));
|
||||
const paths = [...getManagedResources()];
|
||||
return paths.some((testPath) => isUrlType(testPath, serverUrl, inputURL));
|
||||
}
|
||||
|
||||
function getView(inputURL: URL | string, teams: TeamWithTabs[], ignoreScheme = false): ServerFromURL | undefined {
|
||||
|
@ -172,20 +127,27 @@ function getView(inputURL: URL | string, teams: TeamWithTabs[], ignoreScheme = f
|
|||
let secondOption;
|
||||
teams.forEach((team) => {
|
||||
const srv = new MattermostServer(team.name, team.url);
|
||||
team.tabs.forEach((tab) => {
|
||||
|
||||
// sort by length so that we match the highest specificity last
|
||||
const filteredTabs = team.tabs.map((tab) => {
|
||||
const tabView = getServerView(srv, tab);
|
||||
const parsedServerUrl = parseURL(tabView.url);
|
||||
if (parsedServerUrl) {
|
||||
return {tabView, parsedServerUrl};
|
||||
});
|
||||
|
||||
filteredTabs.sort((a, b) => a.tabView.url.toString().length - b.tabView.url.toString().length);
|
||||
filteredTabs.forEach((tab) => {
|
||||
if (tab.parsedServerUrl) {
|
||||
// check server and subpath matches (without subpath pathname is \ so it always matches)
|
||||
if (equalUrlsWithSubpath(parsedServerUrl, parsedURL, ignoreScheme)) {
|
||||
firstOption = {name: tabView.name, url: parsedServerUrl.toString()};
|
||||
if (getFormattedPathName(tab.parsedServerUrl.pathname) !== '/' && equalUrlsWithSubpath(tab.parsedServerUrl, parsedURL, ignoreScheme)) {
|
||||
firstOption = {name: tab.tabView.name, url: tab.parsedServerUrl.toString()};
|
||||
}
|
||||
if (equalUrlsIgnoringSubpath(parsedServerUrl, parsedURL, ignoreScheme)) {
|
||||
if (getFormattedPathName(tab.parsedServerUrl.pathname) === '/' && equalUrlsIgnoringSubpath(tab.parsedServerUrl, parsedURL, ignoreScheme)) {
|
||||
// in case the user added something on the path that doesn't really belong to the server
|
||||
// there might be more than one that matches, but we can't differentiate, so last one
|
||||
// is as good as any other in case there is no better match (e.g.: two subpath servers with the same origin)
|
||||
// e.g.: https://community.mattermost.com/core
|
||||
secondOption = {name: tabView.name, url: parsedServerUrl.toString()};
|
||||
secondOption = {name: tab.tabView.name, url: tab.parsedServerUrl.toString()};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -194,14 +156,14 @@ function getView(inputURL: URL | string, teams: TeamWithTabs[], ignoreScheme = f
|
|||
}
|
||||
|
||||
// next two functions are defined to clarify intent
|
||||
function equalUrlsWithSubpath(url1: URL, url2: URL, ignoreScheme?: boolean) {
|
||||
export function equalUrlsWithSubpath(url1: URL, url2: URL, ignoreScheme?: boolean) {
|
||||
if (ignoreScheme) {
|
||||
return url1.host === url2.host && url2.pathname.toLowerCase().startsWith(url1.pathname.toLowerCase());
|
||||
return url1.host === url2.host && getFormattedPathName(url2.pathname).startsWith(getFormattedPathName(url1.pathname));
|
||||
}
|
||||
return url1.origin === url2.origin && url2.pathname.toLowerCase().startsWith(url1.pathname.toLowerCase());
|
||||
return url1.origin === url2.origin && getFormattedPathName(url2.pathname).startsWith(getFormattedPathName(url1.pathname));
|
||||
}
|
||||
|
||||
function equalUrlsIgnoringSubpath(url1: URL, url2: URL, ignoreScheme?: boolean) {
|
||||
export function equalUrlsIgnoringSubpath(url1: URL, url2: URL, ignoreScheme?: boolean) {
|
||||
if (ignoreScheme) {
|
||||
return url1.host.toLowerCase() === url2.host.toLowerCase();
|
||||
}
|
||||
|
@ -227,7 +189,6 @@ function isCustomLoginURL(url: URL | string, server: ServerFromURL, teams: TeamW
|
|||
return false;
|
||||
}
|
||||
const urlPath = parsedURL.pathname;
|
||||
if (subpath !== '' && subpath !== '/' && urlPath.startsWith(subpath)) {
|
||||
const replacement = subpath.endsWith('/') ? '/' : '';
|
||||
const replacedPath = urlPath.replace(subpath, replacement);
|
||||
for (const regexPath of customLoginRegexPaths) {
|
||||
|
@ -235,19 +196,11 @@ function isCustomLoginURL(url: URL | string, server: ServerFromURL, teams: TeamW
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there is no subpath, or we are adding the team and got redirected to the real server it'll be caught here
|
||||
for (const regexPath of customLoginRegexPaths) {
|
||||
if (urlPath.match(regexPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
getDomain,
|
||||
isValidURL,
|
||||
isValidURI,
|
||||
isInternalURL,
|
||||
|
|
91
src/common/utils/util.test.js
Normal file
91
src/common/utils/util.test.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Utils from 'common/utils/util';
|
||||
|
||||
describe('common/utils/util', () => {
|
||||
describe('shorten', () => {
|
||||
it('should shorten based on max', () => {
|
||||
const string = '123456789012345678901234567890';
|
||||
expect(Utils.shorten(string, 10)).toBe('1234567...');
|
||||
});
|
||||
it('should use DEFAULT_MAX for max < 4', () => {
|
||||
const string = '123456789012345678901234567890';
|
||||
expect(Utils.shorten(string, 3)).toBe('12345678901234567...');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isVersionGreaterThanOrEqualTo', () => {
|
||||
test('should consider two empty versions as equal', () => {
|
||||
const a = '';
|
||||
const b = '';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should consider different strings without components as equal', () => {
|
||||
const a = 'not a server version';
|
||||
const b = 'also not a server version';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should consider different malformed versions normally (not greater than case)', () => {
|
||||
const a = '1.2.3';
|
||||
const b = '1.2.4';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(false);
|
||||
});
|
||||
|
||||
test('should consider different malformed versions normally (greater than case)', () => {
|
||||
const a = '1.2.4';
|
||||
const b = '1.2.3';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should work correctly for different numbers of digits', () => {
|
||||
const a = '10.0.1';
|
||||
const b = '4.8.0';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should consider an empty version as not greater than or equal', () => {
|
||||
const a = '';
|
||||
const b = '4.7.1.dev.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(false);
|
||||
});
|
||||
|
||||
test('should consider the same versions equal', () => {
|
||||
const a = '4.7.1.dev.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
const b = '4.7.1.dev.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should consider different release versions (not greater than case)', () => {
|
||||
const a = '4.7.0.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
const b = '4.7.1.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(false);
|
||||
});
|
||||
|
||||
test('should consider different release versions (greater than case)', () => {
|
||||
const a = '4.7.1.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
const b = '4.7.0.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should consider different build numbers unequal', () => {
|
||||
const a = '4.7.1.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
const b = '4.7.1.13.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(false);
|
||||
});
|
||||
|
||||
test('should ignore different config hashes', () => {
|
||||
const a = '4.7.1.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
const b = '4.7.1.12.c51676437bc02ada78f3a0a0a2203c61.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
|
||||
test('should ignore different licensed statuses', () => {
|
||||
const a = '4.7.1.13.c51676437bc02ada78f3a0a0a2203c60.false';
|
||||
const b = '4.7.1.12.c51676437bc02ada78f3a0a0a2203c60.true';
|
||||
expect(Utils.isVersionGreaterThanOrEqualTo(a, b)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import assert from 'assert';
|
||||
|
||||
import UserActivityMonitor from '../../../src/main/UserActivityMonitor';
|
||||
import UserActivityMonitor from './UserActivityMonitor';
|
||||
|
||||
describe('UserActivityMonitor', () => {
|
||||
describe('updateIdleTime', () => {
|
||||
|
@ -10,7 +9,7 @@ describe('UserActivityMonitor', () => {
|
|||
const userActivityMonitor = new UserActivityMonitor();
|
||||
const idleTime = Math.round(Date.now() / 1000);
|
||||
userActivityMonitor.updateIdleTime(idleTime);
|
||||
assert.equal(userActivityMonitor.userIdleTime, idleTime);
|
||||
expect(userActivityMonitor.userIdleTime).toBe(idleTime);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -23,11 +22,11 @@ describe('UserActivityMonitor', () => {
|
|||
|
||||
it('should set user status to active', () => {
|
||||
userActivityMonitor.setActivityState(true);
|
||||
assert.equal(userActivityMonitor.userIsActive, true);
|
||||
expect(userActivityMonitor.userIsActive).toBe(true);
|
||||
});
|
||||
it('should set user status to inactive', () => {
|
||||
userActivityMonitor.setActivityState(false);
|
||||
assert.equal(userActivityMonitor.userIsActive, false);
|
||||
expect(userActivityMonitor.userIsActive).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -40,28 +39,28 @@ describe('UserActivityMonitor', () => {
|
|||
|
||||
it('should emit a non-system triggered status event indicating a user is active', () => {
|
||||
userActivityMonitor.on('status', ({userIsActive, isSystemEvent}) => {
|
||||
assert.equal(userIsActive && !isSystemEvent, true);
|
||||
expect(userIsActive && !isSystemEvent).toBe(true);
|
||||
});
|
||||
userActivityMonitor.setActivityState(true, false);
|
||||
});
|
||||
|
||||
it('should emit a non-system triggered status event indicating a user is inactive', () => {
|
||||
userActivityMonitor.on('status', ({userIsActive, isSystemEvent}) => {
|
||||
assert.equal(!userIsActive && !isSystemEvent, true);
|
||||
expect(!userIsActive && !isSystemEvent).toBe(true);
|
||||
});
|
||||
userActivityMonitor.setActivityState(false, false);
|
||||
});
|
||||
|
||||
it('should emit a system triggered status event indicating a user is active', () => {
|
||||
userActivityMonitor.on('status', ({userIsActive, isSystemEvent}) => {
|
||||
assert.equal(userIsActive && isSystemEvent, true);
|
||||
expect(userIsActive && isSystemEvent).toBe(true);
|
||||
});
|
||||
userActivityMonitor.setActivityState(true, true);
|
||||
});
|
||||
|
||||
it('should emit a system triggered status event indicating a user is inactive', () => {
|
||||
userActivityMonitor.on('status', ({userIsActive, isSystemEvent}) => {
|
||||
assert.equal(!userIsActive && isSystemEvent, true);
|
||||
expect(!userIsActive && isSystemEvent).toBe(true);
|
||||
});
|
||||
userActivityMonitor.setActivityState(false, true);
|
||||
});
|
|
@ -1,12 +1,14 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import {app, Notification} from 'electron';
|
||||
|
||||
import {MentionOptions} from 'types/notification';
|
||||
|
||||
import osVersion from 'common/osVersion';
|
||||
import Utils from 'common/utils/util';
|
||||
|
||||
const assetsDir = path.resolve(app.getAppPath(), 'assets');
|
||||
const appIconURL = path.resolve(assetsDir, 'appicon_48.png');
|
||||
|
@ -30,7 +32,7 @@ export class Mention extends Notification {
|
|||
// Notification Center shows app's icon, so there were two icons on the notification.
|
||||
Reflect.deleteProperty(options, 'icon');
|
||||
}
|
||||
const isWin7 = (process.platform === 'win32' && osVersion.isLowerThanOrEqualWindows8_1() && DEFAULT_WIN7);
|
||||
const isWin7 = (process.platform === 'win32' && !Utils.isVersionGreaterThanOrEqualTo(os.version(), '6.3') && DEFAULT_WIN7);
|
||||
const customSound = String(!options.silent && ((options.data && options.data.soundName !== 'None' && options.data.soundName) || isWin7));
|
||||
if (customSound) {
|
||||
options.silent = true;
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
// See LICENSE.txt for license information.
|
||||
'use strict';
|
||||
|
||||
import assert from 'assert';
|
||||
import TrustedOriginsStore from 'main/trustedOrigins';
|
||||
import {BASIC_AUTH_PERMISSION} from 'common/permissions';
|
||||
|
||||
import TrustedOriginsStore from 'main/trustedOrigins.ts';
|
||||
import {BASIC_AUTH_PERMISSION} from 'common/permissions.ts';
|
||||
jest.mock('electron-log', () => ({
|
||||
error: jest.fn(),
|
||||
}));
|
||||
|
||||
function mockTOS(fileName, returnvalue) {
|
||||
const tos = new TrustedOriginsStore(fileName);
|
||||
|
@ -20,24 +22,28 @@ describe('Trusted Origins', () => {
|
|||
it('should be empty if there is no file', () => {
|
||||
const tos = mockTOS('emptyfile', null);
|
||||
tos.load();
|
||||
assert.deepEqual(tos.data.size, 0);
|
||||
expect(tos.data.size).toStrictEqual(0);
|
||||
});
|
||||
|
||||
it('should throw an error if data isn\'t an object', () => {
|
||||
const tos = mockTOS('notobject', 'this is not my object!');
|
||||
|
||||
assert.throws(tos.load, SyntaxError);
|
||||
expect(() => {
|
||||
tos.load();
|
||||
}).toThrow(SyntaxError);
|
||||
});
|
||||
|
||||
it('should throw an error if data isn\'t in the expected format', () => {
|
||||
const tos = mockTOS('badobject', '{"https://mattermost.com": "this is not my object!"}');
|
||||
assert.throws(tos.load, /^Error: Provided TrustedOrigins file does not validate, using defaults instead\.$/);
|
||||
expect(() => {
|
||||
tos.load();
|
||||
}).toThrow(/^Provided TrustedOrigins file does not validate, using defaults instead\.$/);
|
||||
});
|
||||
|
||||
it('should drop keys that aren\'t urls', () => {
|
||||
const tos = mockTOS('badobject2', `{"this is not an uri": {"${BASIC_AUTH_PERMISSION}": true}}`);
|
||||
tos.load();
|
||||
assert.equal(typeof tos.data['this is not an uri'], 'undefined');
|
||||
expect(typeof tos.data['this is not an uri']).toBe('undefined');
|
||||
});
|
||||
|
||||
it('should contain valid data if everything goes right', () => {
|
||||
|
@ -47,7 +53,7 @@ describe('Trusted Origins', () => {
|
|||
}};
|
||||
const tos = mockTOS('okfile', JSON.stringify(value));
|
||||
tos.load();
|
||||
assert.deepEqual(Object.fromEntries(tos.data.entries()), value);
|
||||
expect(Object.fromEntries(tos.data.entries())).toStrictEqual(value);
|
||||
});
|
||||
});
|
||||
describe('validate testing permissions', () => {
|
||||
|
@ -62,19 +68,19 @@ describe('Trusted Origins', () => {
|
|||
const tos = mockTOS('permission_test', JSON.stringify(value));
|
||||
tos.load();
|
||||
it('tos should contain 2 elements', () => {
|
||||
assert.equal(tos.data.size, 2);
|
||||
expect(tos.data.size).toBe(2);
|
||||
});
|
||||
it('should say ok if the permission is set', () => {
|
||||
assert.equal(tos.checkPermission('https://mattermost.com', BASIC_AUTH_PERMISSION), true);
|
||||
expect(tos.checkPermission('https://mattermost.com', BASIC_AUTH_PERMISSION)).toBe(true);
|
||||
});
|
||||
it('should say ko if the permission is set to false', () => {
|
||||
assert.equal(tos.checkPermission('https://notmattermost.com', BASIC_AUTH_PERMISSION), false);
|
||||
expect(tos.checkPermission('https://notmattermost.com', BASIC_AUTH_PERMISSION)).toBe(false);
|
||||
});
|
||||
it('should say ko if the uri is not set', () => {
|
||||
assert.equal(tos.checkPermission('https://undefined.com', BASIC_AUTH_PERMISSION), null);
|
||||
expect(tos.checkPermission('https://undefined.com', BASIC_AUTH_PERMISSION)).toBe(undefined);
|
||||
});
|
||||
it('should say null if the permission is unknown', () => {
|
||||
assert.equal(tos.checkPermission('https://mattermost.com'), null);
|
||||
expect(tos.checkPermission('https://mattermost.com')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -90,9 +96,9 @@ describe('Trusted Origins', () => {
|
|||
const tos = mockTOS('permission_test', JSON.stringify(value));
|
||||
tos.load();
|
||||
it('deleting revokes access', () => {
|
||||
assert.equal(tos.checkPermission('https://mattermost.com', BASIC_AUTH_PERMISSION), true);
|
||||
expect(tos.checkPermission('https://mattermost.com', BASIC_AUTH_PERMISSION)).toBe(true);
|
||||
tos.delete('https://mattermost.com');
|
||||
assert.equal(tos.checkPermission('https://mattermost.com', BASIC_AUTH_PERMISSION), null);
|
||||
expect(tos.checkPermission('https://mattermost.com', BASIC_AUTH_PERMISSION)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -304,7 +304,7 @@ export class MattermostView extends EventEmitter {
|
|||
}
|
||||
|
||||
handleUpdateTarget = (e: Event, url: string) => {
|
||||
if (!url || !this.tab.server.sameOrigin(url)) {
|
||||
if (!url || !urlUtils.isInternalURL(new URL(url), this.tab.server.url)) {
|
||||
this.emit(UPDATE_TARGET_URL, url);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue