swc/crates/swc_bundler/tests/.cache/deno/a67b1c64514bea54c6365ab7db8939627efb005f.ts
2021-11-09 20:42:49 +09:00

103 lines
3.0 KiB
TypeScript

// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isIP.ts
// @ts-ignore allowing typedoc to build
import { assertString } from '../helpers/assertString.ts';
/**
* @ignore
*/
const ipv4Maybe = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;
/**
* @ignore
*/
const ipv6Block = /^[0-9A-F]{1,4}$/i;
export const isIP = (str: string, ipVersion?: string | number): boolean => {
assertString(str);
const version = ipVersion ? String(ipVersion) : '';
if (!version) {
return isIP(str, 4) || isIP(str, 6);
} else if (version === '4') {
if (!ipv4Maybe.test(str)) {
return false;
}
const arr = str.split('.') as unknown;
const parts = (arr as number[]).sort((a, b) => a - b);
return (parts[3] <= 255) as boolean;
} else if (version === '6') {
let addressAndZone = [str];
// ipv6 addresses could have scoped architecture
// according to https://tools.ietf.org/html/rfc4007#section-11
if (str.includes('%')) {
addressAndZone = str.split('%');
if (addressAndZone.length !== 2) {
// it must be just two parts
return false;
}
if (!addressAndZone[0].includes(':')) {
// the first part must be the address
return false;
}
if (addressAndZone[1] === '') {
// the second part must not be empty
return false;
}
}
const blocks = addressAndZone[0].split(':');
let foundOmissionBlock = false; // marker to indicate ::
// At least some OS accept the last 32 bits of an IPv6 address
// (i.e. 2 of the blocks) in IPv4 notation, and RFC 3493 says
// that '::ffff:a.b.c.d' is valid for IPv4-mapped IPv6 addresses,
// and '::a.b.c.d' is deprecated, but also valid.
const foundIPv4TransitionBlock = isIP(blocks[blocks.length - 1], 4);
const expectedNumberOfBlocks = foundIPv4TransitionBlock ? 7 : 8;
if (blocks.length > expectedNumberOfBlocks) {
return false;
}
// initial or final ::
if (str === '::') {
return true;
} else if (str.substr(0, 2) === '::') {
blocks.shift();
blocks.shift();
foundOmissionBlock = true;
} else if (str.substr(str.length - 2) === '::') {
blocks.pop();
blocks.pop();
foundOmissionBlock = true;
}
for (let i = 0; i < blocks.length; ++i) {
// test for a :: which can not be at the string start/end
// since those cases have been handled above
if (blocks[i] === '' && i > 0 && i < blocks.length - 1) {
if (foundOmissionBlock) {
return false; // multiple :: in address
}
foundOmissionBlock = true;
} else if (foundIPv4TransitionBlock && i === blocks.length - 1) {
// it has been checked before that the last
// block is a valid IPv4 address
} else if (!ipv6Block.test(blocks[i])) {
return false;
}
}
if (foundOmissionBlock) {
return blocks.length >= 1;
}
return blocks.length === expectedNumberOfBlocks;
}
return false;
};