Refactor Signal app routing
This commit is contained in:
parent
86e6c2499c
commit
3ef0d221d1
28 changed files with 1347 additions and 1044 deletions
205
ts/test-node/util/signalRoutes_test.ts
Normal file
205
ts/test-node/util/signalRoutes_test.ts
Normal file
|
@ -0,0 +1,205 @@
|
|||
// 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);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue