Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
104 lines
2.5 KiB
Text
Executable file
104 lines
2.5 KiB
Text
Executable file
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 };
|
|
}
|