From 44e06ab4d79011b35fc7b8607455be4478cd599f Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 19:52:59 +0300 Subject: [PATCH 1/7] refactor: thread defang-aware separators through Extract IP addresses Adds an "Include defanged" boolean arg (default false) and refactors the IPv4/IPv6/removeLocal regex assembly to use dotSep/colonSep variables. With the arg off the variables collapse to the original literal separators, so the regex string is byte-identical to the pre-change op. Behaviour unchanged; no new tests yet. --- src/core/operations/ExtractIPAddresses.mjs | 33 ++++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/core/operations/ExtractIPAddresses.mjs b/src/core/operations/ExtractIPAddresses.mjs index b74ec8fe..6aa2c438 100644 --- a/src/core/operations/ExtractIPAddresses.mjs +++ b/src/core/operations/ExtractIPAddresses.mjs @@ -54,6 +54,11 @@ class ExtractIPAddresses extends Operation { name: "Unique", type: "boolean", value: false + }, + { + name: "Include defanged", + type: "boolean", + value: false } ]; } @@ -64,7 +69,13 @@ class ExtractIPAddresses extends Operation { * @returns {string} */ run(input, args) { - const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args, + const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique, includeDefanged] = args, + + // Defang-aware separator patterns. When includeDefanged is false these + // collapse to the original literal separators, so the regex behaviour + // is byte-for-byte identical to the pre-change op. + dotSep = includeDefanged ? "(?:\\.|\\[\\.\\])" : "\\.", + colonSep = includeDefanged ? "(?::|\\[:\\])" : ":", // IPv4 decimal groups can have values 0 to 255. To construct a regex the following sub-regex is reused: ipv4DecimalByte = "(?:25[0-5]|2[0-4]\\d|1?[0-9]\\d|\\d)", @@ -74,13 +85,16 @@ class ExtractIPAddresses extends Operation { lookBehind = "(? Date: Fri, 15 May 2026 19:53:46 +0300 Subject: [PATCH 2/7] test: assert Extract IP defang-off ignores defanged input --- tests/operations/tests/ExtractIPAddresses.mjs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/operations/tests/ExtractIPAddresses.mjs b/tests/operations/tests/ExtractIPAddresses.mjs index 13922e64..b758ba5d 100644 --- a/tests/operations/tests/ExtractIPAddresses.mjs +++ b/tests/operations/tests/ExtractIPAddresses.mjs @@ -129,5 +129,16 @@ TestRegister.addTests([ }, ], }, + { + name: "ExtractIPAddress backwards-compat: defang off ignores [.] defanged input", + input: "192[.]168[.]1[.]1 plain 10.0.0.1", + expectedOutput: "10.0.0.1", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, false] + }, + ], + }, ]); From 340d081c011d3d20063f23200547a1df24efad87 Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 19:54:36 +0300 Subject: [PATCH 3/7] test: extract fully-defanged IPv4 and IPv6 --- tests/operations/tests/ExtractIPAddresses.mjs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/operations/tests/ExtractIPAddresses.mjs b/tests/operations/tests/ExtractIPAddresses.mjs index b758ba5d..fd0b0f47 100644 --- a/tests/operations/tests/ExtractIPAddresses.mjs +++ b/tests/operations/tests/ExtractIPAddresses.mjs @@ -140,5 +140,38 @@ TestRegister.addTests([ }, ], }, + { + name: "ExtractIPAddress defang on: fully defanged IPv4", + input: "192[.]168[.]1[.]1", + expectedOutput: "192[.]168[.]1[.]1", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: fully defanged IPv6 long form", + input: "2001[:]0db8[:]85a3[:]0000[:]0000[:]8a2e[:]0370[:]7343", + expectedOutput: "2001[:]0db8[:]85a3[:]0000[:]0000[:]8a2e[:]0370[:]7343", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [false, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: fully defanged IPv6 shorthand", + input: "2001[:]db8[:][:]1", + expectedOutput: "2001[:]db8[:][:]1", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [false, true, false, false, false, false, true] + }, + ], + }, ]); From 695103728fda75b02bfa7240aba69e3edb7f1eab Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 19:57:36 +0300 Subject: [PATCH 4/7] test: extract partial-defang IPv4 (decimal + octal) and mixed inputs --- tests/operations/tests/ExtractIPAddresses.mjs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/operations/tests/ExtractIPAddresses.mjs b/tests/operations/tests/ExtractIPAddresses.mjs index fd0b0f47..4d40f976 100644 --- a/tests/operations/tests/ExtractIPAddresses.mjs +++ b/tests/operations/tests/ExtractIPAddresses.mjs @@ -173,5 +173,49 @@ TestRegister.addTests([ }, ], }, + { + name: "ExtractIPAddress defang on: partial defang IPv4", + input: "192.168[.]1.1 and 1[.]2.3[.]4", + expectedOutput: "192.168[.]1.1\n1[.]2.3[.]4", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: mixed plain and defanged in one input", + input: "plain 10.0.0.1 defanged 8[.]8[.]8[.]8", + expectedOutput: "10.0.0.1\n8[.]8[.]8[.]8", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: defanged octal IPv4", + input: "0123[.]0177[.]0234[.]0377", + expectedOutput: "0123[.]0177[.]0234[.]0377", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: partial-defang octal IPv4", + input: "0123.0177[.]0234[.]0377", + expectedOutput: "0123.0177[.]0234[.]0377", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, ]); From 31545dd0de2f3dc9c51e13fe6ba3ee402654a617 Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 19:58:28 +0300 Subject: [PATCH 5/7] test: removeLocal filters full and partial defanged local IPs --- tests/operations/tests/ExtractIPAddresses.mjs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/operations/tests/ExtractIPAddresses.mjs b/tests/operations/tests/ExtractIPAddresses.mjs index 4d40f976..801e34f6 100644 --- a/tests/operations/tests/ExtractIPAddresses.mjs +++ b/tests/operations/tests/ExtractIPAddresses.mjs @@ -217,5 +217,38 @@ TestRegister.addTests([ }, ], }, + { + name: "ExtractIPAddress defang on + removeLocal: full-defang local 10/8 filtered", + input: "10[.]0[.]0[.]1 public 8[.]8[.]8[.]8", + expectedOutput: "8[.]8[.]8[.]8", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, true, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on + removeLocal: partial-defang local 192.168 filtered", + input: "192.168[.]1[.]100 keeps 1.1.1.1", + expectedOutput: "1.1.1.1", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, true, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on + removeLocal: full-defang 172.16/12 filtered", + input: "172[.]16[.]0[.]1 public 9[.]9[.]9[.]9", + expectedOutput: "9[.]9[.]9[.]9", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, true, false, false, false, true] + }, + ], + }, ]); From 8c2429736c8684110a1d3341aa8852f9c654cbb8 Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 19:59:24 +0300 Subject: [PATCH 6/7] test: unique/sort/URI-literal/edge-case behaviour with Extract IP defang --- tests/operations/tests/ExtractIPAddresses.mjs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tests/operations/tests/ExtractIPAddresses.mjs b/tests/operations/tests/ExtractIPAddresses.mjs index 801e34f6..ab8f9d48 100644 --- a/tests/operations/tests/ExtractIPAddresses.mjs +++ b/tests/operations/tests/ExtractIPAddresses.mjs @@ -250,5 +250,104 @@ TestRegister.addTests([ }, ], }, + { + name: "ExtractIPAddress defang on + unique: plain and defanged kept distinct", + input: "1.1.1.1 1[.]1[.]1[.]1 1.1.1.1", + expectedOutput: "1.1.1.1\n1[.]1[.]1[.]1", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, true, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on + sort: plain group sorts numerically before defanged group sorts lexically", + input: "200.1.1.1 5.5.5.5 100[.]100[.]100[.]100 10[.]0[.]0[.]1", + expectedOutput: "5.5.5.5\n200.1.1.1\n10[.]0[.]0[.]1\n100[.]100[.]100[.]100", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, true, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: IPv6 URI literal brackets stripped, inner extracted", + input: "Connect to [2001:db8::1]:8080 please", + expectedOutput: "2001:db8::1", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [false, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: empty input", + input: "", + expectedOutput: "", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: trailing-digit trap does not over-extend defanged IP", + input: "abc 192[.]168[.]1[.]1234", + expectedOutput: "", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on + displayTotal: count line includes defanged matches", + input: "1.1.1.1 2[.]2[.]2[.]2 3[.]3[.]3[.]3", + expectedOutput: "Total found: 3\n\n1.1.1.1\n2[.]2[.]2[.]2\n3[.]3[.]3[.]3", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, true, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on, IPv4 toggle off: defanged IPv4 input matches nothing", + input: "192[.]168[.]1[.]1", + expectedOutput: "", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [false, true, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on, IPv6 toggle off: defanged IPv6 input matches nothing", + input: "2001[:]db8[:][:]1", + expectedOutput: "", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, false, false, false, false, false, true] + }, + ], + }, + { + name: "ExtractIPAddress defang on: pure ASCII text with no IPs returns empty", + input: "the quick brown fox jumps over the lazy dog (no addresses here)", + expectedOutput: "", + recipeConfig: [ + { + "op": "Extract IP addresses", + "args": [true, true, false, false, false, false, true] + }, + ], + }, ]); From 981371e98d1be8679a1c9abaeef004ee30d4940d Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 20:04:37 +0300 Subject: [PATCH 7/7] docs: update Extract IP description for Include defanged arg --- src/core/operations/ExtractIPAddresses.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/ExtractIPAddresses.mjs b/src/core/operations/ExtractIPAddresses.mjs index 6aa2c438..f169e340 100644 --- a/src/core/operations/ExtractIPAddresses.mjs +++ b/src/core/operations/ExtractIPAddresses.mjs @@ -21,7 +21,7 @@ class ExtractIPAddresses extends Operation { this.name = "Extract IP addresses"; this.module = "Regex"; - this.description = "Extracts all IPv4 and IPv6 addresses.

Warning: Given a string 1.2.3.4.5.6.7.8, this will match 1.2.3.4 and 5.6.7.8 so always check the original input!"; + this.description = "Extracts all IPv4 and IPv6 addresses.

When 'Include defanged' is enabled, addresses defanged with [.] (IPv4) or [:] (IPv6) are also extracted, including partial defangs (e.g. 192.168[.]1.1). Matches are returned as-is; chain Fang IP Addresses after if you need clean addresses. With 'Sort' enabled, defanged matches sort lexicographically after the plain-IP group.

Warning: Given a string 1.2.3.4.5.6.7.8, this will match 1.2.3.4 and 5.6.7.8 so always check the original input!"; this.inputType = "string"; this.outputType = "string"; this.args = [