diff --git a/.eslintignore b/.eslintignore index 7f6c39a2c2fb..20ed14d2b0d4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -19,7 +19,6 @@ sticker-creator/dist/** # Third-party files js/Mp3LameEncoder.min.js js/WebAudioRecorderMp3.js -js/libphonenumber-util.js # TypeScript generated files app/**/*.js diff --git a/js/libphonenumber-util.js b/js/libphonenumber-util.js deleted file mode 100644 index 57e4155ccd77..000000000000 --- a/js/libphonenumber-util.js +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2014-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -(function () { - 'use strict'; - - /* - * This file extends the libphonenumber object with a set of phonenumbery - * utility functions. libphonenumber must be included before you call these - * functions, but the order of the files/script-tags doesn't matter. - */ - - window.libphonenumber = window.libphonenumber || {}; - window.libphonenumber.util = { - getRegionCodeForNumber: function (number) { - try { - var parsedNumber = libphonenumber.parse(number); - return libphonenumber.getRegionCodeForNumber(parsedNumber); - } catch (e) { - return 'ZZ'; - } - }, - - splitCountryCode: function (number) { - var parsedNumber = libphonenumber.parse(number); - return { - country_code: parsedNumber.values_[1], - national_number: parsedNumber.values_[2], - }; - }, - - getCountryCode: function (regionCode) { - var cc = libphonenumber.getCountryCodeForRegion(regionCode); - return cc !== 0 ? cc : ''; - }, - - parseNumber: function (number, defaultRegionCode) { - try { - var parsedNumber = libphonenumber.parse(number, defaultRegionCode); - - return { - isValidNumber: libphonenumber.isValidNumber(parsedNumber), - regionCode: libphonenumber.getRegionCodeForNumber(parsedNumber), - countryCode: '' + parsedNumber.getCountryCode(), - nationalNumber: '' + parsedNumber.getNationalNumber(), - e164: libphonenumber.format( - parsedNumber, - libphonenumber.PhoneNumberFormat.E164 - ), - }; - } catch (ex) { - return { error: ex, isValidNumber: false }; - } - }, - - getAllRegionCodes: function () { - return { - AD: 'Andorra', - AE: 'United Arab Emirates', - AF: 'Afghanistan', - AG: 'Antigua and Barbuda', - AI: 'Anguilla', - AL: 'Albania', - AM: 'Armenia', - AO: 'Angola', - AR: 'Argentina', - AS: 'AmericanSamoa', - AT: 'Austria', - AU: 'Australia', - AW: 'Aruba', - AX: 'Åland Islands', - AZ: 'Azerbaijan', - BA: 'Bosnia and Herzegovina', - BB: 'Barbados', - BD: 'Bangladesh', - BE: 'Belgium', - BF: 'Burkina Faso', - BG: 'Bulgaria', - BH: 'Bahrain', - BI: 'Burundi', - BJ: 'Benin', - BL: 'Saint Barthélemy', - BM: 'Bermuda', - BN: 'Brunei Darussalam', - BO: 'Bolivia, Plurinational State of', - BR: 'Brazil', - BS: 'Bahamas', - BT: 'Bhutan', - BW: 'Botswana', - BY: 'Belarus', - BZ: 'Belize', - CA: 'Canada', - CC: 'Cocos (Keeling) Islands', - CD: 'Congo, The Democratic Republic of the', - CF: 'Central African Republic', - CG: 'Congo', - CH: 'Switzerland', - CI: "Cote d'Ivoire", - CK: 'Cook Islands', - CL: 'Chile', - CM: 'Cameroon', - CN: 'China', - CO: 'Colombia', - CR: 'Costa Rica', - CU: 'Cuba', - CV: 'Cape Verde', - CX: 'Christmas Island', - CY: 'Cyprus', - CZ: 'Czech Republic', - DE: 'Germany', - DJ: 'Djibouti', - DK: 'Denmark', - DM: 'Dominica', - DO: 'Dominican Republic', - DZ: 'Algeria', - EC: 'Ecuador', - EE: 'Estonia', - EG: 'Egypt', - ER: 'Eritrea', - ES: 'Spain', - ET: 'Ethiopia', - FI: 'Finland', - FJ: 'Fiji', - FK: 'Falkland Islands (Malvinas)', - FM: 'Micronesia, Federated States of', - FO: 'Faroe Islands', - FR: 'France', - GA: 'Gabon', - GB: 'United Kingdom', - GD: 'Grenada', - GE: 'Georgia', - GF: 'French Guiana', - GG: 'Guernsey', - GH: 'Ghana', - GI: 'Gibraltar', - GL: 'Greenland', - GM: 'Gambia', - GN: 'Guinea', - GP: 'Guadeloupe', - GQ: 'Equatorial Guinea', - GR: 'Ελλάδα', - GT: 'Guatemala', - GU: 'Guam', - GW: 'Guinea-Bissau', - GY: 'Guyana', - HK: 'Hong Kong', - HN: 'Honduras', - HR: 'Croatia', - HT: 'Haiti', - HU: 'Magyarország', - ID: 'Indonesia', - IE: 'Ireland', - IL: 'Israel', - IM: 'Isle of Man', - IN: 'India', - IO: 'British Indian Ocean Territory', - IQ: 'Iraq', - IR: 'Iran, Islamic Republic of', - IS: 'Iceland', - IT: 'Italy', - JE: 'Jersey', - JM: 'Jamaica', - JO: 'Jordan', - JP: 'Japan', - KE: 'Kenya', - KG: 'Kyrgyzstan', - KH: 'Cambodia', - KI: 'Kiribati', - KM: 'Comoros', - KN: 'Saint Kitts and Nevis', - KP: "Korea, Democratic People's Republic of", - KR: 'Korea, Republic of', - KW: 'Kuwait', - KY: 'Cayman Islands', - KZ: 'Kazakhstan', - LA: "Lao People's Democratic Republic", - LB: 'Lebanon', - LC: 'Saint Lucia', - LI: 'Liechtenstein', - LK: 'Sri Lanka', - LR: 'Liberia', - LS: 'Lesotho', - LT: 'Lithuania', - LU: 'Luxembourg', - LV: 'Latvia', - LY: 'Libyan Arab Jamahiriya', - MA: 'Morocco', - MC: 'Monaco', - MD: 'Moldova, Republic of', - ME: 'Црна Гора', - MF: 'Saint Martin', - MG: 'Madagascar', - MH: 'Marshall Islands', - MK: 'Macedonia, The Former Yugoslav Republic of', - ML: 'Mali', - MM: 'Myanmar', - MN: 'Mongolia', - MO: 'Macao', - MP: 'Northern Mariana Islands', - MQ: 'Martinique', - MR: 'Mauritania', - MS: 'Montserrat', - MT: 'Malta', - MU: 'Mauritius', - MV: 'Maldives', - MW: 'Malawi', - MX: 'Mexico', - MY: 'Malaysia', - MZ: 'Mozambique', - NA: 'Namibia', - NC: 'New Caledonia', - NE: 'Niger', - NF: 'Norfolk Island', - NG: 'Nigeria', - NI: 'Nicaragua', - NL: 'Netherlands', - NO: 'Norway', - NP: 'Nepal', - NR: 'Nauru', - NU: 'Niue', - NZ: 'New Zealand', - OM: 'Oman', - PA: 'Panama', - PE: 'Peru', - PF: 'French Polynesia', - PG: 'Papua New Guinea', - PH: 'Philippines', - PK: 'Pakistan', - PL: 'Polska', - PM: 'Saint Pierre and Miquelon', - PR: 'Puerto Rico', - PS: 'Palestinian Territory, Occupied', - PT: 'Portugal', - PW: 'Palau', - PY: 'Paraguay', - QA: 'Qatar', - RE: 'Réunion', - RO: 'Romania', - RS: 'Србија', - RU: 'Russia', - RW: 'Rwanda', - SA: 'Saudi Arabia', - SB: 'Solomon Islands', - SC: 'Seychelles', - SD: 'Sudan', - SE: 'Sweden', - SG: 'Singapore', - SH: 'Saint Helena, Ascension and Tristan Da Cunha', - SI: 'Slovenia', - SJ: 'Svalbard and Jan Mayen', - SK: 'Slovakia', - SL: 'Sierra Leone', - SM: 'San Marino', - SN: 'Senegal', - SO: 'Somalia', - SR: 'Suriname', - ST: 'Sao Tome and Principe', - SV: 'El Salvador', - SY: 'Syrian Arab Republic', - SZ: 'Swaziland', - TC: 'Turks and Caicos Islands', - TD: 'Chad', - TG: 'Togo', - TH: 'Thailand', - TJ: 'Tajikistan', - TK: 'Tokelau', - TL: 'Timor-Leste', - TM: 'Turkmenistan', - TN: 'Tunisia', - TO: 'Tonga', - TR: 'Turkey', - TT: 'Trinidad and Tobago', - TV: 'Tuvalu', - TW: 'Taiwan, Province of China', - TZ: 'Tanzania, United Republic of', - UA: 'Ukraine', - UG: 'Uganda', - US: 'United States', - UY: 'Uruguay', - UZ: 'Uzbekistan', - VA: 'Holy See (Vatican City State)', - VC: 'Saint Vincent and the Grenadines', - VE: 'Venezuela', - VG: 'Virgin Islands, British', - VI: 'Virgin Islands, U.S.', - VN: 'Viet Nam', - VU: 'Vanuatu', - WF: 'Wallis and Futuna', - WS: 'Samoa', - YE: 'Yemen', - YT: 'Mayotte', - ZA: 'South Africa', - ZM: 'Zambia', - ZW: 'Zimbabwe', - }; - }, // getAllRegionCodes - }; // libphonenumber.util -})(); diff --git a/test/index.html b/test/index.html index fd4cfec134db..2a7763c939a4 100644 --- a/test/index.html +++ b/test/index.html @@ -107,7 +107,6 @@ - diff --git a/ts/components/StandaloneRegistration.tsx b/ts/components/StandaloneRegistration.tsx index ce6cfd250d20..b8340c04aaa4 100644 --- a/ts/components/StandaloneRegistration.tsx +++ b/ts/components/StandaloneRegistration.tsx @@ -1,4 +1,4 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { ChangeEvent } from 'react'; @@ -7,6 +7,7 @@ import type { Plugin } from 'intl-tel-input'; import intlTelInput from 'intl-tel-input'; import { strictAssert } from '../util/assert'; +import { parseNumber } from '../util/libphonenumberUtil'; import { getChallengeURL } from '../challenge'; const PhoneInput = ({ @@ -42,10 +43,7 @@ const PhoneInput = ({ const regionCode = plugin.getSelectedCountryData().iso2; - const parsedNumber = window.libphonenumber.util.parseNumber( - number, - regionCode - ); + const parsedNumber = parseNumber(number, regionCode); setIsValid(parsedNumber.isValidNumber); onValidation(parsedNumber.isValidNumber); diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 6fcfe0941b2c..f66a706d5ee8 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -19,6 +19,10 @@ import type { } from '../model-types.d'; import { getInitials } from '../util/getInitials'; import { normalizeUuid } from '../util/normalizeUuid'; +import { + getRegionCodeForNumber, + parseNumber, +} from '../util/libphonenumberUtil'; import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary'; import type { AttachmentType } from '../types/Attachment'; import { isGIF } from '../types/Attachment'; @@ -3406,7 +3410,7 @@ export class ConversationModel extends window.Backbone if (!regionCode) { throw new Error('No region code'); } - const number = window.libphonenumber.util.parseNumber( + const number = parseNumber( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.get('e164')!, regionCode @@ -5017,8 +5021,7 @@ export class ConversationModel extends window.Backbone const number = this.get('e164')!; try { const parsedNumber = window.libphonenumber.parse(number); - const regionCode = - window.libphonenumber.getRegionCodeForNumber(parsedNumber); + const regionCode = getRegionCodeForNumber(parsedNumber); if (regionCode === window.storage.get('regionCode')) { return window.libphonenumber.format( parsedNumber, diff --git a/test/libphonenumber_util_test.js b/ts/test-both/util/libphonenumberUtil_test.ts similarity index 59% rename from test/libphonenumber_util_test.js rename to ts/test-both/util/libphonenumberUtil_test.ts index 4c9effae24f1..85c53acd0491 100644 --- a/test/libphonenumber_util_test.js +++ b/ts/test-both/util/libphonenumberUtil_test.ts @@ -1,25 +1,26 @@ -// Copyright 2015-2020 Signal Messenger, LLC +// Copyright 2015-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -/* global libphonenumber */ - -'use strict'; +import { assert, AssertionError } from 'chai'; +import { parseNumber } from '../../util/libphonenumberUtil'; describe('libphonenumber util', () => { describe('parseNumber', () => { it('numbers with + are valid without providing regionCode', () => { - const result = libphonenumber.util.parseNumber('+14155555555'); - assert.isTrue(result.isValidNumber); - assert.strictEqual(result.nationalNumber, '4155555555'); + const result = parseNumber('+14155555555'); + if (!result.isValidNumber) { + throw new AssertionError('Phone number is not valid'); + } assert.strictEqual(result.e164, '+14155555555'); assert.strictEqual(result.regionCode, 'US'); assert.strictEqual(result.countryCode, '1'); }); it('variant numbers with the right regionCode are valid', () => { ['4155555555', '14155555555', '+14155555555'].forEach(number => { - const result = libphonenumber.util.parseNumber(number, 'US'); - assert.isTrue(result.isValidNumber); - assert.strictEqual(result.nationalNumber, '4155555555'); + const result = parseNumber(number, 'US'); + if (!result.isValidNumber) { + throw new AssertionError('Phone number is not valid'); + } assert.strictEqual(result.e164, '+14155555555'); assert.strictEqual(result.regionCode, 'US'); assert.strictEqual(result.countryCode, '1'); diff --git a/ts/textsecure/AccountManager.ts b/ts/textsecure/AccountManager.ts index a0b0fd267085..7195985432b7 100644 --- a/ts/textsecure/AccountManager.ts +++ b/ts/textsecure/AccountManager.ts @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Signal Messenger, LLC +// Copyright 2020-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import PQueue from 'p-queue'; @@ -31,6 +31,7 @@ import { UUID, UUIDKind } from '../types/UUID'; import { isMoreRecentThan, isOlderThan } from '../util/timestamp'; import { ourProfileKeyService } from '../services/ourProfileKey'; import { assert, strictAssert } from '../util/assert'; +import { getRegionCodeForNumber } from '../util/libphonenumberUtil'; import { getProvisioningUrl } from '../util/getProvisioningUrl'; import { SignalService as Proto } from '../protobuf'; import * as log from '../logging/log'; @@ -689,8 +690,7 @@ export default class AccountManager extends EventTarget { await storage.put('read-receipt-setting', Boolean(readReceipts)); - const regionCode = - window.libphonenumber.util.getRegionCodeForNumber(number); + const regionCode = getRegionCodeForNumber(number); await storage.put('regionCode', regionCode); await storage.protocol.hydrateCaches(); } diff --git a/ts/util/libphonenumberUtil.ts b/ts/util/libphonenumberUtil.ts new file mode 100644 index 000000000000..c9fb9f69e272 --- /dev/null +++ b/ts/util/libphonenumberUtil.ts @@ -0,0 +1,51 @@ +// Copyright 2014-2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { + instance as libphonenumber, + PhoneNumberFormat, +} from './libphonenumberInstance'; + +const FALLBACK_REGION_CODE = 'ZZ'; + +export function getRegionCodeForNumber(number: string): string { + try { + const parsedNumber = libphonenumber.parse(number); + return ( + libphonenumber.getRegionCodeForNumber(parsedNumber) || + FALLBACK_REGION_CODE + ); + } catch (e) { + return FALLBACK_REGION_CODE; + } +} + +export function parseNumber( + number: string, + defaultRegionCode?: string +): + | { isValidNumber: false; error: unknown } + | { + isValidNumber: true; + regionCode: undefined | string; + countryCode: undefined | string; + e164: string; + } { + try { + const parsedNumber = libphonenumber.parse(number, defaultRegionCode); + + const isValidNumber = libphonenumber.isValidNumber(parsedNumber); + if (!isValidNumber) { + return { error: new Error('Invalid phone number'), isValidNumber: false }; + } + + return { + isValidNumber: true, + regionCode: libphonenumber.getRegionCodeForNumber(parsedNumber), + countryCode: parsedNumber.getCountryCode()?.toString(), + e164: libphonenumber.format(parsedNumber, PhoneNumberFormat.E164), + }; + } catch (error) { + return { error, isValidNumber: false }; + } +} diff --git a/ts/util/scaleImageToLevel.ts b/ts/util/scaleImageToLevel.ts index e125413d1428..a086893b6404 100644 --- a/ts/util/scaleImageToLevel.ts +++ b/ts/util/scaleImageToLevel.ts @@ -1,4 +1,4 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import loadImage from 'blueimp-load-image'; @@ -7,6 +7,7 @@ import type { MIMEType } from '../types/MIME'; import { IMAGE_JPEG } from '../types/MIME'; import { canvasToBlob } from './canvasToBlob'; import { getValue } from '../RemoteConfig'; +import { parseNumber } from './libphonenumberUtil'; enum MediaQualityLevels { One = 1, @@ -67,18 +68,22 @@ function getMediaQualityLevel(): MediaQualityLevels { if (!values) { return DEFAULT_LEVEL; } - const countryValues = parseCountryValues(values); + const e164 = window.textsecure.storage.user.getNumber(); if (!e164) { return DEFAULT_LEVEL; } - const parsedPhoneNumber = window.libphonenumber.util.parseNumber(e164); + const parsedPhoneNumber = parseNumber(e164); if (!parsedPhoneNumber.isValidNumber) { return DEFAULT_LEVEL; } - const level = countryValues.get(parsedPhoneNumber.countryCode); + const countryValues = parseCountryValues(values); + + const level = parsedPhoneNumber.countryCode + ? countryValues.get(parsedPhoneNumber.countryCode) + : undefined; if (level) { return level; } diff --git a/ts/window.d.ts b/ts/window.d.ts index 373a3dfe7dfa..e913c8ee1d46 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -213,21 +213,6 @@ declare global { isFullScreen: () => boolean; initialTheme?: ThemeType; libphonenumber: { - util: { - getRegionCodeForNumber: (number: string) => string; - parseNumber: ( - e164: string, - defaultRegionCode?: string - ) => - | { isValidNumber: false; error: unknown } - | { - isValidNumber: true; - regionCode: string | undefined; - countryCode: string; - nationalNumber: string; - e164: string; - }; - }; parse: (number: string) => string; getRegionCodeForNumber: (number: string) => string; format: (number: string, format: PhoneNumberFormat) => string;