auth-email-context.test.ts154 lines · main
1import { describe, expect, test } from 'bun:test';
2
3import {
4 AUTH_EMAIL_TIMEZONE,
5 authEmailRequestMetaHtml,
6 authEmailRequestMetaText,
7 clientIpFromHeaders,
8 formatAuthEmailDeviceLocation,
9 formatAuthEmailPlatform,
10 formatAuthEmailTime,
11} from './auth-email-context.js';
12import { nearestCityFromCoords } from './nearest-city.js';
13
14describe('auth email request meta', () => {
15 test('platform from Chrome on macOS', () => {
16 const ua =
17 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36';
18 expect(formatAuthEmailPlatform(ua)).toBe('Chrome browser on macOS device');
19 });
20
21 test('platform detects Brave from Sec-CH-UA even when UA looks like Chrome', () => {
22 const ua =
23 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36';
24 const ch =
25 '"Not A(Brand";v="8", "Chromium";v="126", "Brave";v="126"';
26 expect(formatAuthEmailPlatform(ua, ch)).toBe(
27 'Brave browser on macOS device',
28 );
29 });
30
31 test('platform detects Brave from UA token', () => {
32 const ua =
33 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Brave/126';
34 expect(formatAuthEmailPlatform(ua)).toBe('Brave browser on macOS device');
35 });
36
37 test('platform from Safari on iPhone', () => {
38 const ua =
39 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
40 expect(formatAuthEmailPlatform(ua)).toBe(
41 'Safari browser on iPhone device',
42 );
43 });
44
45 test('device location with city + region + country + IP in parens', () => {
46 expect(
47 formatAuthEmailDeviceLocation(
48 {
49 city: 'Ghent',
50 region: 'East Flanders',
51 country: 'Belgium',
52 latitude: 51.05,
53 longitude: 3.72,
54 },
55 '109.128.54.152',
56 ),
57 ).toBe('Ghent, East Flanders, Belgium (109.128.54.152)');
58 });
59
60 test('device location nearest-city when MaxMind has only country + coords', () => {
61 // Belgium country centroid (real MaxMind sample for 193.74.157.185)
62 expect(
63 formatAuthEmailDeviceLocation(
64 {
65 city: null,
66 region: null,
67 country: 'Belgium',
68 latitude: 50.8509,
69 longitude: 4.3447,
70 accuracyRadiusKm: 100,
71 },
72 '193.74.157.185',
73 ),
74 ).toBe('Brussels, Belgium (193.74.157.185)');
75 });
76
77 test('device location IP only when geo missing', () => {
78 expect(formatAuthEmailDeviceLocation(null, '1.2.3.4')).toBe(
79 'Location unavailable (1.2.3.4)',
80 );
81 });
82
83 test('nearestCityFromCoords maps Brussels centroid', () => {
84 const n = nearestCityFromCoords(50.8509, 4.3447, 120);
85 expect(n?.name).toBe('Brussels');
86 expect(n?.country).toBe('Belgium');
87 });
88
89 test('time uses Europe/Brussels and US-style "at" format', () => {
90 // 2026-07-25 08:48:35 UTC = 10:48:35 AM in Brussels (CEST, GMT+2)
91 const t = formatAuthEmailTime(
92 new Date('2026-07-25T08:48:35.000Z'),
93 AUTH_EMAIL_TIMEZONE,
94 );
95 expect(t).toContain('July');
96 expect(t).toContain('2026');
97 expect(t).toContain('25');
98 expect(t).toMatch(/10:48:35/);
99 expect(t).toMatch(/\bAM\b/);
100 expect(t).toContain(' at ');
101 expect(t).toMatch(/GMT\+2|UTC\+2|\+02/);
102 });
103
104 test('html uses Platform / Device location / Time + Lucide SVG (no emoji)', () => {
105 const meta = {
106 platform: 'Brave browser on macOS device',
107 deviceLocation: 'Ghent, East Flanders, Belgium (109.128.54.152)',
108 time: 'July 25, 2026 at 10:48:35 AM GMT+2',
109 };
110 const html = authEmailRequestMetaHtml(meta);
111 expect(html).toContain('Platform');
112 expect(html).toContain('Device location');
113 expect(html).toContain('Time');
114 expect(html).toContain('Brave browser on macOS device');
115 expect(html).toContain('109.128.54.152');
116 // Official Lucide path fragments (monitor / map-pin / clock)
117 expect(html).toContain('viewBox="0 0 24 24"');
118 expect(html).toContain('width="18"');
119 expect(html).toContain('rect width="20" height="14"'); // monitor
120 expect(html).toContain('M20 10c0 4.993'); // map-pin
121 expect(html).toContain('polyline points="12 6 12 12 16 14"'); // clock
122 expect(html).not.toContain('Device & browser');
123 expect(html).not.toContain('Sent at');
124 // Never emoji — flndrn rule (lucide-animated.com shapes only)
125 expect(html).not.toContain('💻');
126 expect(html).not.toContain('📍');
127 expect(html).not.toContain('🕐');
128 expect(html).not.toContain('🖥');
129 expect(html).not.toContain('🌍');
130 expect(html).not.toContain('<script>');
131
132 const text = authEmailRequestMetaText(meta);
133 expect(text).toContain('Platform: Brave browser on macOS device');
134 expect(text).toContain('Device location: Ghent');
135 expect(text).toContain('Time: July 25');
136 });
137
138 test('clientIpFromHeaders prefers x-briven-client-ip', () => {
139 const h = (n: string) => {
140 if (n === 'x-briven-client-ip') return '203.0.113.50';
141 if (n === 'x-forwarded-for') return '10.0.0.1, 203.0.113.50';
142 return null;
143 };
144 expect(clientIpFromHeaders(h)).toBe('203.0.113.50');
145 });
146
147 test('clientIpFromHeaders skips private hop for public client', () => {
148 const h = (n: string) => {
149 if (n === 'x-forwarded-for') return '10.0.0.5, 203.0.113.99';
150 return null;
151 };
152 expect(clientIpFromHeaders(h)).toBe('203.0.113.99');
153 });
154});