Repository: colinhacks/zod (language: python)

Issue:
IPv6 validation error
IPv6 validation fails when the last two parts of the IPv6 are compressed, both when one or both are omitted. It does not happen if it is any other part. I have checked the regex you use in https://github.com/colinhacks/zod/blob/1247caf58d1c189155bd04c068be1c758ab77c1c/src/types.ts#L613 and I have also checked it in external tools and the zod behavior is reproduced.

```ts
const ip = '2001:4888:50:ff00:500:d::';
const schema = z.string().ip();
const { success } = schema.safeParse(ip); // false
```

```ts
const ip = '2001:4888:50:ff00:500:d:0:0';
const schema = z.string().ip();
const { success } = schema.safeParse(ip); // true
```

```ts
const ip = '2001:4888:50:ff00::d:0:0';
const schema = z.string().ip();
const { success } = schema.safeParse(ip); // true
```


Discussion / hints:

Fix patch:
diff --git a/deno/lib/types.ts b/deno/lib/types.ts
index 9a6311289..57502f3fd 100644
--- a/deno/lib/types.ts
+++ b/deno/lib/types.ts
@@ -610,7 +610,7 @@ const ipv4Regex =
   /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
 
 const ipv6Regex =
-  /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/;
+  /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
 
 // https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript
 const base64Regex =
diff --git a/src/types.ts b/src/types.ts
index f89acb5e0..966381719 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -610,7 +610,7 @@ const ipv4Regex =
   /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
 
 const ipv6Regex =
-  /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/;
+  /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
 
 // https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript
 const base64Regex =


Test patch:
diff --git a/deno/lib/__tests__/string.test.ts b/deno/lib/__tests__/string.test.ts
index 3f5b95562..aa73e52d8 100644
--- a/deno/lib/__tests__/string.test.ts
+++ b/deno/lib/__tests__/string.test.ts
@@ -745,6 +745,9 @@ test("IP validation", () => {
     "114.71.82.94",
     "0.0.0.0",
     "37.85.236.115",
+    "2001:4888:50:ff00:500:d::",
+    "2001:4888:50:ff00:0500:000d:000:0000",
+    "2001:4888:50:ff00:0500:000d:0000:0000",
   ];
 
   const invalidIPs = [
diff --git a/src/__tests__/string.test.ts b/src/__tests__/string.test.ts
index db01a64eb..8cced8795 100644
--- a/src/__tests__/string.test.ts
+++ b/src/__tests__/string.test.ts
@@ -744,6 +744,9 @@ test("IP validation", () => {
     "114.71.82.94",
     "0.0.0.0",
     "37.85.236.115",
+    "2001:4888:50:ff00:500:d::",
+    "2001:4888:50:ff00:0500:000d:000:0000",
+    "2001:4888:50:ff00:0500:000d:0000:0000",
   ];
 
   const invalidIPs = [