feat(dialout) check appId for permission to call outbound destination (#12871)

This commit is contained in:
Mihaela Dumitru 2023-02-07 16:18:27 +02:00 committed by GitHub
parent 3e59359563
commit 84221c5c13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 8 deletions

View File

@ -1335,6 +1335,7 @@ var config = {
deploymentInfo
dialOutAuthUrl
dialOutCodesUrl
dialOutRegionUrl
disableRemoteControl
displayJids
externalConnectUrl

View File

@ -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<P: Props, S: State>
_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<P: Props, S: State>
} = 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,

View File

@ -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<any> {
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)) {

View File

@ -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",

View File

@ -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,