Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/@webex/contact-center/src/cc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,11 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
]);

if (data.loginOption === LoginOption.AGENT_DN && !isValidDialNumber(data.dialNumber)) {
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
if (
data.loginOption === LoginOption.AGENT_DN &&
!isValidDialNumber(data.dialNumber, dialPlanEntries)
) {
const error = new Error('INVALID_DIAL_NUMBER');
// @ts-ignore - adding custom key to the error object
error.details = {data: {reason: 'INVALID_DIAL_NUMBER'}} as Failure;
Expand Down
37 changes: 32 additions & 5 deletions packages/@webex/contact-center/src/services/core/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Interaction,
} from '../task/types';
import {PARTICIPANT_TYPES, STATE_CONSULT} from './constants';
import {DialPlan} from '../config/types';

/**
* Extracts common error details from a Webex request payload.
Expand Down Expand Up @@ -48,11 +49,37 @@ const getAgentActionTypeFromTask = (taskData?: TaskData): 'DIAL_NUMBER' | '' =>
return isDialNumber || isEntryPointVariant ? 'DIAL_NUMBER' : '';
};

export const isValidDialNumber = (input: string): boolean => {
// This regex checks for a valid dial number format for only few countries such as US, Canada.
const regexForDn = /1[0-9]{3}[2-9][0-9]{6}([,]{1,10}[0-9]+){0,1}/;
// Fallback regex for US/Canada dial numbers when no dial plan entries are configured
export const FALLBACK_DIAL_NUMBER_REGEX = /1[0-9]{3}[2-9][0-9]{6}([,]{1,10}[0-9]+){0,1}/;

return regexForDn.test(input);
/**
* Validates a dial number against the provided dial plan regex patterns.
* A number is valid if it matches at least one regex pattern in the dial plans.
* Falls back to US/Canada regex validation if no dial plan entries are configured.
*
* @param input - The dial number to validate
* @param dialPlanEntries - Array of dial plan entries containing regex patterns
* @returns true if the input matches at least one dial plan regex pattern, false otherwise
*/
export const isValidDialNumber = (
input: string,
dialPlanEntries: DialPlan['dialPlanEntity']
): boolean => {
if (!dialPlanEntries || dialPlanEntries.length === 0) {
LoggerProxy.info('No dial plan entries found. Falling back to US number validation.');

return FALLBACK_DIAL_NUMBER_REGEX.test(input);
}

return dialPlanEntries.some((entry) => {
try {
const regex = new RegExp(entry.regex);

return regex.test(input);
} catch {
return false;
}
});
};

export const getStationLoginErrorData = (failure: Failure, loginOption: LoginOption) => {
Expand All @@ -74,7 +101,7 @@ export const getStationLoginErrorData = (failure: Failure, loginOption: LoginOpt
},
INVALID_DIAL_NUMBER: {
message:
'Enter a valid US dial number. For help, reach out to your administrator or support team.',
'Enter a valid dial number. For help, reach out to your administrator or support team.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we include the supported country list here?

@Kesari3008 @mkesavan13

Copy link
Author

@zachraymer zachraymer Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review Rajesh. Can we satisfy this item or go forward with merge?

fieldName: loginOption,
},
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Utils from '../../../../../src/services/core/Utils';
import {FALLBACK_DIAL_NUMBER_REGEX} from '../../../../../src/services/core/Utils';
import LoggerProxy from '../../../../../src/logger-proxy';
import WebexRequest from '../../../../../src/services/core/WebexRequest';
import {LoginOption, WebexRequestPayload} from '../../../../../src/types';
Expand Down Expand Up @@ -244,7 +245,7 @@ describe('Utils', () => {
const result = Utils.getStationLoginErrorData(failure, LoginOption.AGENT_DN);
expect(result).toEqual({
message:
'Enter a valid US dial number. For help, reach out to your administrator or support team.',
'Enter a valid dial number. For help, reach out to your administrator or support team.',
fieldName: LoginOption.AGENT_DN,
});
});
Expand Down Expand Up @@ -557,4 +558,65 @@ describe('Utils', () => {
});
});

describe('isValidDialNumber', () => {
const anyFormatEntry = {
name: 'Any Format',
prefix: '',
regex: '([0-9a-zA-Z]+[-._])*[0-9a-zA-Z]+',
strippedChars: '( )-',
};

const usOnlyEntry = {
name: 'US',
prefix: '1',
regex: FALLBACK_DIAL_NUMBER_REGEX.source,
strippedChars: '( )-',
};

describe('with multiple dial plan entries (Any Format + US)', () => {
const dialPlanEntries = [anyFormatEntry, usOnlyEntry];

it('should return true for a valid US phone number', () => {
const result = Utils.isValidDialNumber('12223334567', dialPlanEntries);
expect(result).toBe(true);
});

it('should return true for a UK phone number', () => {
const result = Utils.isValidDialNumber('+442030484377', dialPlanEntries);
expect(result).toBe(true);
});
});

describe('with US-only dial plan entry', () => {
const dialPlanEntries = [usOnlyEntry];

it('should return true for a valid US phone number', () => {
const result = Utils.isValidDialNumber('12223334567', dialPlanEntries);
expect(result).toBe(true);
});

it('should return false for a UK phone number', () => {
const result = Utils.isValidDialNumber('+442030484377', dialPlanEntries);
expect(result).toBe(false);
});

it('should return false for an invalid US number format', () => {
const result = Utils.isValidDialNumber('1234567890', dialPlanEntries);
expect(result).toBe(false);
});
});

describe('with empty dial plan entries (fallback to US regex)', () => {
it('should return true for a valid US phone number', () => {
const result = Utils.isValidDialNumber('12223334567', []);
expect(result).toBe(true);
});

it('should return false for a UK phone number', () => {
const result = Utils.isValidDialNumber('+442030484377', []);
expect(result).toBe(false);
});
});
});

});
Loading