11import rateLimit , { ipKeyGenerator } from 'express-rate-limit' ;
2+ import axios from 'axios' ;
23import fs from 'fs' ;
34import net from 'node:net' ;
45import { authCache } from './server.js' ;
56
67const maxLimitReq = parseInt ( process . env . RATE_LIMIT ) || 50 ;
78const bannedIpsFile = './banned-ips.log' ;
89const trustedProxyCidrsRaw = String ( process . env . TRUSTED_PROXY_CIDRS || '' ) . trim ( ) ;
9- const trustedProxyAllowlist = new net . BlockList ( ) ;
10- let trustedProxyRulesLoaded = false ;
10+ const useCloudflareIps = String ( process . env . USE_CLOUDFLARE_IPS || 'false' ) . toLowerCase ( ) === 'true' ;
11+ const cloudflareIpv4Url = process . env . CLOUDFLARE_IPV4_URL || 'https://www.cloudflare.com/ips-v4' ;
12+ const cloudflareIpv6Url = process . env . CLOUDFLARE_IPV6_URL || 'https://www.cloudflare.com/ips-v6' ;
13+ let trustedProxyAllowlist = new net . BlockList ( ) ;
14+ let trustedProxyCidrs = [ ] ;
15+ let trustedProxyInitialized = false ;
1116
1217function sanitizeIpValue ( value ) {
1318 if ( typeof value !== 'string' ) return '' ;
@@ -23,35 +28,83 @@ function sanitizeIpValue(value) {
2328 return net . isIP ( cleaned ) ? cleaned : '' ;
2429}
2530
26- function loadTrustedProxyRules ( ) {
27- if ( trustedProxyRulesLoaded ) return ;
28- trustedProxyRulesLoaded = true ;
29- if ( ! trustedProxyCidrsRaw ) return ;
30-
31- const rules = trustedProxyCidrsRaw
31+ function parseCidrs ( raw ) {
32+ if ( ! raw || typeof raw !== 'string' ) return [ ] ;
33+ return raw
3234 . split ( / [ \s , ] + / )
3335 . map ( ( entry ) => entry . trim ( ) )
3436 . filter ( Boolean ) ;
37+ }
3538
36- for ( const rule of rules ) {
39+ function applyTrustedProxyCidrs ( entries , sourceLabel ) {
40+ trustedProxyAllowlist = new net . BlockList ( ) ;
41+ trustedProxyCidrs = [ ] ;
42+ const deduped = new Set ( entries ) ;
43+
44+ for ( const rule of deduped ) {
3745 const [ address , prefix ] = rule . split ( '/' ) ;
3846 const sanitizedAddress = sanitizeIpValue ( address ) ;
3947 const prefixNum = Number ( prefix ) ;
4048 const ipVersion = net . isIP ( sanitizedAddress ) ;
49+ const maxPrefix = ipVersion === 4 ? 32 : 128 ;
4150
42- if ( ! sanitizedAddress || Number . isNaN ( prefixNum ) || ! Number . isInteger ( prefixNum ) || ! ipVersion ) {
43- console . warn ( `Skipping invalid TRUSTED_PROXY_CIDRS entry: ${ rule } ` ) ;
51+ if (
52+ ! sanitizedAddress ||
53+ Number . isNaN ( prefixNum ) ||
54+ ! Number . isInteger ( prefixNum ) ||
55+ ! ipVersion ||
56+ prefixNum < 0 ||
57+ prefixNum > maxPrefix
58+ ) {
59+ console . warn ( `Skipping invalid trusted proxy CIDR from ${ sourceLabel } : ${ rule } ` ) ;
4460 continue ;
4561 }
4662
4763 const type = ipVersion === 4 ? 'ipv4' : 'ipv6' ;
4864 trustedProxyAllowlist . addSubnet ( sanitizedAddress , prefixNum , type ) ;
65+ trustedProxyCidrs . push ( `${ sanitizedAddress } /${ prefixNum } ` ) ;
66+ }
67+
68+ return trustedProxyCidrs ;
69+ }
70+
71+ function logTrustedProxyCidrs ( sourceLabel ) {
72+ if ( ! trustedProxyCidrs . length ) {
73+ console . warn ( 'No trusted proxy CIDRs configured; forwarded headers will be ignored.' ) ;
74+ return ;
4975 }
76+
77+ console . log ( `Trusted proxy CIDRs loaded from ${ sourceLabel } (${ trustedProxyCidrs . length } ):` ) ;
78+ trustedProxyCidrs . forEach ( ( cidr ) => console . log ( ` - ${ cidr } ` ) ) ;
79+ }
80+
81+ export async function initializeTrustedProxyCidrs ( ) {
82+ if ( trustedProxyInitialized ) return trustedProxyCidrs ;
83+ trustedProxyInitialized = true ;
84+
85+ if ( useCloudflareIps ) {
86+ try {
87+ const [ ipv4Res , ipv6Res ] = await Promise . all ( [
88+ axios . get ( cloudflareIpv4Url , { timeout : 5000 , responseType : 'text' } ) ,
89+ axios . get ( cloudflareIpv6Url , { timeout : 5000 , responseType : 'text' } )
90+ ] ) ;
91+ const cloudflareCidrs = [ ...parseCidrs ( ipv4Res . data ) , ...parseCidrs ( ipv6Res . data ) ] ;
92+ applyTrustedProxyCidrs ( cloudflareCidrs , 'Cloudflare' ) ;
93+ logTrustedProxyCidrs ( 'Cloudflare' ) ;
94+ return trustedProxyCidrs ;
95+ } catch ( error ) {
96+ console . error ( `Failed to fetch Cloudflare IP ranges: ${ error . message } ` ) ;
97+ console . warn ( 'Falling back to TRUSTED_PROXY_CIDRS.' ) ;
98+ }
99+ }
100+
101+ applyTrustedProxyCidrs ( parseCidrs ( trustedProxyCidrsRaw ) , 'TRUSTED_PROXY_CIDRS' ) ;
102+ logTrustedProxyCidrs ( 'TRUSTED_PROXY_CIDRS' ) ;
103+ return trustedProxyCidrs ;
50104}
51105
52106function isTrustedProxyIp ( ip ) {
53- loadTrustedProxyRules ( ) ;
54- if ( ! trustedProxyCidrsRaw ) return false ;
107+ if ( ! trustedProxyCidrs . length ) return false ;
55108 const sanitizedIp = sanitizeIpValue ( ip ) ;
56109 if ( ! sanitizedIp ) return false ;
57110 const type = net . isIP ( sanitizedIp ) === 4 ? 'ipv4' : 'ipv6' ;
0 commit comments