diff --git a/README.md b/README.md index 37cf569..7b5ed63 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,15 @@ ip.cidrSubnet('192.168.1.134/26').contains('192.168.1.190') // true Additional features: ```ts ip.isV4Format('255.255.255.256') // true +ip.isV6Format('127.0.0.1') // true + +ip.setMode('strict') // or 'legacy' +ip.isV4Format('255.255.255.256') // false +ip.isV6Format('127.0.0.1') // false + +// new methods are always strict ip.isV4('255.255.255.256') // false +ip.isV6('127.0.0.1') // false ``` ## License diff --git a/src/main/ts/core.ts b/src/main/ts/core.ts index 8e57b7b..98ab609 100644 --- a/src/main/ts/core.ts +++ b/src/main/ts/core.ts @@ -8,11 +8,23 @@ export const V6_RE = /^(?=.+)(::)?(((\d{1,3}\.){3}\d{1,3})?|([0-9a-f]{0,4}:{0,2} export const V4_S_RE = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/ export const V6_S_RE = /(([\dA-Fa-f]{1,4}:){7}[\dA-Fa-f]{1,4}|([\dA-Fa-f]{1,4}:){1,7}:|([\dA-Fa-f]{1,4}:){1,6}:[\dA-Fa-f]{1,4}|([\dA-Fa-f]{1,4}:){1,5}(:[\dA-Fa-f]{1,4}){1,2}|([\dA-Fa-f]{1,4}:){1,4}(:[\dA-Fa-f]{1,4}){1,3}|([\dA-Fa-f]{1,4}:){1,3}(:[\dA-Fa-f]{1,4}){1,4}|([\dA-Fa-f]{1,4}:){1,2}(:[\dA-Fa-f]{1,4}){1,5}|[\dA-Fa-f]{1,4}:((:[\dA-Fa-f]{1,4}){1,6})|:((:[\dA-Fa-f]{1,4}){1,7}|:)|fe80:(:[\dA-Fa-f]{0,4}){0,4}%[\dA-Za-z]+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)|([\dA-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d))$/ -export const isV4Format = (ip: string): boolean => V4_RE.test(ip) // Legacy -export const isV6Format = (ip: string): boolean => V6_RE.test(ip) // Legacy +export const isV4Format = (ip: string): boolean => defs.V4_RE.test(ip) // Legacy +export const isV6Format = (ip: string): boolean => defs.V6_RE.test(ip) // Legacy export const isV4 = (ip: string): boolean => V4_S_RE.test(ip) export const isV6 = (ip: string): boolean => V6_S_RE.test(ip) +const defs = { + V4_RE, + V6_RE, +} + +export const setMode = (mode: 'legacy' | 'strict'): void => { + if (mode === 'legacy') { Object.assign(defs, { V4_RE, V6_RE }); return } + if (mode === 'strict') { Object.assign(defs, { V4_RE: V4_S_RE, V6_RE: V6_S_RE }); return } + + throw new Error('mode must be either "legacy" or "strict"') +} + export function readUInt16BE(buf: Buffer | Uint8Array | DataView, offset: number = 0): number { if (typeof (buf as Buffer).readUInt16BE === 'function') { // Node.js Buffer or feross/buffer polyfill diff --git a/src/test/ts/core.test.ts b/src/test/ts/core.test.ts index 0a0b20c..4aaace1 100644 --- a/src/test/ts/core.test.ts +++ b/src/test/ts/core.test.ts @@ -28,7 +28,8 @@ import { cidr, cidrSubnet, or, - not + not, + setMode } from '../../main/ts/core.ts' describe('core', () => { @@ -372,4 +373,22 @@ describe('core', () => { assert.equal(isPublic(input), !expected, `isPublic(${input}) === ${!expected}`) } }) + + describe('setMode()', () => { + test('sets ipv4/ipv6 mode', () => { + setMode('legacy') + assert.equal(isV4Format('999.999.999.999'), true) + assert.equal(isV4('999.999.999.999'), false) + assert.equal(isV6Format('127.0.0.1'), true) + assert.equal(isV6('127.0.0.1'), false) + + setMode('strict') + assert.equal(isV4Format('999.999.999.999'), false) + assert.equal(isV4('999.999.999.999'), false) + assert.equal(isV6Format('127.0.0.1'), false) + assert.equal(isV6('127.0.0.1'), false) + + setMode('legacy') + }) + }) }) diff --git a/target/cjs/core.cjs b/target/cjs/core.cjs index 64fbc9d..cb50cdb 100644 --- a/target/cjs/core.cjs +++ b/target/cjs/core.cjs @@ -35,6 +35,7 @@ __export(core_exports, { not: () => not, or: () => or, readUInt16BE: () => readUInt16BE, + setMode: () => setMode, subnet: () => subnet, toBuffer: () => toBuffer, toLong: () => toLong, @@ -47,10 +48,25 @@ var V4_RE = /^(\d{1,3}(\.|$)){4}$/; var V6_RE = /^(?=.+)(::)?(((\d{1,3}\.){3}\d{1,3})?|([0-9a-f]{0,4}:{0,2})){1,8}(::)?$/i; var V4_S_RE = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/; var V6_S_RE = /(([\dA-Fa-f]{1,4}:){7}[\dA-Fa-f]{1,4}|([\dA-Fa-f]{1,4}:){1,7}:|([\dA-Fa-f]{1,4}:){1,6}:[\dA-Fa-f]{1,4}|([\dA-Fa-f]{1,4}:){1,5}(:[\dA-Fa-f]{1,4}){1,2}|([\dA-Fa-f]{1,4}:){1,4}(:[\dA-Fa-f]{1,4}){1,3}|([\dA-Fa-f]{1,4}:){1,3}(:[\dA-Fa-f]{1,4}){1,4}|([\dA-Fa-f]{1,4}:){1,2}(:[\dA-Fa-f]{1,4}){1,5}|[\dA-Fa-f]{1,4}:((:[\dA-Fa-f]{1,4}){1,6})|:((:[\dA-Fa-f]{1,4}){1,7}|:)|fe80:(:[\dA-Fa-f]{0,4}){0,4}%[\dA-Za-z]+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)|([\dA-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d))$/; -var isV4Format = (ip) => V4_RE.test(ip); -var isV6Format = (ip) => V6_RE.test(ip); +var isV4Format = (ip) => defs.V4_RE.test(ip); +var isV6Format = (ip) => defs.V6_RE.test(ip); var isV4 = (ip) => V4_S_RE.test(ip); var isV6 = (ip) => V6_S_RE.test(ip); +var defs = { + V4_RE, + V6_RE +}; +var setMode = (mode) => { + if (mode === "legacy") { + Object.assign(defs, { V4_RE, V6_RE }); + return; + } + if (mode === "strict") { + Object.assign(defs, { V4_RE: V4_S_RE, V6_RE: V6_S_RE }); + return; + } + throw new Error('mode must be either "legacy" or "strict"'); +}; function readUInt16BE(buf, offset = 0) { if (typeof buf.readUInt16BE === "function") { return buf.readUInt16BE(offset); @@ -306,6 +322,7 @@ var isPublic = (addr) => !isPrivate(addr); not, or, readUInt16BE, + setMode, subnet, toBuffer, toLong, diff --git a/target/dts/core.d.ts b/target/dts/core.d.ts index 4d3c19a..0d33804 100644 --- a/target/dts/core.d.ts +++ b/target/dts/core.d.ts @@ -8,6 +8,7 @@ export declare const isV4Format: (ip: string) => boolean; export declare const isV6Format: (ip: string) => boolean; export declare const isV4: (ip: string) => boolean; export declare const isV6: (ip: string) => boolean; +export declare const setMode: (mode: "legacy" | "strict") => void; export declare function readUInt16BE(buf: Buffer | Uint8Array | DataView, offset?: number): number; export type Family = typeof IPV4 | typeof IPV6; export declare function normalizeFamily(family?: string | number): Family; diff --git a/target/dts/index.d.ts b/target/dts/index.d.ts index e303292..1a127d6 100644 --- a/target/dts/index.d.ts +++ b/target/dts/index.d.ts @@ -14,6 +14,7 @@ export declare const ip: { isV6Format: (ip: string) => boolean; isV4: (ip: string) => boolean; isV6: (ip: string) => boolean; + setMode: (mode: "legacy" | "strict") => void; normalizeAddress: (addr: string | number) => string; normalizeToLong: (addr: string) => number; isLoopback: (addr: string | number) => boolean; diff --git a/target/esm/core.mjs b/target/esm/core.mjs index b0435ad..a02ff21 100644 --- a/target/esm/core.mjs +++ b/target/esm/core.mjs @@ -5,10 +5,25 @@ var V4_RE = /^(\d{1,3}(\.|$)){4}$/; var V6_RE = /^(?=.+)(::)?(((\d{1,3}\.){3}\d{1,3})?|([0-9a-f]{0,4}:{0,2})){1,8}(::)?$/i; var V4_S_RE = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/; var V6_S_RE = /(([\dA-Fa-f]{1,4}:){7}[\dA-Fa-f]{1,4}|([\dA-Fa-f]{1,4}:){1,7}:|([\dA-Fa-f]{1,4}:){1,6}:[\dA-Fa-f]{1,4}|([\dA-Fa-f]{1,4}:){1,5}(:[\dA-Fa-f]{1,4}){1,2}|([\dA-Fa-f]{1,4}:){1,4}(:[\dA-Fa-f]{1,4}){1,3}|([\dA-Fa-f]{1,4}:){1,3}(:[\dA-Fa-f]{1,4}){1,4}|([\dA-Fa-f]{1,4}:){1,2}(:[\dA-Fa-f]{1,4}){1,5}|[\dA-Fa-f]{1,4}:((:[\dA-Fa-f]{1,4}){1,6})|:((:[\dA-Fa-f]{1,4}){1,7}|:)|fe80:(:[\dA-Fa-f]{0,4}){0,4}%[\dA-Za-z]+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)|([\dA-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d))$/; -var isV4Format = (ip) => V4_RE.test(ip); -var isV6Format = (ip) => V6_RE.test(ip); +var isV4Format = (ip) => defs.V4_RE.test(ip); +var isV6Format = (ip) => defs.V6_RE.test(ip); var isV4 = (ip) => V4_S_RE.test(ip); var isV6 = (ip) => V6_S_RE.test(ip); +var defs = { + V4_RE, + V6_RE +}; +var setMode = (mode) => { + if (mode === "legacy") { + Object.assign(defs, { V4_RE, V6_RE }); + return; + } + if (mode === "strict") { + Object.assign(defs, { V4_RE: V4_S_RE, V6_RE: V6_S_RE }); + return; + } + throw new Error('mode must be either "legacy" or "strict"'); +}; function readUInt16BE(buf, offset = 0) { if (typeof buf.readUInt16BE === "function") { return buf.readUInt16BE(offset); @@ -263,6 +278,7 @@ export { not, or, readUInt16BE, + setMode, subnet, toBuffer, toLong,