Spaces:
Paused
Paused
| import { assert } from '@hapi/hoek'; | |
| import { ipVersions } from './uri'; | |
| interface Options { | |
| /** | |
| * The required CIDR mode. | |
| * | |
| * @default 'optional' | |
| */ | |
| readonly cidr?: Cidr; | |
| /** | |
| * The allowed versions. | |
| * | |
| * @default ['ipv4', 'ipv6', 'ipvfuture'] | |
| */ | |
| readonly version?: Version | Version[]; | |
| } | |
| type Cidr = 'optional' | 'required' | 'forbidden'; | |
| type Version = 'ipv4' | 'ipv6' | 'ipvfuture'; | |
| interface Expression { | |
| /** The CIDR mode. */ | |
| cidr: Cidr; | |
| /** The raw regular expression string. */ | |
| raw: string; | |
| /** The regular expression. */ | |
| regex: RegExp; | |
| /** The array of versions allowed. */ | |
| versions: Version[]; | |
| } | |
| /** | |
| * Generates a regular expression used to validate IP addresses. | |
| * | |
| * @param options - optional settings. | |
| * | |
| * @returns an object with the regular expression and meta data. | |
| */ | |
| export function ipRegex(options: Options = {}): Expression { | |
| // CIDR | |
| const cidr = options.cidr || 'optional'; | |
| assert( | |
| ['required', 'optional', 'forbidden'].includes(cidr), | |
| 'options.cidr must be one of required, optional, forbidden' | |
| ); | |
| // Versions | |
| assert( | |
| options.version === undefined || typeof options.version === 'string' || Array.isArray(options.version), | |
| 'options.version must be a string or an array of string' | |
| ); | |
| let versions = options.version || ['ipv4', 'ipv6', 'ipvfuture']; | |
| if (!Array.isArray(versions)) { | |
| versions = [versions]; | |
| } | |
| assert(versions.length >= 1, 'options.version must have at least 1 version specified'); | |
| for (const version of versions) { | |
| assert(typeof version === 'string' && version === version.toLowerCase(), 'Invalid options.version value'); | |
| assert( | |
| ['ipv4', 'ipv6', 'ipvfuture'].includes(version), | |
| 'options.version contains unknown version ' + version + ' - must be one of ipv4, ipv6, ipvfuture' | |
| ); | |
| } | |
| versions = Array.from(new Set(versions)); | |
| // Regex | |
| const parts = versions.map((version) => { | |
| // Forbidden | |
| if (cidr === 'forbidden') { | |
| return ipVersions[version]; | |
| } | |
| // Required | |
| const cidrpart = `\\/${version === 'ipv4' ? ipVersions.v4Cidr : ipVersions.v6Cidr}`; | |
| if (cidr === 'required') { | |
| return `${ipVersions[version]}${cidrpart}`; | |
| } | |
| // Optional | |
| return `${ipVersions[version]}(?:${cidrpart})?`; | |
| }); | |
| const raw = `(?:${parts.join('|')})`; | |
| const regex = new RegExp(`^${raw}$`); | |
| return { cidr, versions, regex, raw }; | |
| } | |