@better-auth/core 1.5.6 → 1.6.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/api/index.d.mts +42 -13
  2. package/dist/api/index.mjs +0 -4
  3. package/dist/async_hooks/index.d.mts +1 -2
  4. package/dist/async_hooks/index.mjs +0 -2
  5. package/dist/async_hooks/pure.index.d.mts +1 -2
  6. package/dist/async_hooks/pure.index.mjs +0 -2
  7. package/dist/context/endpoint-context.d.mts +2 -3
  8. package/dist/context/endpoint-context.mjs +0 -3
  9. package/dist/context/global.d.mts +1 -2
  10. package/dist/context/global.mjs +1 -3
  11. package/dist/context/index.mjs +1 -2
  12. package/dist/context/request-state.d.mts +1 -2
  13. package/dist/context/request-state.mjs +0 -3
  14. package/dist/context/transaction.d.mts +1 -2
  15. package/dist/context/transaction.mjs +0 -3
  16. package/dist/db/adapter/factory.d.mts +1 -2
  17. package/dist/db/adapter/factory.mjs +3 -7
  18. package/dist/db/adapter/get-default-field-name.d.mts +1 -2
  19. package/dist/db/adapter/get-default-field-name.mjs +0 -3
  20. package/dist/db/adapter/get-default-model-name.d.mts +1 -2
  21. package/dist/db/adapter/get-default-model-name.mjs +0 -3
  22. package/dist/db/adapter/get-field-attributes.d.mts +1 -2
  23. package/dist/db/adapter/get-field-attributes.mjs +0 -3
  24. package/dist/db/adapter/get-field-name.d.mts +1 -2
  25. package/dist/db/adapter/get-field-name.mjs +0 -3
  26. package/dist/db/adapter/get-id-field.d.mts +1 -2
  27. package/dist/db/adapter/get-id-field.mjs +0 -4
  28. package/dist/db/adapter/get-model-name.d.mts +1 -2
  29. package/dist/db/adapter/get-model-name.mjs +0 -3
  30. package/dist/db/adapter/index.d.mts +9 -2
  31. package/dist/db/adapter/index.mjs +0 -3
  32. package/dist/db/adapter/types.d.mts +1 -2
  33. package/dist/db/adapter/utils.d.mts +1 -2
  34. package/dist/db/adapter/utils.mjs +0 -2
  35. package/dist/db/get-tables.d.mts +1 -2
  36. package/dist/db/get-tables.mjs +0 -2
  37. package/dist/db/index.mjs +1 -2
  38. package/dist/db/plugin.d.mts +1 -2
  39. package/dist/db/schema/account.d.mts +1 -2
  40. package/dist/db/schema/account.mjs +0 -3
  41. package/dist/db/schema/rate-limit.d.mts +1 -2
  42. package/dist/db/schema/rate-limit.mjs +0 -3
  43. package/dist/db/schema/session.d.mts +1 -2
  44. package/dist/db/schema/session.mjs +0 -3
  45. package/dist/db/schema/shared.d.mts +1 -2
  46. package/dist/db/schema/shared.mjs +0 -3
  47. package/dist/db/schema/user.d.mts +1 -2
  48. package/dist/db/schema/user.mjs +0 -3
  49. package/dist/db/schema/verification.d.mts +1 -2
  50. package/dist/db/schema/verification.mjs +0 -3
  51. package/dist/db/type.d.mts +1 -2
  52. package/dist/env/color-depth.d.mts +1 -2
  53. package/dist/env/color-depth.mjs +0 -3
  54. package/dist/env/env-impl.d.mts +1 -2
  55. package/dist/env/env-impl.mjs +0 -2
  56. package/dist/env/index.mjs +1 -2
  57. package/dist/env/logger.d.mts +1 -2
  58. package/dist/env/logger.mjs +0 -3
  59. package/dist/error/codes.d.mts +1 -2
  60. package/dist/error/codes.mjs +0 -3
  61. package/dist/error/index.d.mts +1 -2
  62. package/dist/error/index.mjs +0 -3
  63. package/dist/index.mjs +1 -1
  64. package/dist/instrumentation/attributes.d.mts +1 -2
  65. package/dist/instrumentation/attributes.mjs +0 -3
  66. package/dist/instrumentation/index.mjs +1 -2
  67. package/dist/instrumentation/tracer.d.mts +1 -2
  68. package/dist/instrumentation/tracer.mjs +29 -16
  69. package/dist/oauth2/client-credentials-token.d.mts +1 -2
  70. package/dist/oauth2/client-credentials-token.mjs +0 -3
  71. package/dist/oauth2/create-authorization-url.d.mts +1 -2
  72. package/dist/oauth2/create-authorization-url.mjs +0 -3
  73. package/dist/oauth2/index.mjs +1 -2
  74. package/dist/oauth2/oauth-provider.d.mts +1 -2
  75. package/dist/oauth2/refresh-access-token.d.mts +1 -2
  76. package/dist/oauth2/refresh-access-token.mjs +0 -3
  77. package/dist/oauth2/utils.d.mts +1 -2
  78. package/dist/oauth2/utils.mjs +0 -3
  79. package/dist/oauth2/validate-authorization-code.d.mts +1 -2
  80. package/dist/oauth2/validate-authorization-code.mjs +0 -4
  81. package/dist/oauth2/verify.d.mts +1 -2
  82. package/dist/oauth2/verify.mjs +0 -4
  83. package/dist/social-providers/apple.d.mts +1 -2
  84. package/dist/social-providers/apple.mjs +0 -4
  85. package/dist/social-providers/atlassian.d.mts +1 -2
  86. package/dist/social-providers/atlassian.mjs +0 -5
  87. package/dist/social-providers/cognito.d.mts +1 -2
  88. package/dist/social-providers/cognito.mjs +0 -5
  89. package/dist/social-providers/discord.d.mts +1 -2
  90. package/dist/social-providers/discord.mjs +0 -4
  91. package/dist/social-providers/dropbox.d.mts +1 -2
  92. package/dist/social-providers/dropbox.mjs +0 -4
  93. package/dist/social-providers/facebook.d.mts +1 -2
  94. package/dist/social-providers/facebook.mjs +0 -4
  95. package/dist/social-providers/figma.d.mts +1 -2
  96. package/dist/social-providers/figma.mjs +0 -5
  97. package/dist/social-providers/github.d.mts +1 -2
  98. package/dist/social-providers/github.mjs +0 -5
  99. package/dist/social-providers/gitlab.d.mts +1 -2
  100. package/dist/social-providers/gitlab.mjs +0 -4
  101. package/dist/social-providers/google.d.mts +1 -2
  102. package/dist/social-providers/google.mjs +0 -5
  103. package/dist/social-providers/huggingface.d.mts +1 -2
  104. package/dist/social-providers/huggingface.mjs +0 -4
  105. package/dist/social-providers/index.d.mts +1 -2
  106. package/dist/social-providers/index.mjs +0 -3
  107. package/dist/social-providers/kakao.d.mts +1 -2
  108. package/dist/social-providers/kakao.mjs +0 -4
  109. package/dist/social-providers/kick.d.mts +1 -2
  110. package/dist/social-providers/kick.mjs +0 -4
  111. package/dist/social-providers/line.d.mts +1 -2
  112. package/dist/social-providers/line.mjs +0 -4
  113. package/dist/social-providers/linear.d.mts +1 -2
  114. package/dist/social-providers/linear.mjs +0 -4
  115. package/dist/social-providers/linkedin.d.mts +1 -2
  116. package/dist/social-providers/linkedin.mjs +0 -4
  117. package/dist/social-providers/microsoft-entra-id.d.mts +1 -2
  118. package/dist/social-providers/microsoft-entra-id.mjs +0 -5
  119. package/dist/social-providers/naver.d.mts +1 -2
  120. package/dist/social-providers/naver.mjs +0 -4
  121. package/dist/social-providers/notion.d.mts +1 -2
  122. package/dist/social-providers/notion.mjs +0 -4
  123. package/dist/social-providers/paybin.d.mts +1 -2
  124. package/dist/social-providers/paybin.mjs +0 -5
  125. package/dist/social-providers/paypal.d.mts +1 -2
  126. package/dist/social-providers/paypal.mjs +0 -5
  127. package/dist/social-providers/polar.d.mts +1 -2
  128. package/dist/social-providers/polar.mjs +0 -4
  129. package/dist/social-providers/railway.d.mts +1 -2
  130. package/dist/social-providers/railway.mjs +0 -4
  131. package/dist/social-providers/reddit.d.mts +1 -2
  132. package/dist/social-providers/reddit.mjs +0 -4
  133. package/dist/social-providers/roblox.d.mts +1 -2
  134. package/dist/social-providers/roblox.mjs +0 -4
  135. package/dist/social-providers/salesforce.d.mts +1 -2
  136. package/dist/social-providers/salesforce.mjs +0 -5
  137. package/dist/social-providers/slack.d.mts +1 -2
  138. package/dist/social-providers/slack.mjs +0 -4
  139. package/dist/social-providers/spotify.d.mts +1 -2
  140. package/dist/social-providers/spotify.mjs +0 -4
  141. package/dist/social-providers/tiktok.d.mts +1 -2
  142. package/dist/social-providers/tiktok.mjs +0 -4
  143. package/dist/social-providers/twitch.d.mts +1 -2
  144. package/dist/social-providers/twitch.mjs +0 -5
  145. package/dist/social-providers/twitter.d.mts +1 -2
  146. package/dist/social-providers/twitter.mjs +0 -4
  147. package/dist/social-providers/vercel.d.mts +1 -2
  148. package/dist/social-providers/vercel.mjs +0 -4
  149. package/dist/social-providers/vk.d.mts +1 -2
  150. package/dist/social-providers/vk.mjs +0 -4
  151. package/dist/social-providers/wechat.d.mts +1 -2
  152. package/dist/social-providers/wechat.mjs +0 -3
  153. package/dist/social-providers/zoom.d.mts +1 -2
  154. package/dist/social-providers/zoom.mjs +0 -4
  155. package/dist/types/context.d.mts +3 -5
  156. package/dist/types/cookie.d.mts +1 -2
  157. package/dist/types/helper.d.mts +1 -2
  158. package/dist/types/init-options.d.mts +14 -6
  159. package/dist/types/plugin-client.d.mts +2 -2
  160. package/dist/types/plugin.d.mts +6 -3
  161. package/dist/types/secret.d.mts +1 -2
  162. package/dist/utils/db.d.mts +1 -2
  163. package/dist/utils/db.mjs +0 -2
  164. package/dist/utils/deprecate.d.mts +1 -2
  165. package/dist/utils/deprecate.mjs +0 -2
  166. package/dist/utils/error-codes.d.mts +1 -2
  167. package/dist/utils/error-codes.mjs +0 -2
  168. package/dist/utils/fetch-metadata.d.mts +1 -2
  169. package/dist/utils/fetch-metadata.mjs +0 -2
  170. package/dist/utils/id.d.mts +1 -2
  171. package/dist/utils/id.mjs +0 -3
  172. package/dist/utils/ip.d.mts +1 -2
  173. package/dist/utils/ip.mjs +0 -3
  174. package/dist/utils/json.d.mts +1 -2
  175. package/dist/utils/json.mjs +0 -4
  176. package/dist/utils/string.d.mts +1 -2
  177. package/dist/utils/string.mjs +0 -2
  178. package/dist/utils/url.d.mts +1 -2
  179. package/dist/utils/url.mjs +0 -2
  180. package/package.json +11 -9
  181. package/src/api/index.ts +151 -41
  182. package/src/context/endpoint-context.ts +2 -1
  183. package/src/db/adapter/factory.ts +2 -0
  184. package/src/db/adapter/index.ts +8 -0
  185. package/src/instrumentation/tracer.ts +40 -12
  186. package/src/social-providers/index.ts +0 -2
  187. package/src/types/context.ts +2 -3
  188. package/src/types/init-options.ts +13 -4
  189. package/src/types/plugin-client.ts +1 -0
  190. package/src/types/plugin.ts +15 -1
  191. package/dist/api/index.mjs.map +0 -1
  192. package/dist/async_hooks/index.mjs.map +0 -1
  193. package/dist/async_hooks/pure.index.mjs.map +0 -1
  194. package/dist/context/endpoint-context.mjs.map +0 -1
  195. package/dist/context/global.mjs.map +0 -1
  196. package/dist/context/request-state.mjs.map +0 -1
  197. package/dist/context/transaction.mjs.map +0 -1
  198. package/dist/db/adapter/factory.mjs.map +0 -1
  199. package/dist/db/adapter/get-default-field-name.mjs.map +0 -1
  200. package/dist/db/adapter/get-default-model-name.mjs.map +0 -1
  201. package/dist/db/adapter/get-field-attributes.mjs.map +0 -1
  202. package/dist/db/adapter/get-field-name.mjs.map +0 -1
  203. package/dist/db/adapter/get-id-field.mjs.map +0 -1
  204. package/dist/db/adapter/get-model-name.mjs.map +0 -1
  205. package/dist/db/adapter/index.mjs.map +0 -1
  206. package/dist/db/adapter/utils.mjs.map +0 -1
  207. package/dist/db/get-tables.mjs.map +0 -1
  208. package/dist/db/schema/account.mjs.map +0 -1
  209. package/dist/db/schema/rate-limit.mjs.map +0 -1
  210. package/dist/db/schema/session.mjs.map +0 -1
  211. package/dist/db/schema/shared.mjs.map +0 -1
  212. package/dist/db/schema/user.mjs.map +0 -1
  213. package/dist/db/schema/verification.mjs.map +0 -1
  214. package/dist/env/color-depth.mjs.map +0 -1
  215. package/dist/env/env-impl.mjs.map +0 -1
  216. package/dist/env/logger.mjs.map +0 -1
  217. package/dist/error/codes.mjs.map +0 -1
  218. package/dist/error/index.mjs.map +0 -1
  219. package/dist/instrumentation/attributes.mjs.map +0 -1
  220. package/dist/instrumentation/tracer.mjs.map +0 -1
  221. package/dist/oauth2/client-credentials-token.mjs.map +0 -1
  222. package/dist/oauth2/create-authorization-url.mjs.map +0 -1
  223. package/dist/oauth2/refresh-access-token.mjs.map +0 -1
  224. package/dist/oauth2/utils.mjs.map +0 -1
  225. package/dist/oauth2/validate-authorization-code.mjs.map +0 -1
  226. package/dist/oauth2/verify.mjs.map +0 -1
  227. package/dist/social-providers/apple.mjs.map +0 -1
  228. package/dist/social-providers/atlassian.mjs.map +0 -1
  229. package/dist/social-providers/cognito.mjs.map +0 -1
  230. package/dist/social-providers/discord.mjs.map +0 -1
  231. package/dist/social-providers/dropbox.mjs.map +0 -1
  232. package/dist/social-providers/facebook.mjs.map +0 -1
  233. package/dist/social-providers/figma.mjs.map +0 -1
  234. package/dist/social-providers/github.mjs.map +0 -1
  235. package/dist/social-providers/gitlab.mjs.map +0 -1
  236. package/dist/social-providers/google.mjs.map +0 -1
  237. package/dist/social-providers/huggingface.mjs.map +0 -1
  238. package/dist/social-providers/index.mjs.map +0 -1
  239. package/dist/social-providers/kakao.mjs.map +0 -1
  240. package/dist/social-providers/kick.mjs.map +0 -1
  241. package/dist/social-providers/line.mjs.map +0 -1
  242. package/dist/social-providers/linear.mjs.map +0 -1
  243. package/dist/social-providers/linkedin.mjs.map +0 -1
  244. package/dist/social-providers/microsoft-entra-id.mjs.map +0 -1
  245. package/dist/social-providers/naver.mjs.map +0 -1
  246. package/dist/social-providers/notion.mjs.map +0 -1
  247. package/dist/social-providers/paybin.mjs.map +0 -1
  248. package/dist/social-providers/paypal.mjs.map +0 -1
  249. package/dist/social-providers/polar.mjs.map +0 -1
  250. package/dist/social-providers/railway.mjs.map +0 -1
  251. package/dist/social-providers/reddit.mjs.map +0 -1
  252. package/dist/social-providers/roblox.mjs.map +0 -1
  253. package/dist/social-providers/salesforce.mjs.map +0 -1
  254. package/dist/social-providers/slack.mjs.map +0 -1
  255. package/dist/social-providers/spotify.mjs.map +0 -1
  256. package/dist/social-providers/tiktok.mjs.map +0 -1
  257. package/dist/social-providers/twitch.mjs.map +0 -1
  258. package/dist/social-providers/twitter.mjs.map +0 -1
  259. package/dist/social-providers/vercel.mjs.map +0 -1
  260. package/dist/social-providers/vk.mjs.map +0 -1
  261. package/dist/social-providers/wechat.mjs.map +0 -1
  262. package/dist/social-providers/zoom.mjs.map +0 -1
  263. package/dist/utils/db.mjs.map +0 -1
  264. package/dist/utils/deprecate.mjs.map +0 -1
  265. package/dist/utils/error-codes.mjs.map +0 -1
  266. package/dist/utils/fetch-metadata.mjs.map +0 -1
  267. package/dist/utils/id.mjs.map +0 -1
  268. package/dist/utils/ip.mjs.map +0 -1
  269. package/dist/utils/json.mjs.map +0 -1
  270. package/dist/utils/string.mjs.map +0 -1
  271. package/dist/utils/url.mjs.map +0 -1
  272. package/src/context/request-state.test.ts +0 -94
  273. package/src/db/adapter/get-id-field.test.ts +0 -222
  274. package/src/db/test/get-tables.test.ts +0 -116
  275. package/src/env/logger.test.ts +0 -34
  276. package/src/instrumentation/instrumentation.test.ts +0 -139
  277. package/src/oauth2/refresh-access-token.test.ts +0 -90
  278. package/src/oauth2/validate-token.test.ts +0 -229
  279. package/src/utils/deprecate.test.ts +0 -71
  280. package/src/utils/fetch-metadata.test.ts +0 -28
  281. package/src/utils/ip.test.ts +0 -255
