UNPKG

lakutata

Version:

An IoC-based universal application framework.

373 lines (368 loc) 14.2 kB
class IPv4Range { #t; #s; constructor(t, s) { if (+t < 0 || +t > 4294967295 || +s < 0 || +s > 4294967295) { throw new Error("Invalid start or end IPv4 address"); } this.#t = t; this.#s = s; } static fromLong(t, s) { if (typeof t !== "number" || typeof s !== "number") throw new Error("Invalid start or end IPv4 address"); if (+s < +t) throw new Error("Invalid range value, end must be greater than or equal to start"); return new IPv4Range(t, s); } static fromString(t, s) { const i = IPv4.ip2long(t); const n = IPv4.ip2long(s); if (typeof i !== "number" || typeof n !== "number") throw new Error("Invalid start or end IPv4 address"); if (n < i) throw new Error("Invalid range value, end must be greater than or equal to start"); return new IPv4Range(i, n); } ip2long() { return [ this.#t, this.#s ]; } long2ip() { return [ IPv4.long2ip(this.#t), IPv4.long2ip(this.#s) ]; } ipCount() { return this.#s - this.#t + 1; } contains(t) { const s = IPv4.ip2long(t); if (typeof s !== "number") return false; return s >= this.#t && s <= this.#s; } } class IP { static contains(t, s) { if (typeof t !== "string" || typeof s !== "string") return false; return IPv4.contains(t, s) || IPv6.contains(t, s); } static ip2long(t) { if (!this.isValidIP(t)) return false; return IPv4.ip2long(t) || IPv6.ip2long(t); } static isCIDR(t) { if (typeof t !== "string") return false; return IPv4.isCIDR(t) || IPv6.isCIDR(t); } static isConflict(t) { if (!Array.isArray(t) || t.length === 0) return false; return IPv4.isConflict(t) || IPv6.isConflict(t); } static isValidIP(t) { if (typeof t !== "string") return false; return IPv4.isValidIP(t) || IPv6.isValidIP(t); } static long2ip(t) { if (typeof t !== "number" && typeof t !== "bigint") return false; return IPv4.long2ip(t) || IPv6.long2ip(t); } } class IPv4 { static ip2long(t) { if (!this.isValidIP(t)) return false; let s = 0; const i = t.split("."); for (const t of i) s = (s << 8) + +t; return s >>> 0; } static long2ip(t) { if (typeof t !== "number" || isNaN(t)) return false; if (t >= 0 && t <= 4294967295) { const s = []; for (let i = 3; i >= 0; i--) s.push(t >>> i * 8 & 255); return s.join("."); } else { return false; } } static { this.ipRange = IPv4Range; } static isCIDR(t) { if (typeof t !== "string") return false; const s = this.parseCIDR(t); return typeof s === "object" ? true : false; } static isEqual(t, s) { if (typeof t === "number" && (t < 0 || t > 4294967295)) return false; if (typeof s === "number" && (s < 0 || s > 4294967295)) return false; if (typeof t === "string") t = this.ip2long(t); if (typeof s === "string") s = this.ip2long(s); if (typeof t !== "number" || typeof s !== "number") return false; return t === s; } static contains(t, s) { const i = this.parseCIDR(t); if (typeof i !== "object" || !this.isValidIP(s)) return false; const {cidrMask: n, firstHost: e, lastHost: r, networkAddress: o, broadcastAddress: a} = i; if (n >= 31) { return this.ipRange.fromString(e, r).contains(s); } else { return this.ipRange.fromString(o, a).contains(s); } } static isPrivate(t) { if (!this.isValidIP(t)) return false; const s = [ { start: "10.0.0.0", end: "10.255.255.255" }, { start: "127.0.0.0", end: "127.255.255.255" }, { start: "172.16.0.0", end: "172.31.255.255" }, { start: "169.254.0.0", end: "169.254.255.255" }, { start: "192.168.0.0", end: "192.168.255.255" } ]; for (const i of s) { if (this.ipRange.fromString(i.start, i.end).contains(t)) { return true; } } return false; } static isValidIP(t, s = { strict: false }) { if (s.strict) { const s = /^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])(\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)){3}$/; return s.test(t); } else { const s = /^(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]?)){3}$/; return s.test(t); } } static parseCIDR(t) { if (typeof t !== "string") return false; const [s, i] = t.split("/"); if (s === undefined || i === undefined || i === "") return false; if (!this.isValidIP(s) || !this.isValidMask(+i)) return false; const n = 32 - +i; const e = this.ip2long(s); const r = Number(1n << BigInt(n)); const o = +i ? e >> n << n >>> 0 : 0; const a = (o | r - 1) >>> 0; const f = { ipCount: r, cidrMask: +i, usableCount: +i < 31 ? r - 2 : r, subnetMask: this.toSubnetMask(+i), networkAddress: +i < 31 ? this.long2ip(o) : "", broadcastAddress: +i < 31 ? this.long2ip(a) : "", firstHost: this.long2ip(o + (+i < 31 ? 1 : 0)), lastHost: this.long2ip(a - (+i < 31 ? 1 : 0)) }; return f; } static isConflict(t) { if (!Array.isArray(t) || t.length === 0) return false; const s = []; for (const i of t) { const t = this.parseCIDR(i); if (typeof t === "object") s.push({ cidr: i, networkAddress: t.networkAddress || t.firstHost }); } for (let t = 0; t < s.length; t++) { for (let i = t + 1; i < s.length; i++) { const n = this.contains(s[i].cidr, s[t].networkAddress); const e = this.contains(s[t].cidr, s[i].networkAddress); if (n || e) return true; } } return false; } static parseSubnet(t, s) { if (!this.isValidIP(t) || !this.isValidMask(s)) return false; const i = this.toMaskLength(s); const n = this.parseCIDR(`${t}/${i}`); return n; } static isValidMask(t) { if (typeof t === "number" && !isNaN(t)) { if (t < 0 || t > 32) return false; return true; } else if (typeof t === "string") { const s = this.ip2long(t); if (typeof s !== "number") return false; return /^1*0*$/.test(s.toString(2).padStart(32, "0")); } else { return false; } } static isSameSubnet(t, s, i) { if (!this.isValidIP(t) || !this.isValidIP(s) || !this.isValidMask(i)) return false; const n = this.ip2long(t); const e = this.ip2long(s); if (typeof i === "number") i = this.toSubnetMask(i); const r = this.ip2long(i); return (n & r) === (e & r); } static toBinHex(t) { if (!this.isValidIP(t)) return false; const s = this.ip2long(t); return { decimal: s, hex: `0x${s.toString(16).padStart(8, "0")}`, binary: s.toString(2).padStart(32, "0") }; } static toIPv6Format(t) { if (!this.isValidIP(t)) return false; const s = this.ip2long(t); const i = this.long2ip(s); return { mapped: `::ffff:${i}`, comperssed: IPv6.compressedForm(`::ffff:${i}`), expanded: IPv6.expandedForm(`::ffff:${i}`) }; } static toSubnetMask(t) { if (typeof t !== "number" || isNaN(t) || !this.isValidMask(t)) return false; const s = 4294967295 << 32 - t; return t ? this.long2ip(s >>> 0) : "0.0.0.0"; } static toMaskLength(t) { if (typeof t !== "string") return false; if (!this.isValidMask(t)) return false; const s = this.ip2long(t); const i = s === 0 ? 0 : s.toString(2).replaceAll("0", "").length; return i; } static toInverseMask(t) { if (!this.isValidMask(t)) return false; if (typeof t === "number") t = this.toSubnetMask(t); const s = this.ip2long(t); const i = ~s >>> 0; return this.long2ip(i); } } class IPv6 { static compressedForm(t) { if (!this.isValidIP(t)) return false; if (this.ip2long(t) === 0n) return "::"; t = this.expandedForm(t); const s = t.split(":"); const i = s.map((t => { const s = parseInt(t, 16); return s ? s.toString(16) : "X"; })).join(":"); const n = [ /(X:X:X:X:X:X:X)/, /(X:X:X:X:X:X)/, /(X:X:X:X:X)/, /(X:X:X:X)/, /(X:X:X)/, /(X:X)/ ]; for (let t = 0; t < n.length; t++) { if (i.match(n[t])) return i.replace(n[t], ":").replace(":::", "::").replaceAll("X", "0"); } return i.replaceAll("X", "0"); } static contains(t, s) { const i = this.parseCIDR(t); if (typeof i !== "object" || !this.isValidIP(s)) return false; const {lastHost: n, firstHost: e} = i; const r = this.ip2long(s); const o = this.ip2long(n); const a = this.ip2long(e); return r >= a && r <= o; } static expandedForm(t) { if (!this.isValidIP(t)) return false; if (t === "::") return "0000:".repeat(8).slice(0, -1); const s = t.split(":"); for (let t = 0; t < s.length; t++) { if (s[t] === "" && s[t + 1] === "") s.splice(t, 1); } const i = s[s.length - 1]; if (IPv4.isValidIP(i)) { const t = IPv4.toBinHex(i).hex.slice(2); s.pop() && s.push(t.slice(0, 4), t.slice(4)); } return s.map((t => t ? t.padStart(4, "0") : "0000:".repeat(9 - s.length).slice(0, -1))).join(":"); } static ip2long(t) { if (!this.isValidIP(t)) return false; const s = []; t = this.expandedForm(t); const i = t.split(":"); for (let t = 0; t < i.length; t++) { const n = parseInt(i[t], 16); s.push(n.toString(2).padStart(16, "0")); } return BigInt(`0b${s.join("")}`); } static isCIDR(t) { if (typeof t !== "string") return false; const s = this.parseCIDR(t); return typeof s === "object" ? true : false; } static isConflict(t) { if (!Array.isArray(t) || t.length === 0) return false; const s = []; for (const i of t) { const t = this.parseCIDR(i); if (typeof t === "object") s.push({ cidr: i, firstHost: t.firstHost }); } for (let t = 0; t < s.length; t++) { for (let i = t + 1; i < s.length; i++) { const n = this.contains(s[i].cidr, s[t].firstHost); const e = this.contains(s[t].cidr, s[i].firstHost); if (n || e) return true; } } return false; } static isEqual(t, s) { if (typeof t === "bigint" && (t < 0n || t > 340282366920938463463374607431768211455n)) return false; if (typeof s === "bigint" && (s < 0 || s > 340282366920938463463374607431768211455n)) return false; if (typeof t === "string") t = this.ip2long(t); if (typeof s === "string") s = this.ip2long(s); if (typeof t !== "bigint" || typeof s !== "bigint") return false; return t === s; } static isValidIP(t) { const s = /^[\s]*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((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]?)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((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]?)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((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]?)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((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]?)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((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]?)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((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]?)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((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]?)){3}))|:)))(%.+)?[\s]*$/; return s.test(t); } static long2ip(t) { if (typeof t !== "bigint") return false; if (t >= 0n && t <= 340282366920938463463374607431768211455n) { const s = []; const i = t.toString(16).padStart(32, "0"); for (let t = 0; t < 8; t++) s.push(i.slice(t * 4, (t + 1) * 4)); return this.compressedForm(s.join(":")); } else { return false; } } static parseCIDR(t) { if (typeof t !== "string") return false; const [s, i] = t.split("/"); if (s === undefined || i === undefined || i === "") return false; const n = +i; if (!this.isValidIP(s) || isNaN(n) || n < 0 || n > 128) return false; const e = BigInt(128 - n); const r = this.ip2long(s); const o = BigInt(1n << e); const a = r >> e << e; const f = this.long2ip(a); const l = this.long2ip(a | o - 1n); const c = { ipCount: o, firstHost: f, lastHost: l, prefixLength: n }; return c; } } export { IP, IPv4, IPv6 };