206 lines
6.8 KiB
TypeScript
206 lines
6.8 KiB
TypeScript
|
// Copyright 2023 Signal Messenger, LLC
|
||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||
|
import { assert } from 'chai';
|
||
|
import type { ParsedSignalRoute } from '../../util/signalRoutes';
|
||
|
import {
|
||
|
isSignalRoute,
|
||
|
parseSignalRoute,
|
||
|
toSignalRouteAppUrl,
|
||
|
toSignalRouteUrl,
|
||
|
toSignalRouteWebUrl,
|
||
|
} from '../../util/signalRoutes';
|
||
|
|
||
|
describe('signalRoutes', () => {
|
||
|
type CheckConfig = {
|
||
|
hasAppUrl: boolean;
|
||
|
hasWebUrl: boolean;
|
||
|
isRoute: boolean;
|
||
|
};
|
||
|
|
||
|
function createCheck(options: Partial<CheckConfig> = {}) {
|
||
|
const config: CheckConfig = {
|
||
|
hasAppUrl: true,
|
||
|
hasWebUrl: true,
|
||
|
isRoute: true,
|
||
|
...options,
|
||
|
};
|
||
|
// Different than `isRoute` because of normalization
|
||
|
const hasRouteUrl = config.hasAppUrl || config.hasWebUrl;
|
||
|
return function check(input: string, expected: ParsedSignalRoute | null) {
|
||
|
const url = new URL(input);
|
||
|
assert.deepEqual(parseSignalRoute(url), expected);
|
||
|
assert.deepEqual(isSignalRoute(url), config.isRoute);
|
||
|
assert.deepEqual(toSignalRouteUrl(url) != null, hasRouteUrl);
|
||
|
assert.deepEqual(toSignalRouteAppUrl(url) != null, config.hasAppUrl);
|
||
|
assert.deepEqual(toSignalRouteWebUrl(url) != null, config.hasWebUrl);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
it('nonsense', () => {
|
||
|
const check = createCheck({
|
||
|
isRoute: false,
|
||
|
hasAppUrl: false,
|
||
|
hasWebUrl: false,
|
||
|
});
|
||
|
// Charles Entertainment Cheese, what are you doing here?
|
||
|
check('https://www.chuckecheese.com/#p/+1234567890', null);
|
||
|
// Non-route signal urls
|
||
|
check('https://signal.me', null);
|
||
|
check('sgnl://signal.me/#p', null);
|
||
|
check('sgnl://signal.me/#p/', null);
|
||
|
check('sgnl://signal.me/p/+1234567890', null);
|
||
|
check('https://signal.me/?p/+1234567890', null);
|
||
|
});
|
||
|
|
||
|
it('normalize', () => {
|
||
|
const check = createCheck({ isRoute: false, hasAppUrl: true });
|
||
|
check('http://username:password@signal.me:8888/#p/+1234567890', null);
|
||
|
});
|
||
|
|
||
|
it('contactByPhoneNumber', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'contactByPhoneNumber',
|
||
|
args: { phoneNumber: '+1234567890' },
|
||
|
};
|
||
|
const check = createCheck();
|
||
|
check('https://signal.me/#p/+1234567890', result);
|
||
|
check('https://signal.me#p/+1234567890', result);
|
||
|
check('sgnl://signal.me/#p/+1234567890', result);
|
||
|
check('sgnl://signal.me#p/+1234567890', result);
|
||
|
});
|
||
|
|
||
|
it('contactByEncryptedUsername', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'contactByEncryptedUsername',
|
||
|
args: { encryptedUsername: 'foobar' },
|
||
|
};
|
||
|
const check = createCheck();
|
||
|
check('https://signal.me/#eu/foobar', result);
|
||
|
check('https://signal.me#eu/foobar', result);
|
||
|
check('sgnl://signal.me/#eu/foobar', result);
|
||
|
check('sgnl://signal.me#eu/foobar', result);
|
||
|
});
|
||
|
|
||
|
it('groupInvites', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'groupInvites',
|
||
|
args: { inviteCode: 'foobar' },
|
||
|
};
|
||
|
const check = createCheck();
|
||
|
check('https://signal.group/#foobar', result);
|
||
|
check('https://signal.group#foobar', result);
|
||
|
check('sgnl://signal.group/#foobar', result);
|
||
|
check('sgnl://signal.group#foobar', result);
|
||
|
check('sgnl://joingroup/#foobar', result);
|
||
|
check('sgnl://joingroup#foobar', result);
|
||
|
});
|
||
|
|
||
|
it('linkDevice', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'linkDevice',
|
||
|
args: { uuid: 'foo', pubKey: 'bar' },
|
||
|
};
|
||
|
const check = createCheck({ hasWebUrl: false });
|
||
|
check('sgnl://linkdevice/?uuid=foo&pub_key=bar', result);
|
||
|
check('sgnl://linkdevice?uuid=foo&pub_key=bar', result);
|
||
|
});
|
||
|
|
||
|
it('captcha', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'captcha',
|
||
|
args: { captchaId: 'foobar' },
|
||
|
};
|
||
|
const check = createCheck({ hasWebUrl: false });
|
||
|
check('signalcaptcha://foobar', result);
|
||
|
});
|
||
|
|
||
|
it('linkCall', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'linkCall',
|
||
|
args: { key: 'foobar' },
|
||
|
};
|
||
|
const check = createCheck();
|
||
|
check('https://signal.link/call/#key=foobar', result);
|
||
|
check('https://signal.link/call#key=foobar', result);
|
||
|
check('sgnl://signal.link/call/#key=foobar', result);
|
||
|
check('sgnl://signal.link/call#key=foobar', result);
|
||
|
});
|
||
|
|
||
|
it('artAuth', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'artAuth',
|
||
|
args: { token: 'foo', pubKey: 'bar' },
|
||
|
};
|
||
|
const check = createCheck({ hasWebUrl: false });
|
||
|
check('sgnl://art-auth/?token=foo&pub_key=bar', result);
|
||
|
check('sgnl://art-auth?token=foo&pub_key=bar', result);
|
||
|
});
|
||
|
|
||
|
it('artAddStickers', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'artAddStickers',
|
||
|
args: { packId: 'foo', packKey: 'bar' },
|
||
|
};
|
||
|
const check = createCheck();
|
||
|
check('https://signal.art/addstickers/#pack_id=foo&pack_key=bar', result);
|
||
|
check('https://signal.art/addstickers#pack_id=foo&pack_key=bar', result);
|
||
|
check('sgnl://addstickers/?pack_id=foo&pack_key=bar', result);
|
||
|
check('sgnl://addstickers?pack_id=foo&pack_key=bar', result);
|
||
|
});
|
||
|
|
||
|
it('showConversation', () => {
|
||
|
const check = createCheck({ isRoute: true, hasWebUrl: false });
|
||
|
const args1 = 'conversationId=abc';
|
||
|
const args2 = 'conversationId=abc&messageId=def';
|
||
|
const args3 = 'conversationId=abc&messageId=def&storyId=ghi';
|
||
|
const result1: ParsedSignalRoute = {
|
||
|
key: 'showConversation',
|
||
|
args: { conversationId: 'abc', messageId: null, storyId: null },
|
||
|
};
|
||
|
const result2: ParsedSignalRoute = {
|
||
|
key: 'showConversation',
|
||
|
args: { conversationId: 'abc', messageId: 'def', storyId: null },
|
||
|
};
|
||
|
const result3: ParsedSignalRoute = {
|
||
|
key: 'showConversation',
|
||
|
args: { conversationId: 'abc', messageId: 'def', storyId: 'ghi' },
|
||
|
};
|
||
|
check(`sgnl://show-conversation/?${args1}`, result1);
|
||
|
check(`sgnl://show-conversation?${args1}`, result1);
|
||
|
check(`sgnl://show-conversation/?${args2}`, result2);
|
||
|
check(`sgnl://show-conversation?${args2}`, result2);
|
||
|
check(`sgnl://show-conversation/?${args3}`, result3);
|
||
|
check(`sgnl://show-conversation?${args3}`, result3);
|
||
|
});
|
||
|
|
||
|
it('startCallLobby', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'startCallLobby',
|
||
|
args: { conversationId: 'abc' },
|
||
|
};
|
||
|
const check = createCheck({ isRoute: true, hasWebUrl: false });
|
||
|
check('sgnl://start-call-lobby/?conversationId=abc', result);
|
||
|
check('sgnl://start-call-lobby?conversationId=abc', result);
|
||
|
});
|
||
|
|
||
|
it('showWindow', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'showWindow',
|
||
|
args: {},
|
||
|
};
|
||
|
const check = createCheck({ isRoute: true, hasWebUrl: false });
|
||
|
check('sgnl://show-window/', result);
|
||
|
check('sgnl://show-window', result);
|
||
|
});
|
||
|
|
||
|
it('setIsPresenting', () => {
|
||
|
const result: ParsedSignalRoute = {
|
||
|
key: 'setIsPresenting',
|
||
|
args: {},
|
||
|
};
|
||
|
const check = createCheck({ isRoute: true, hasWebUrl: false });
|
||
|
check('sgnl://set-is-presenting/', result);
|
||
|
check('sgnl://set-is-presenting', result);
|
||
|
});
|
||
|
});
|