mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2026-10-19 01:44:18 +00:00
* support admin settings private network CIDR * support admin settings private network CIDR * fix review comment
268 lines
6.8 KiB
TypeScript
268 lines
6.8 KiB
TypeScript
import { withSuspense } from "./with-suspense";
|
|
import { useMobileMedia } from "../utils/use-mobile-media";
|
|
import { withAccessControl } from "./with-access-control";
|
|
import { withSelectState } from "./with-select-state";
|
|
import { useRedirect } from "./use-redirect";
|
|
import { useFilteredResults } from "./use-filtered-results";
|
|
import { useScopedRedirect } from "./use-scoped-redirect";
|
|
import {
|
|
FQDN,
|
|
FQDN_TOP_LEVEL,
|
|
INVALID,
|
|
IP,
|
|
TCP_MAX_PORT,
|
|
USER_ACCOUNT,
|
|
USER_ADMIN,
|
|
USER_SP,
|
|
} from "src/api/constants";
|
|
|
|
import type {
|
|
Carrier,
|
|
IpType,
|
|
PasswordSettings,
|
|
SelectorOptions,
|
|
SpeechCredential,
|
|
User,
|
|
UserScopes,
|
|
} from "src/api/types";
|
|
import type { UserData } from "src/store/types";
|
|
import { getQueryFilter } from "src/store/localStore";
|
|
|
|
export const hasValue = <Type>(
|
|
variable: Type | null | undefined,
|
|
): variable is NonNullable<Type> => {
|
|
return variable !== null && variable !== undefined;
|
|
};
|
|
|
|
export const hasLength = <Type>(
|
|
variable: Type[] | null | undefined,
|
|
minlength = 0,
|
|
): variable is NonNullable<Type[]> => {
|
|
return hasValue(variable) && variable.length > minlength;
|
|
};
|
|
|
|
export const isNotBlank = (variable: string | null | undefined) => {
|
|
return hasValue(variable) && variable.length > 0;
|
|
};
|
|
|
|
export const isObject = (obj: unknown) => {
|
|
/** null | undefined | Array will be "object" so exclude them */
|
|
return typeof obj === "object" && hasValue(obj) && !Array.isArray(obj);
|
|
};
|
|
|
|
export const isValidPasswd = (
|
|
password: string,
|
|
passwordSettings: PasswordSettings,
|
|
) => {
|
|
if (passwordSettings) {
|
|
return (
|
|
password.length >= passwordSettings?.min_password_length &&
|
|
(passwordSettings?.require_digit ? /\d/.test(password) : true) &&
|
|
(passwordSettings?.require_special_character
|
|
? /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)
|
|
: true)
|
|
);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
export const isValidPort = (port: number) => {
|
|
return (
|
|
hasValue(port) &&
|
|
/^[0-9]+$/.test(port.toString().trim()) &&
|
|
parseInt(port.toString().trim(), 10) >= 0 &&
|
|
parseInt(port.toString().trim(), 10) <= TCP_MAX_PORT
|
|
);
|
|
};
|
|
|
|
export const getIpValidationType = (ipv4: string): IpType => {
|
|
const type =
|
|
/^((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])$/.test(
|
|
ipv4.trim(),
|
|
)
|
|
? IP
|
|
: /^([a-zA-Z0-9][^.]*)(\.[^.]+){2,}$/.test(ipv4.trim())
|
|
? FQDN
|
|
: /^([a-zA-Z][^.]*)(\.[^.]+)$/.test(ipv4.trim())
|
|
? FQDN_TOP_LEVEL
|
|
: INVALID;
|
|
return type;
|
|
};
|
|
|
|
function isValidIPV4(ip: string): boolean {
|
|
const ipv4Pattern =
|
|
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
return ipv4Pattern.test(ip);
|
|
}
|
|
|
|
function isValidCIDR(cidr: string): boolean {
|
|
const cidrPattern =
|
|
/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(\/([0-9]|[1-2][0-9]|3[0-2]))$/;
|
|
return cidrPattern.test(cidr);
|
|
}
|
|
|
|
export function isvalidIpv4OrCidr(input: string): boolean {
|
|
return isValidIPV4(input) || isValidCIDR(input);
|
|
}
|
|
|
|
export const getObscured = (str: string, sub = 4, char = "*") => {
|
|
const len = str.length - sub;
|
|
const obscured = str.substring(0, len).replace(/[a-zA-Z0-9]/g, char);
|
|
const revealed = str.substring(len);
|
|
|
|
return `${obscured}${revealed}`;
|
|
};
|
|
|
|
export const getObscuredSecret = (str: string, sub = 6, char = "X") => {
|
|
if (str.length <= sub) {
|
|
return str;
|
|
}
|
|
|
|
const obscured = char.repeat(str.length - sub);
|
|
const revealed = str.substring(0, sub);
|
|
|
|
return `${revealed}${obscured}`;
|
|
};
|
|
|
|
export const getHumanDateTime = (date: string, fallbackText = "Never used") => {
|
|
const currDate = new Date();
|
|
const argDate = new Date(date);
|
|
currDate.setHours(0, 0, 0, 0);
|
|
argDate.setHours(0, 0, 0, 0);
|
|
const daysDiff = Math.round(
|
|
(currDate.getTime() - argDate.getTime()) / 1000 / 60 / 60 / 24,
|
|
);
|
|
|
|
return daysDiff > 1
|
|
? `${daysDiff} days ago`
|
|
: daysDiff === 1
|
|
? "Yesterday"
|
|
: daysDiff === 0
|
|
? "Today"
|
|
: fallbackText;
|
|
};
|
|
|
|
export const formatPhoneNumber = (number: string) => {
|
|
const match = number.match(/^(1?)([2-9][0-9]{2})([2-9][0-9]{2})([0-9]{4})$/);
|
|
|
|
if (match) {
|
|
return `${match[1] ? `+${match[1]} ` : ""}(${match[2]}) ${match[3]}-${
|
|
match[4]
|
|
}`;
|
|
}
|
|
|
|
return number;
|
|
};
|
|
|
|
export const formatTime = (seconds: number) => {
|
|
if (seconds < 60) {
|
|
return `${seconds}s`;
|
|
}
|
|
|
|
const minutes = Math.floor(seconds / 60);
|
|
const remainingSeconds = seconds % 60;
|
|
return `${minutes}m ${remainingSeconds}s`;
|
|
};
|
|
|
|
export const sortLocaleName = (
|
|
a: Required<{ name: string }>,
|
|
b: Required<{ name: string }>,
|
|
) => a.name.localeCompare(b.name);
|
|
|
|
export const getUserScope = (user: User): UserScopes => {
|
|
if (user.account_sid) {
|
|
return USER_ACCOUNT;
|
|
} else if (user.service_provider_sid) {
|
|
return USER_SP;
|
|
} else {
|
|
return USER_ADMIN;
|
|
}
|
|
};
|
|
|
|
export const isUserAccountScope = (accountSid: string, user?: UserData) => {
|
|
return (
|
|
user?.scope === USER_ACCOUNT &&
|
|
(user?.account_sid !== accountSid || !accountSid)
|
|
);
|
|
};
|
|
|
|
export const checkSelectOptions = (
|
|
user?: UserData,
|
|
resource?: SpeechCredential | Carrier,
|
|
) => {
|
|
if (user?.scope === USER_ACCOUNT) {
|
|
if (!resource) {
|
|
return false;
|
|
}
|
|
if (resource && resource?.account_sid) {
|
|
return false;
|
|
}
|
|
if (resource && !resource?.account_sid) {
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
export const sortUsersAlpha = (a: User, b: User) => {
|
|
const nameA = a.name.toLowerCase();
|
|
const nameB = b.name.toLowerCase();
|
|
if (nameA < nameB) {
|
|
return -1;
|
|
}
|
|
if (nameA > nameB) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
export const filterScopeOptions = (
|
|
optionArray: SelectorOptions[],
|
|
user: UserData,
|
|
) => {
|
|
if (user.scope === USER_SP) {
|
|
return optionArray.filter((option) => option.value !== USER_ADMIN);
|
|
}
|
|
|
|
if (user.scope === USER_ACCOUNT) {
|
|
return optionArray.filter((option) => option.value === USER_ACCOUNT);
|
|
}
|
|
|
|
return optionArray;
|
|
};
|
|
|
|
export const createFilterString = (filterValue: string, label: string) => {
|
|
const filterString = getQueryFilter().split("/");
|
|
|
|
if (label === "Date") {
|
|
filterString.splice(0, 0, filterValue);
|
|
} else if (label === "Direction") {
|
|
filterString.splice(1, 1, filterValue);
|
|
} else if (label === "Status") {
|
|
filterString.splice(2, 2, filterValue);
|
|
}
|
|
return filterString.join("/");
|
|
};
|
|
|
|
export const disableDefaultTrunkRouting = (userScope: UserData["scope"]) => {
|
|
if (import.meta.env.VITE_APP_DISABLE_DEFAULT_TRUNK_ROUTING) {
|
|
if (userScope === USER_ADMIN) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
export {
|
|
withSuspense,
|
|
useMobileMedia,
|
|
withAccessControl,
|
|
withSelectState,
|
|
useRedirect,
|
|
useFilteredResults,
|
|
useScopedRedirect,
|
|
};
|