From a776999aac4bae05d8ddd875e7f264365a19a870 Mon Sep 17 00:00:00 2001 From: Sebastijan K <58827427+sebastijankuzner@users.noreply.github.com> Date: Wed, 25 Nov 2020 06:38:57 +0100 Subject: [PATCH] feat(core-kernel): ip address utils (#4195) --- .../unit/core-kernel/utils/ip-address.test.ts | 94 +++++++++++++++++++ packages/core-kernel/package.json | 1 + packages/core-kernel/src/utils/index.ts | 1 + packages/core-kernel/src/utils/ip-address.ts | 27 ++++++ 4 files changed, 123 insertions(+) create mode 100644 __tests__/unit/core-kernel/utils/ip-address.test.ts create mode 100644 packages/core-kernel/src/utils/ip-address.ts diff --git a/__tests__/unit/core-kernel/utils/ip-address.test.ts b/__tests__/unit/core-kernel/utils/ip-address.test.ts new file mode 100644 index 0000000000..73f12d89aa --- /dev/null +++ b/__tests__/unit/core-kernel/utils/ip-address.test.ts @@ -0,0 +1,94 @@ +import "jest-extended"; + +import { isValidAddress, isIPv6Address, normalizeAddress } from "@packages/core-kernel/src/utils/ip-address"; + +describe("isValidAddress", () => { + it("should return true for valid IPv6 address", () => { + expect(isValidAddress("2001:3984:3989::104")).toBeTrue(); + }); + + it("should return true for localhost IPv6 address", () => { + expect(isValidAddress("::1")).toBeTrue(); + }); + + it("should return true for :: IPv6 address", () => { + expect(isValidAddress("::")).toBeTrue(); + }); + + it("should return true for valid IPv6 address in brackets", () => { + expect(isValidAddress("[2001:3984:3989::104]")).toBeTrue(); + }); + + it("should return false for invalid IPv6 address", () => { + expect(isValidAddress("2001:3984:3989:104:1:2001:3984:3989:10")).toBeFalse(); // Too long address + }); + + it("should return true for valid IPv4 address", () => { + expect(isValidAddress("127.0.0.1")).toBeTrue(); + }); + + it("should return true for invalid IPv4 address", () => { + expect(isValidAddress("127.0.0.300")).toBeFalse(); + }); + + + it("should return false for random string", () => { + expect(isValidAddress("random")).toBeFalse(); + }); +}); + +describe("isIPv6Address", () => { + it("should return true for valid IPv6 address", () => { + expect(isIPv6Address("2001:3984:3989::104")).toBeTrue(); + }); + + it("should return true for localhost IPv6 address", () => { + expect(isIPv6Address("::1")).toBeTrue(); + }); + + it("should return true for :: IPv6 address", () => { + expect(isIPv6Address("::")).toBeTrue(); + }); + + it("should return true for valid IPv6 address in brackets", () => { + expect(isIPv6Address("[2001:3984:3989::104]")).toBeTrue(); + }); + + it("should return false for invalid IPv6 address", () => { + expect(isIPv6Address("2001:3984:3989:104:1:2001:3984:3989:10")).toBeFalse(); // Too long address + }); + + it("should return false for valid IPv4 address", () => { + expect(isIPv6Address("127.0.0.1")).toBeFalse(); + }); + + it("should return false for random string", () => { + expect(isIPv6Address("random")).toBeFalse(); + }); +}); + +describe("normalizeAddress", () => { + it("should return normalized IPv6 address", () => { + expect(normalizeAddress("2001:3984:3989::104")).toEqual("[2001:3984:3989::104]"); + }); + + it("should return normalized localhost IPv6 address", () => { + expect(normalizeAddress("::1")).toEqual("[::1]"); + }); + + it("should return normalized :: IPv6 address", () => { + expect(normalizeAddress("::")).toEqual("[::]"); + }); + + it("should keep normalized IPv6 address in brackets", () => { + expect(normalizeAddress("[2001:3984:3989::104]")).toEqual("[2001:3984:3989::104]"); + }); + + it("should return same IPv4 address", () => { + expect(normalizeAddress("127.0.0.1")).toEqual("127.0.0.1"); + }); + + it("should return same random string", () => { + expect(normalizeAddress("random")).toEqual("random"); + }); +}); diff --git a/packages/core-kernel/package.json b/packages/core-kernel/package.json index 90b5ac5387..98ef7185d2 100644 --- a/packages/core-kernel/package.json +++ b/packages/core-kernel/package.json @@ -33,6 +33,7 @@ "fs-extra": "^8.1.0", "import-fresh": "^3.2.1", "inversify": "^5.0.1", + "ipaddr.js": "^2.0.0", "log-process-errors": "^5.0.3", "nanomatch": "^1.2.13", "nsfw": "^2.0.0", diff --git a/packages/core-kernel/src/utils/index.ts b/packages/core-kernel/src/utils/index.ts index 6481eff461..d8cadc4521 100644 --- a/packages/core-kernel/src/utils/index.ts +++ b/packages/core-kernel/src/utils/index.ts @@ -7,6 +7,7 @@ import { isBlacklisted } from "./is-blacklisted"; import { getBlockNotChainedErrorMessage, isBlockChained } from "./is-block-chained"; import { isWhitelisted } from "./is-whitelisted"; import { calculateRound, isNewRound } from "./round-calculator"; +export * as IpAddress from "./ip-address"; export * as Search from "./search"; import { calculate } from "./supply-calculator"; diff --git a/packages/core-kernel/src/utils/ip-address.ts b/packages/core-kernel/src/utils/ip-address.ts new file mode 100644 index 0000000000..214cb40155 --- /dev/null +++ b/packages/core-kernel/src/utils/ip-address.ts @@ -0,0 +1,27 @@ +import ipaddr from "ipaddr.js"; + +export const isValidAddress = (ip: string) => { + return ipaddr.isValid(clean(ip)); +}; + +export const isIPv6Address = (ip: string) => { + try { + return ipaddr.parse(clean(ip)).kind() === "ipv6"; + } catch {} + + return false; +}; + +export const normalizeAddress = (ip: string) => { + ip = clean(ip); + + if (isIPv6Address(ip)) { + return `[${ip}]`; + } + + return ip; +}; + +const clean = (ip: string) => { + return ip.replace("[", "").replace("]", ""); +};