@@ -1,255 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { createRateLimitKey, isValidIP, normalizeIP } from "./ip";
3
-
4
- describe("IP Normalization", () => {
5
- describe("isValidIP", () => {
6
- it("should validate IPv4 addresses", () => {
7
- expect(isValidIP("192.168.1.1")).toBe(true);
8
- expect(isValidIP("127.0.0.1")).toBe(true);
9
- expect(isValidIP("0.0.0.0")).toBe(true);
10
- expect(isValidIP("255.255.255.255")).toBe(true);
11
- });
12
-
13
- it("should validate IPv6 addresses", () => {
14
- expect(isValidIP("2001:db8::1")).toBe(true);
15
- expect(isValidIP("::1")).toBe(true);
16
- expect(isValidIP("::")).toBe(true);
17
- expect(isValidIP("2001:0db8:0000:0000:0000:0000:0000:0001")).toBe(true);
18
- });
19
-
20
- it("should reject invalid IPs", () => {
21
- expect(isValidIP("not-an-ip")).toBe(false);
22
- expect(isValidIP("999.999.999.999")).toBe(false);
23
- expect(isValidIP("gggg::1")).toBe(false);
24
- });
25
- });
26
-
27
- describe("IPv4 Normalization", () => {
28
- it("should return IPv4 addresses unchanged", () => {
29
- expect(normalizeIP("192.168.1.1")).toBe("192.168.1.1");
30
- expect(normalizeIP("127.0.0.1")).toBe("127.0.0.1");
31
- expect(normalizeIP("10.0.0.1")).toBe("10.0.0.1");
32
- });
33
- });
34
-
35
- describe("IPv6 Normalization", () => {
36
- it("should normalize compressed IPv6 to full form", () => {
37
- expect(normalizeIP("2001:db8::1", { ipv6Subnet: 128 })).toBe(
38
- "2001:0db8:0000:0000:0000:0000:0000:0001",
39
- );
40
- expect(normalizeIP("::1", { ipv6Subnet: 128 })).toBe(
41
- "0000:0000:0000:0000:0000:0000:0000:0001",
42
- );
43
- expect(normalizeIP("::", { ipv6Subnet: 128 })).toBe(
44
- "0000:0000:0000:0000:0000:0000:0000:0000",
45
- );
46
- });
47
-
48
- it("should normalize uppercase to lowercase", () => {
49
- expect(normalizeIP("2001:DB8::1", { ipv6Subnet: 128 })).toBe(
50
- "2001:0db8:0000:0000:0000:0000:0000:0001",
51
- );
52
- expect(normalizeIP("2001:0DB8:ABCD:EF00::1", { ipv6Subnet: 128 })).toBe(
53
- "2001:0db8:abcd:ef00:0000:0000:0000:0001",
54
- );
55
- });
56
-
57
- it("should handle various IPv6 formats consistently", () => {
58
- // All these represent the same address
59
- const normalized = "2001:0db8:0000:0000:0000:0000:0000:0001";
60
- expect(normalizeIP("2001:db8::1", { ipv6Subnet: 128 })).toBe(normalized);
61
- expect(normalizeIP("2001:0db8:0:0:0:0:0:1", { ipv6Subnet: 128 })).toBe(
62
- normalized,
63
- );
64
- expect(normalizeIP("2001:db8:0::1", { ipv6Subnet: 128 })).toBe(
65
- normalized,
66
- );
67
- expect(normalizeIP("2001:0db8::0:0:0:1", { ipv6Subnet: 128 })).toBe(
68
- normalized,
69
- );
70
- });
71
-
72
- it("should handle IPv6 with :: at different positions", () => {
73
- expect(
74
- normalizeIP("2001:db8:85a3::8a2e:370:7334", { ipv6Subnet: 128 }),
75
- ).toBe("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
76
- expect(normalizeIP("::ffff:192.0.2.1")).not.toContain("::");
77
- });
78
- });
79
-
80
- describe("IPv4-mapped IPv6 Conversion", () => {
81
- it("should convert IPv4-mapped IPv6 to IPv4", () => {
82
- expect(normalizeIP("::ffff:192.0.2.1")).toBe("192.0.2.1");
83
- expect(normalizeIP("::ffff:127.0.0.1")).toBe("127.0.0.1");
84
- expect(normalizeIP("::FFFF:10.0.0.1")).toBe("10.0.0.1");
85
- });
86
-
87
- it("should handle hex-encoded IPv4 in mapped addresses", () => {
88
- // ::ffff:c000:0201 = ::ffff:192.0.2.1 = 192.0.2.1
89
- expect(normalizeIP("::ffff:c000:0201")).toBe("192.0.2.1");
90
- // ::ffff:7f00:0001 = ::ffff:127.0.0.1 = 127.0.0.1
91
- expect(normalizeIP("::ffff:7f00:0001")).toBe("127.0.0.1");
92
- });
93
-
94
- it("should handle full form IPv4-mapped IPv6", () => {
95
- expect(normalizeIP("0:0:0:0:0:ffff:192.0.2.1")).toBe("192.0.2.1");
96
- });
97
- });
98
-
99
- describe("IPv6 Subnet Support", () => {
100
- it("should extract /64 subnet", () => {
101
- /* cspell:disable-next-line */
102
- const ip1 = normalizeIP("2001:db8:0:0:1234:5678:90ab:cdef", {
103
- ipv6Subnet: 64,
104
- });
105
- const ip2 = normalizeIP("2001:db8:0:0:ffff:ffff:ffff:ffff", {
106
- ipv6Subnet: 64,
107
- });
108
- // Both should have same /64 prefix
109
- expect(ip1).toBe("2001:0db8:0000:0000:0000:0000:0000:0000");
110
- expect(ip2).toBe("2001:0db8:0000:0000:0000:0000:0000:0000");
111
- expect(ip1).toBe(ip2);
112
- });
113
-
114
- it("should extract /48 subnet", () => {
115
- /* cspell:disable-next-line */
116
- const ip1 = normalizeIP("2001:db8:1234:5678:90ab:cdef:1234:5678", {
117
- ipv6Subnet: 48,
118
- });
119
- const ip2 = normalizeIP("2001:db8:1234:ffff:ffff:ffff:ffff:ffff", {
120
- ipv6Subnet: 48,
121
- });
122
- // Both should have same /48 prefix
123
- expect(ip1).toBe("2001:0db8:1234:0000:0000:0000:0000:0000");
124
- expect(ip2).toBe("2001:0db8:1234:0000:0000:0000:0000:0000");
125
- expect(ip1).toBe(ip2);
126
- });
127
-
128
- it("should extract /32 subnet", () => {
129
- /* cspell:disable-next-line */
130
- const ip1 = normalizeIP("2001:db8:1234:5678:90ab:cdef:1234:5678", {
131
- ipv6Subnet: 32,
132
- });
133
- const ip2 = normalizeIP("2001:db8:ffff:ffff:ffff:ffff:ffff:ffff", {
134
- ipv6Subnet: 32,
135
- });
136
- // Both should have same /32 prefix
137
- expect(ip1).toBe("2001:0db8:0000:0000:0000:0000:0000:0000");
138
- expect(ip2).toBe("2001:0db8:0000:0000:0000:0000:0000:0000");
139
- expect(ip1).toBe(ip2);
140
- });
141
-
142
- it("should handle /64 subnet by default", () => {
143
- const ip1 = normalizeIP("2001:db8::1");
144
- const ip2 = normalizeIP("2001:db8::1", { ipv6Subnet: 64 });
145
- expect(ip1).toBe(ip2);
146
- expect(ip1).toBe("2001:0db8:0000:0000:0000:0000:0000:0000");
147
- });
148
-
149
- it("should not affect IPv4 addresses when ipv6Subnet is set", () => {
150
- expect(normalizeIP("192.168.1.1", { ipv6Subnet: 64 })).toBe(
151
- "192.168.1.1",
152
- );
153
- });
154
- });
155
-
156
- describe("Rate Limit Key Creation", () => {
157
- it("should create keys with separator", () => {
158
- expect(createRateLimitKey("192.168.1.1", "/sign-in")).toBe(
159
- "192.168.1.1|/sign-in",
160
- );
161
- expect(createRateLimitKey("2001:db8::1", "/api/auth")).toBe(
162
- "2001:db8::1|/api/auth",
163
- );
164
- });
165
-
166
- it("should prevent collision attacks", () => {
167
- // Without separator: "192.0.2.1" + "/sign-in" = "192.0.2.1/sign-in"
168
- // "192.0.2" + ".1/sign-in" = "192.0.2.1/sign-in"
169
- // With separator: they're different
170
- const key1 = createRateLimitKey("192.0.2.1", "/sign-in");
171
- const key2 = createRateLimitKey("192.0.2", ".1/sign-in");
172
- expect(key1).not.toBe(key2);
173
- expect(key1).toBe("192.0.2.1|/sign-in");
174
- expect(key2).toBe("192.0.2|.1/sign-in");
175
- });
176
- });
177
-
178
- describe("Security: Bypass Prevention", () => {
179
- it("should prevent IPv6 representation bypass", () => {
180
- // Attacker tries different representations of same address
181
- const representations = [
182
- "2001:db8::1",
183
- "2001:DB8::1",
184
- "2001:0db8::1",
185
- "2001:db8:0::1",
186
- "2001:0db8:0:0:0:0:0:1",
187
- "2001:db8::0:1",
188
- ];
189
-
190
- const normalized = representations.map((ip) =>
191
- normalizeIP(ip, { ipv6Subnet: 128 }),
192
- );
193
- // All should normalize to the same value
194
- const uniqueValues = new Set(normalized);
195
- expect(uniqueValues.size).toBe(1);
196
- expect(normalized[0]).toBe("2001:0db8:0000:0000:0000:0000:0000:0001");
197
- });
198
-
199
- it("should prevent IPv4-mapped bypass", () => {
200
- // Attacker switches between IPv4 and IPv4-mapped IPv6
201
- const ip1 = normalizeIP("192.0.2.1");
202
- const ip2 = normalizeIP("::ffff:192.0.2.1");
203
- const ip3 = normalizeIP("::FFFF:192.0.2.1");
204
- const ip4 = normalizeIP("::ffff:c000:0201");
205
-
206
- // All should normalize to the same IPv4
207
- expect(ip1).toBe("192.0.2.1");
208
- expect(ip2).toBe("192.0.2.1");
209
- expect(ip3).toBe("192.0.2.1");
210
- expect(ip4).toBe("192.0.2.1");
211
- });
212
-
213
- it("should group IPv6 subnet attacks", () => {
214
- // Attacker rotates through addresses in their /64 allocation
215
- const attackIPs = [
216
- "2001:db8:abcd:1234:0000:0000:0000:0001",
217
- "2001:db8:abcd:1234:1111:2222:3333:4444",
218
- "2001:db8:abcd:1234:ffff:ffff:ffff:ffff",
219
- "2001:db8:abcd:1234:aaaa:bbbb:cccc:dddd",
220
- ];
221
-
222
- const normalized = attackIPs.map((ip) =>
223
- normalizeIP(ip, { ipv6Subnet: 64 }),
224
- );
225
-
226
- // All should map to same /64 subnet
227
- const uniqueValues = new Set(normalized);
228
- expect(uniqueValues.size).toBe(1);
229
- expect(normalized[0]).toBe("2001:0db8:abcd:1234:0000:0000:0000:0000");
230
- });
231
- });
232
-
233
- describe("Edge Cases", () => {
234
- it("should handle localhost addresses", () => {
235
- expect(normalizeIP("127.0.0.1")).toBe("127.0.0.1");
236
- expect(normalizeIP("::1", { ipv6Subnet: 128 })).toBe(
237
- "0000:0000:0000:0000:0000:0000:0000:0001",
238
- );
239
- });
240
-
241
- it("should handle all-zeros address", () => {
242
- expect(normalizeIP("0.0.0.0")).toBe("0.0.0.0");
243
- expect(normalizeIP("::", { ipv6Subnet: 128 })).toBe(
244
- "0000:0000:0000:0000:0000:0000:0000:0000",
245
- );
246
- });
247
-
248
- it("should handle link-local addresses", () => {
249
- expect(normalizeIP("169.254.0.1")).toBe("169.254.0.1");
250
- expect(normalizeIP("fe80::1", { ipv6Subnet: 128 })).toBe(
251
- "fe80:0000:0000:0000:0000:0000:0000:0001",
252
- );
253
- });
254
- });
255
- });