From 84221c5c1354696a61197a4efab20e23154f192a Mon Sep 17 00:00:00 2001 From: Mihaela Dumitru Date: Tue, 7 Feb 2023 16:18:27 +0200 Subject: [PATCH] feat(dialout) check appId for permission to call outbound destination (#12871) --- config.js | 1 + .../AbstractAddPeopleDialog.js | 12 ++++ react/features/invite/functions.ts | 61 +++++++++++++++++-- tsconfig.native.json | 4 +- tsconfig.web.json | 4 +- 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/config.js b/config.js index f2efb3a81..9decabcf8 100644 --- a/config.js +++ b/config.js @@ -1335,6 +1335,7 @@ var config = { deploymentInfo dialOutAuthUrl dialOutCodesUrl + dialOutRegionUrl disableRemoteControl displayJids externalConnectUrl diff --git a/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js b/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js index 2c115ef2a..3c2c4c4dc 100644 --- a/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js +++ b/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js @@ -35,6 +35,11 @@ export type Props = { */ _dialOutAuthUrl: string, + /** + * The URL for validating if an outbound destination is allowed. + */ + _dialOutRegionUrl: string; + /** * Whether or not to show Dial Out functionality. */ @@ -235,7 +240,9 @@ export default class AbstractAddPeopleDialog _query(query = '') { const { _addPeopleEnabled: addPeopleEnabled, + _appId: appId, _dialOutAuthUrl: dialOutAuthUrl, + _dialOutRegionUrl: dialOutRegionUrl, _dialOutEnabled: dialOutEnabled, _jwt: jwt, _peopleSearchQueryTypes: peopleSearchQueryTypes, @@ -244,8 +251,10 @@ export default class AbstractAddPeopleDialog } = this.props; const options = { addPeopleEnabled, + appId, dialOutAuthUrl, dialOutEnabled, + dialOutRegionUrl, jwt, peopleSearchQueryTypes, peopleSearchUrl, @@ -275,14 +284,17 @@ export function _mapStateToProps(state: Object) { const { callFlowsEnabled, dialOutAuthUrl, + dialOutRegionUrl, peopleSearchQueryTypes, peopleSearchUrl } = state['features/base/config']; return { _addPeopleEnabled: isAddPeopleEnabled(state), + _appId: state['features/base/jwt']?.tenant, _callFlowsEnabled: callFlowsEnabled, _dialOutAuthUrl: dialOutAuthUrl, + _dialOutRegionUrl: dialOutRegionUrl, _dialOutEnabled: isDialOutEnabled(state), _jwt: state['features/base/jwt'].jwt, _peopleSearchQueryTypes: peopleSearchQueryTypes, diff --git a/react/features/invite/functions.ts b/react/features/invite/functions.ts index 80408f671..46bdaea6b 100644 --- a/react/features/invite/functions.ts +++ b/react/features/invite/functions.ts @@ -8,6 +8,7 @@ import { isJwtFeatureEnabled } from '../base/jwt/functions'; import { JitsiRecordingConstants } from '../base/lib-jitsi-meet'; import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants/functions'; import { toState } from '../base/redux/functions'; +import { doGetJSON } from '../base/util/httpUtils'; import { parseURLParams } from '../base/util/parseURLParams'; import { StatusCode, @@ -55,6 +56,34 @@ export function checkDialNumber( }); } +/** + * Sends an ajax request to check if the outbound call is permitted. + * + * @param {string} dialOutRegionUrl - The config endpoint. + * @param {string} jwt - The jwt token. + * @param {string} appId - The customer id. + * @param {string} phoneNumber - The destination phone number. + * @returns {Promise} - The promise created by the request. + */ +export function checkOutboundDestination( + dialOutRegionUrl: string, + jwt: string, + appId: string, + phoneNumber: string +): Promise { + return doGetJSON(dialOutRegionUrl, true, { + body: JSON.stringify({ + appId, + phoneNumber + }), + method: 'POST', + headers: { + 'Authorization': `Bearer ${jwt}`, + 'Content-Type': 'application/json' + } + }); +} + /** * Removes all non-numeric characters from a string. * @@ -76,6 +105,11 @@ export type GetInviteResultsOptions = { */ addPeopleEnabled: boolean; + /** + * The customer id. + */ + appId: string; + /** * The endpoint to use for checking phone number validity. */ @@ -86,6 +120,11 @@ export type GetInviteResultsOptions = { */ dialOutEnabled: boolean; + /** + * The endpoint to use for checking dial permission to an outbound destination. + */ + dialOutRegionUrl: string; + /** * The jwt token to pass to the search service. */ @@ -123,8 +162,10 @@ export function getInviteResultsForQuery( const text = query.trim(); const { - dialOutAuthUrl, addPeopleEnabled, + appId, + dialOutAuthUrl, + dialOutRegionUrl, dialOutEnabled, peopleSearchQueryTypes, peopleSearchUrl, @@ -187,7 +228,7 @@ export function getInviteResultsForQuery( } return Promise.all([ peopleSearchPromise, phoneNumberPromise ]) - .then(([ peopleResults, phoneResults ]) => { + .then(async ([ peopleResults, phoneResults ]) => { const results: any[] = [ ...peopleResults ]; @@ -203,14 +244,26 @@ export function getInviteResultsForQuery( = peopleResults.find(result => result.type === INVITE_TYPES.PHONE); if (!hasPhoneResult && typeof phoneResults.allow === 'boolean') { - results.push({ + const result = { allowed: phoneResults.allow, country: phoneResults.country, type: INVITE_TYPES.PHONE, number: phoneResults.phone, originalEntry: text, showCountryCodeReminder: !hasCountryCode - }); + }; + + if (!phoneResults.allow) { + try { + const response = await checkOutboundDestination(dialOutRegionUrl, jwt, appId, text); + + result.allowed = response.allowed; + } catch (error) { + logger.error('Error checking permission to dial to outbound destination', error); + } + } + + results.push(result); } if (sipInviteEnabled && isASipAddress(text)) { diff --git a/tsconfig.native.json b/tsconfig.native.json index f18551c01..dffb77111 100644 --- a/tsconfig.native.json +++ b/tsconfig.native.json @@ -2,9 +2,9 @@ "include": ["react/features/**/*.ts", "react/features/**/*.tsx", "./custom.d.ts", "./globals.native.d.ts"], "compilerOptions": { "allowSyntheticDefaultImports": true, - "target": "ESNext", + "target": "es2020", "jsx": "react-native", - "lib": [ "ES2017"], + "lib": [ "es2020"], "types": [ "react-native" ], "skipLibCheck": true, "moduleResolution": "Node", diff --git a/tsconfig.web.json b/tsconfig.web.json index d8a88605c..96103fcc8 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -2,8 +2,8 @@ "include": ["react/features/**/*.ts", "react/features/**/*.tsx", "./custom.d.ts", "./globals.d.ts"], "compilerOptions": { "allowSyntheticDefaultImports": true, - "module": "es6", - "target": "es6", + "module": "es2020", + "target": "es2020", "jsx": "react", "lib": [ "webworker", "ES2020", "DOM" ], "skipLibCheck": true,