parseContact: Be resilient to invalid phone numbers
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
parent
f0d112fa1b
commit
5abf21789c
4 changed files with 52 additions and 20 deletions
|
@ -88,7 +88,7 @@ describe('timestamp', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formats month name, day of month, year, and time for other times', () => {
|
it('formats month name, day of month, year, and time for other times', () => {
|
||||||
const rx = /Apr 20, 2000, \d+:\d+ [A|P]M/;
|
const rx = /Apr (19|20|21), 2000, \d+:\d+ [A|P]M/;
|
||||||
const datetime = formatDateTimeLong(i18n, new Date(956216013000));
|
const datetime = formatDateTimeLong(i18n, new Date(956216013000));
|
||||||
assert.isTrue(rx.test(datetime));
|
assert.isTrue(rx.test(datetime));
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,9 +10,11 @@ import type { MessageAttributesType } from '../../model-types.d';
|
||||||
import type { Avatar, Email, Phone } from '../../types/EmbeddedContact';
|
import type { Avatar, Email, Phone } from '../../types/EmbeddedContact';
|
||||||
import {
|
import {
|
||||||
_validate,
|
_validate,
|
||||||
|
ContactFormType,
|
||||||
embeddedContactSelector,
|
embeddedContactSelector,
|
||||||
getName,
|
getName,
|
||||||
parseAndWriteAvatar,
|
parseAndWriteAvatar,
|
||||||
|
parsePhoneItem,
|
||||||
} from '../../types/EmbeddedContact';
|
} from '../../types/EmbeddedContact';
|
||||||
import { fakeAttachment } from '../../test-both/helpers/fakeAttachment';
|
import { fakeAttachment } from '../../test-both/helpers/fakeAttachment';
|
||||||
import { generateAci } from '../../types/ServiceId';
|
import { generateAci } from '../../types/ServiceId';
|
||||||
|
@ -632,6 +634,48 @@ describe('Contact', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('parsePhoneItem', () => {
|
||||||
|
it('adds default phone type', () => {
|
||||||
|
const phone: Phone = {
|
||||||
|
value: '+18005550000',
|
||||||
|
// @ts-expect-error Forcing an invalid value here
|
||||||
|
type: null,
|
||||||
|
};
|
||||||
|
const expected = {
|
||||||
|
value: '+18005550000',
|
||||||
|
type: ContactFormType.HOME,
|
||||||
|
};
|
||||||
|
const actual = parsePhoneItem(phone, { regionCode: '805' });
|
||||||
|
assert.deepEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes invalid phone numbers through', () => {
|
||||||
|
const phone: Phone = {
|
||||||
|
value: '+1800555u000',
|
||||||
|
type: ContactFormType.WORK,
|
||||||
|
};
|
||||||
|
const expected = {
|
||||||
|
value: '+1800555u000',
|
||||||
|
type: ContactFormType.WORK,
|
||||||
|
};
|
||||||
|
const actual = parsePhoneItem(phone, { regionCode: '805' });
|
||||||
|
assert.deepEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns original data if regionCode not provided', () => {
|
||||||
|
const phone: Phone = {
|
||||||
|
value: '+18005550000',
|
||||||
|
type: ContactFormType.MOBILE,
|
||||||
|
};
|
||||||
|
const expected = {
|
||||||
|
value: '+18005550000',
|
||||||
|
type: ContactFormType.MOBILE,
|
||||||
|
};
|
||||||
|
const actual = parsePhoneItem(phone, { regionCode: undefined });
|
||||||
|
assert.deepEqual(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('_validate', () => {
|
describe('_validate', () => {
|
||||||
it('returns error if contact has no name.displayName or organization', () => {
|
it('returns error if contact has no name.displayName or organization', () => {
|
||||||
const messageId = 'the-message-id';
|
const messageId = 'the-message-id';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import type { ReadonlyMessageAttributesType } from '../model-types.d';
|
||||||
import { isNotNil } from '../util/isNotNil';
|
import { isNotNil } from '../util/isNotNil';
|
||||||
import {
|
import {
|
||||||
format as formatPhoneNumber,
|
format as formatPhoneNumber,
|
||||||
parse as parsePhoneNumber,
|
normalize as normalizePhoneNumber,
|
||||||
} from './PhoneNumber';
|
} from './PhoneNumber';
|
||||||
import type {
|
import type {
|
||||||
AttachmentType,
|
AttachmentType,
|
||||||
|
@ -317,7 +317,7 @@ export function _validate(
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePhoneItem(
|
export function parsePhoneItem(
|
||||||
item: Phone,
|
item: Phone,
|
||||||
{ regionCode }: { regionCode: string | undefined }
|
{ regionCode }: { regionCode: string | undefined }
|
||||||
): Phone | undefined {
|
): Phone | undefined {
|
||||||
|
@ -325,10 +325,14 @@ function parsePhoneItem(
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const value = regionCode
|
||||||
|
? normalizePhoneNumber(item.value, { regionCode })
|
||||||
|
: item.value;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
type: item.type || DEFAULT_PHONE_TYPE,
|
type: item.type || DEFAULT_PHONE_TYPE,
|
||||||
value: parsePhoneNumber(item.value, { regionCode }),
|
value: value ?? item.value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,22 +71,6 @@ export const format = memoizee(_format, {
|
||||||
max: 5000,
|
max: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function parse(
|
|
||||||
phoneNumber: string,
|
|
||||||
options: {
|
|
||||||
regionCode: string | undefined;
|
|
||||||
}
|
|
||||||
): string {
|
|
||||||
const { regionCode } = options;
|
|
||||||
const parsedNumber = instance.parse(phoneNumber, regionCode);
|
|
||||||
|
|
||||||
if (instance.isValidNumber(parsedNumber)) {
|
|
||||||
return instance.format(parsedNumber, PhoneNumberFormat.E164);
|
|
||||||
}
|
|
||||||
|
|
||||||
return phoneNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function normalize(
|
export function normalize(
|
||||||
phoneNumber: string,
|
phoneNumber: string,
|
||||||
options: { regionCode: string }
|
options: { regionCode: string }
|
||||||
|
|
Loading…
Add table
Reference in a new issue