@revolugo/common 7.4.2-alpha.0 → 7.4.2-alpha.10

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revolugo/common",
3
- "version": "7.4.2-alpha.0",
3
+ "version": "7.4.2-alpha.10",
4
4
  "private": false,
5
5
  "description": "Revolugo common",
6
6
  "author": "Revolugo",
@@ -0,0 +1,62 @@
1
+ import { describe, expect, test } from 'vitest'
2
+
3
+ import { getUserIpAddress } from './get-user-ip-address.ts'
4
+
5
+ describe('getUserIpAddress', () => {
6
+ test('UT-1a: extracts first IP from x-forwarded-for (comma-separated)', () => {
7
+ const headers = new Headers({
8
+ 'x-forwarded-for': '203.0.113.1, 70.41.3.18, 150.172.238.178',
9
+ })
10
+ expect(getUserIpAddress(headers)).toBe('203.0.113.1')
11
+ })
12
+
13
+ test('UT-1a: extracts single IP from x-forwarded-for', () => {
14
+ const headers = new Headers({ 'x-forwarded-for': '203.0.113.1' })
15
+ expect(getUserIpAddress(headers)).toBe('203.0.113.1')
16
+ })
17
+
18
+ test('UT-1b: extracts IP from cf-connecting-ip', () => {
19
+ const headers = new Headers({ 'cf-connecting-ip': '198.51.100.1' })
20
+ expect(getUserIpAddress(headers)).toBe('198.51.100.1')
21
+ })
22
+
23
+ test('UT-1c: extracts IP from x-real-ip', () => {
24
+ const headers = new Headers({ 'x-real-ip': '198.51.100.2' })
25
+ expect(getUserIpAddress(headers)).toBe('198.51.100.2')
26
+ })
27
+
28
+ test('UT-1c: extracts IP from true-client-ip', () => {
29
+ const headers = new Headers({ 'true-client-ip': '198.51.100.3' })
30
+ expect(getUserIpAddress(headers)).toBe('198.51.100.3')
31
+ })
32
+
33
+ test('UT-1c: extracts IP from x-client-ip', () => {
34
+ const headers = new Headers({ 'x-client-ip': '198.51.100.4' })
35
+ expect(getUserIpAddress(headers)).toBe('198.51.100.4')
36
+ })
37
+
38
+ test('UT-1a: x-forwarded-for takes priority over other headers', () => {
39
+ const headers = new Headers({
40
+ 'cf-connecting-ip': '198.51.100.1',
41
+ 'x-forwarded-for': '203.0.113.1',
42
+ })
43
+ expect(getUserIpAddress(headers)).toBe('203.0.113.1')
44
+ })
45
+
46
+ test('UT-1d: returns null when no IP headers present', () => {
47
+ const headers = new Headers({ 'content-type': 'application/json' })
48
+ expect(getUserIpAddress(headers)).toBeNull()
49
+ })
50
+
51
+ test('UT-1e: extracts IP from Forwarded header (RFC 7239)', () => {
52
+ const headers = new Headers({
53
+ forwarded: 'for=192.0.2.60;proto=http;by=203.0.113.43',
54
+ })
55
+ expect(getUserIpAddress(headers)).toBe('192.0.2.60')
56
+ })
57
+
58
+ test('UT-1e: extracts quoted IP from Forwarded header', () => {
59
+ const headers = new Headers({ forwarded: 'for="192.0.2.60"' })
60
+ expect(getUserIpAddress(headers)).toBe('192.0.2.60')
61
+ })
62
+ })
@@ -0,0 +1,28 @@
1
+ const IP_HEADERS = [
2
+ 'x-forwarded-for',
3
+ 'cf-connecting-ip',
4
+ 'x-real-ip',
5
+ 'true-client-ip',
6
+ 'x-client-ip',
7
+ ] as const
8
+
9
+ export function getUserIpAddress(headers: Headers): string | null {
10
+ for (const header of IP_HEADERS) {
11
+ const value = headers.get(header)
12
+ if (value) {
13
+ return header === 'x-forwarded-for'
14
+ ? (value.split(',')[0]?.trim() ?? null)
15
+ : value
16
+ }
17
+ }
18
+
19
+ const forwarded = headers.get('forwarded')
20
+ if (forwarded) {
21
+ const match = /for=["']?([^;"',\s]+)/u.exec(forwarded)
22
+ if (match?.[1]) {
23
+ return match[1]
24
+ }
25
+ }
26
+
27
+ return null
28
+ }
@@ -26,6 +26,7 @@ export * from './get-random-element-from-array.ts'
26
26
  export * from './get-random-hex-color.ts'
27
27
  export * from './get-random-int.ts'
28
28
  export * from './get-sanitized-room-count.ts'
29
+ export * from './get-user-ip-address.ts'
29
30
  export * from './group-by.ts'
30
31
  export * from './images.ts'
31
32
  export * from './is-empty.ts'