geoip-lite2 2.2.7 → 2.2.8-beta.2

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <br>
6
6
  <p>
7
7
  A native <a href="https://nodejs.org" target="_blank" title="Open nodejs.org">Node.js</a> API for the GeoLite data from MaxMind.<br>
8
- This product includes GeoLite data created by MaxMind, available from <a href="https://www.maxmind.com" target="_blank" title="Open www.maxmind.com">maxmind.com</a>.
8
+ This library includes GeoLite data created by MaxMind, available from <a href="https://www.maxmind.com" target="_blank" title="Open www.maxmind.com">maxmind.com</a>.
9
9
  </p>
10
10
  <a href="https://www.npmjs.com/package/geoip-lite2" target="_blank" title="geoip-lite2 - npm" style="text-decoration:none">
11
11
  <img src="https://img.shields.io/npm/dt/geoip-lite2?maxAge=3600" alt="The number of downloads">
@@ -18,26 +18,18 @@
18
18
 
19
19
 
20
20
  # 🚀 Improved GeoIP Module by [Sefinek](https://sefinek.net)
21
- This module is an enhanced and updated version of [geoip-lite](https://github.com/geoip-lite/node-geoip), carefully designed to meet the latest programming standards.
21
+ This module is an optimized version of [geoip-lite](https://github.com/geoip-lite/node-geoip) and runs slightly faster.
22
+ The project has been migrated to the [Jest](https://www.npmjs.com/package/jest) testing library.
22
23
 
23
- All components have been thoroughly updated to ensure optimal performance and functionality.
24
- The module now runs even faster, thanks to file minification!
25
-
26
- Furthermore, the testing process has been improved with the adoption of the [Jest](https://www.npmjs.com/package/jest) testing library.
27
-
28
- > I am not the primary creator of this! All copyright rights belong to the original [authors](AUTHORS).
24
+ > I am not the primary creator of this project! All copyright rights belong to the original [authors](AUTHORS).
29
25
 
30
26
 
31
27
  ## ⚠️ Important
32
- Remember to regularly update the Maxmind database. You'll need the token for this.
33
-
28
+ Remember to regularly update the MaxMind database. You'll need the token for this.
34
29
 
35
- ## 🌠 Version without a Local Database
36
- This module requires a significant amount of RAM because geolocation data is stored in memory.
37
- However, you can always opt for the official alternative, the [geoip2-api](https://www.npmjs.com/package/geoip2-api) module, which sends requests to an API server and retrieves information about specific IP addresses directly from there.
38
30
 
39
- ###Demonstration
40
- You can see this module in action using my [official API](https://api.sefinek.net). The API interface is public and can be safely used in your projects without any limits. Happy coding!
31
+ ##API
32
+ You can see this module in action using my [official API](https://api.sefinek.net). The `/api/v2/geoip` endpoint should not be used in production environments.
41
33
 
42
34
  - Specific IP: https://api.sefinek.net/api/v2/geoip/109.207.159.255
43
35
  - Client's IP: https://api.sefinek.net/api/v2/geoip/me
@@ -259,7 +251,6 @@ console.log(process.memoryUsage());
259
251
 
260
252
  ## 👥 Copyright
261
253
  `GeoIP-Lite` is Copyright 2011-2018 **Philip Tellis** <philip@bluesmoon.info>
262
- `GeoIP-Lite2` is Copyright 2023-2024 **Sefinek** <contact@sefinek.net> (https://sefinek.net)
263
254
 
264
255
 
265
256
  ## 🔐 License
@@ -1 +1 @@
1
- 9477be6926b39db95dcf6664e36bddd5900425ddb9952840ec5491d5c6ad6bdd GeoLite2-City-CSV_20250905.zip
1
+ 43cd254f51bc2e181c37b82bc3e575d702fb80e47403415369588585ee012abf GeoLite2-City-CSV_20251104.zip
@@ -1 +1 @@
1
- 952a602f47c26afc46782e468b2464fcc7a6a44418bff3819a5d1e63481de5ec GeoLite2-Country-CSV_20250905.zip
1
+ 55f23aac3290cee0cc46ea41d02c8f063357aad8446163065ea6743517b42513 GeoLite2-Country-CSV_20251104.zip
Binary file
Binary file
Binary file
Binary file
Binary file
package/dist/main.js CHANGED
@@ -1 +1 @@
1
- const{open:e,fstat:r,read:t,close:n,openSync:i,fstatSync:a,readSync:o,closeSync:l}=require('node:fs'),{join:u,resolve:c}=require('node:path'),{isIP:f}=require('node:net'),s=require('async'),{aton4:d,aton6:y,cmp6:B,ntoa4:S,ntoa6:p,cmp:g}=require('./utils.js'),I=require('./fsWatcher.js'),{version:E}=require('../package.json'),m='dataWatcher',z=c(__dirname,global.geoDataDir||process.env.GEODATADIR||'../data/'),N={city:u(z,'geoip-city.dat'),city6:u(z,'geoip-city6.dat'),cityNames:u(z,'geoip-city-names.dat'),country:u(z,'geoip-country.dat'),country6:u(z,'geoip-country6.dat')},P=[[d('10.0.0.0'),d('10.255.255.255')],[d('172.16.0.0'),d('172.31.255.255')],[d('192.168.0.0'),d('192.168.255.255')]],h={firstIP:null,lastIP:null,lastLine:0,locationBuffer:null,locationRecordSize:88,mainBuffer:null,recordSize:24},F={firstIP:null,lastIP:null,lastLine:0,mainBuffer:null,recordSize:48};let O=JSON.parse(JSON.stringify(h)),L=JSON.parse(JSON.stringify(F));const U=e=>{let r,t,n=0,i=O.lastLine,a=O.lastIP,o=O.firstIP;const l=O.mainBuffer,u=O.locationBuffer,c=P,f=O.recordSize,s=O.locationRecordSize,d={range:[null,null],country:'',region:'',eu:'',timezone:'',city:'',ll:[null,null],metro:null,area:null};if(e>O.lastIP||e<O.firstIP)return null;for(let r=0;r<c.length;r++)if(e>=c[r][0]&&e<=c[r][1])return null;for(;;){if(r=Math.round((i-n)/2)+n,a=l.readUInt32BE(r*f),o=l.readUInt32BE(r*f+4),a<=e&&o>=e)return d.range=[a,o],10===f?d.country=l.toString('utf8',r*f+8,r*f+10):(t=l.readUInt32BE(r*f+8),-1>>>0>t&&(d.country=u.toString('utf8',t*s,t*s+2).replace(/\u0000.*/,''),d.region=u.toString('utf8',t*s+2,t*s+5).replace(/\u0000.*/,''),d.metro=u.readInt32BE(t*s+5),d.ll[0]=l.readInt32BE(r*f+12)/1e4,d.ll[1]=l.readInt32BE(r*f+16)/1e4,d.area=l.readUInt32BE(r*f+20),d.eu=u.toString('utf8',t*s+9,t*s+10).replace(/\u0000.*/,''),d.timezone=u.toString('utf8',t*s+10,t*s+42).replace(/\u0000.*/,''),d.city=u.toString('utf8',t*s+42,t*s+s).replace(/\u0000.*/,''))),d;if(n===i)return null;n===i-1?r===n?n=i:i=n:a>e?i=r:o<e&&(n=r)}},D=['0:0:0:0:0:FFFF:','::FFFF:'];function J(u){let c,f;const d=JSON.parse(JSON.stringify(h));if('function'==typeof arguments[0])s.series([i=>{s.series([r=>{e(N.cityNames,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,d.locationBuffer=Buffer.alloc(f),e(r)})},e=>{t(c,d.locationBuffer,0,f,0,e)},e=>{n(c,e)},r=>{e(N.city,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,e(r)})}],t=>{if(t){if('ENOENT'!==t.code&&'EBADF'!==t.code)throw t;e(N.country,'r',(e,t)=>{e?i(e):(c=t,r(c,(e,r)=>{f=r.size,d.recordSize=10,i()}))})}else i()})},()=>{d.mainBuffer=Buffer.alloc(f),s.series([e=>{t(c,d.mainBuffer,0,f,0,e)},e=>{n(c,e)}],e=>{e||(d.lastLine=f/d.recordSize-1,d.lastIP=d.mainBuffer.readUInt32BE(d.lastLine*d.recordSize+4),d.firstIP=d.mainBuffer.readUInt32BE(0),O=d),u(e)})}]);else{try{if(c=i(N.cityNames,'r'),f=a(c).size,0===f)throw{code:'EMPTY_FILE'};O.locationBuffer=Buffer.alloc(f),o(c,O.locationBuffer,0,f,0),l(c),c=i(N.city,'r'),f=a(c).size}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;c=i(N.country,'r'),f=a(c).size,O.recordSize=10}O.mainBuffer=Buffer.alloc(f),o(c,O.mainBuffer,0,f,0),l(c),O.lastLine=f/O.recordSize-1,O.lastIP=O.mainBuffer.readUInt32BE(O.lastLine*O.recordSize+4),O.firstIP=O.mainBuffer.readUInt32BE(0)}}function T(u){let c,f;const d=JSON.parse(JSON.stringify(F));if('function'==typeof arguments[0])s.series([t=>{s.series([r=>{e(N.city6,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,e(r)})}],n=>{if(n){if('ENOENT'!==n.code&&'EBADF'!==n.code)throw n;e(N.country6,'r',(e,n)=>{e?t(e):(c=n,r(c,(e,r)=>{f=r.size,d.recordSize=34,t()}))})}else t()})},()=>{d.mainBuffer=Buffer.alloc(f),s.series([e=>{t(c,d.mainBuffer,0,f,0,e)},e=>{n(c,e)}],e=>{e||(d.lastLine=f/d.recordSize-1,L=d),u(e)})}]);else{try{if(c=i(N.city6,'r'),f=a(c).size,0===f)throw{code:'EMPTY_FILE'}}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;c=i(N.country6,'r'),f=a(c).size,L.recordSize=34}L.mainBuffer=Buffer.alloc(f),o(c,L.mainBuffer,0,f,0),l(c),L.lastLine=f/L.recordSize-1}}module.exports={cmp:g,lookup:e=>{if(!e)return null;if('number'==typeof e)return U(e);if(4===f(e))return U(d(e));if(6===f(e)){const r=(e=>{const r=e.toUpperCase();for(let e=0;e<D.length;e++){const t=D[e];if(0===r.indexOf(t))return r.substring(t.length)}return null})(e);return r?U(d(r)):(e=>{const r=L.mainBuffer,t=L.recordSize,n=O.locationBuffer,i=O.locationRecordSize,a={range:[null,null],country:'',region:'',city:'',ll:[0,0],metro:null,area:null,eu:'',timezone:''},o=(e,n)=>{const i=[];for(let a=0;a<2;a++)i.push(r.readUInt32BE(e*t+16*n+4*a));return i};L.lastIP=o(L.lastLine,1),L.firstIP=o(0,0);let l,u,c=0,f=L.lastLine,s=L.lastIP,d=L.firstIP;if(B(e,L.lastIP)>0||B(e,L.firstIP)<0)return null;for(;;){if(l=Math.round((f-c)/2)+c,s=o(l,0),d=o(l,1),B(s,e)<=0&&B(d,e)>=0)return 34===t?a.country=r.toString('utf8',l*t+32,l*t+34).replace(/\u0000.*/,''):(u=r.readUInt32BE(l*t+32),-1>>>0>u&&(a.country=n.toString('utf8',u*i,u*i+2).replace(/\u0000.*/,''),a.region=n.toString('utf8',u*i+2,u*i+5).replace(/\u0000.*/,''),a.metro=n.readInt32BE(u*i+5),a.ll[0]=r.readInt32BE(l*t+36)/1e4,a.ll[1]=r.readInt32BE(l*t+40)/1e4,a.area=r.readUInt32BE(l*t+44),a.eu=n.toString('utf8',u*i+9,u*i+10).replace(/\u0000.*/,''),a.timezone=n.toString('utf8',u*i+10,u*i+42).replace(/\u0000.*/,''),a.city=n.toString('utf8',u*i+42,u*i+i).replace(/\u0000.*/,''))),a;if(c===f)return null;c===f-1?l===c?c=f:f=c:B(s,e)>0?f=l:B(d,e)<0&&(c=l)}})(y(e))}return null},pretty:e=>'string'==typeof e?e:'number'==typeof e?S(e):Array.isArray(e)?p(e):e,startWatchingDataUpdate:e=>{I.makeFsWatchFilter(m,z,6e4,async()=>{await s.series([e=>{J(e)},e=>{T(e)}],e)})},stopWatchingDataUpdate:()=>I.stopWatching(m),clear:()=>{O=JSON.parse(JSON.stringify(h)),L=JSON.parse(JSON.stringify(F))},reloadDataSync:()=>{J(),T()},reloadData:async e=>{await s.series([e=>{J(e)},e=>{T(e)}],e)},version:E},J(),T();
1
+ const{open:e,fstat:r,read:t,close:n,openSync:i,fstatSync:o,readSync:a,closeSync:l}=require('node:fs'),{join:f,resolve:u}=require('node:path'),{isIP:c}=require('node:net'),s=require('async'),{aton4:d,aton6:B,cmp6:y,ntoa4:I,ntoa6:m,cmp:E}=require('./utils.js'),S=require('./fsWatcher.js'),{version:g}=require('../package.json'),z='dataWatcher',p=u(__dirname,global.geoDataDir||process.env.GEODATADIR||'../data/'),P={city:f(p,'geoip-city.dat'),city6:f(p,'geoip-city6.dat'),cityNames:f(p,'geoip-city-names.dat'),country:f(p,'geoip-country.dat'),country6:f(p,'geoip-country6.dat')},h=[[d('10.0.0.0'),d('10.255.255.255')],[d('172.16.0.0'),d('172.31.255.255')],[d('192.168.0.0'),d('192.168.255.255')]],F={firstIP:null,lastIP:null,lastLine:0,locationBuffer:null,locationRecordSize:88,mainBuffer:null,recordSize:24},L={firstIP:null,lastIP:null,lastLine:0,mainBuffer:null,recordSize:48};let U={...F},D={...L};const N=e=>{const r=e.indexOf('\0');return-1===r?e:e.substring(0,r)},T=(e,r,t,n)=>{const i=[];for(let o=0;o<2;o++)i.push(e.readUInt32BE(r*t+16*n+4*o));return i},w=e=>{let r,t,n=0,i=U.lastLine,o=U.lastIP,a=U.firstIP;const l=U.mainBuffer,f=U.locationBuffer,u=h,c=U.recordSize,s=U.locationRecordSize,d={range:[null,null],country:'',region:'',eu:'',timezone:'',city:'',ll:[null,null],metro:null,area:null};if(e>U.lastIP||e<U.firstIP)return null;for(let r=0;r<u.length;r++)if(e>=u[r][0]&&e<=u[r][1])return null;for(;;){r=Math.round((i-n)/2)+n;const u=r*c;if(o=l.readUInt32BE(u),a=l.readUInt32BE(u+4),o<=e&&a>=e){if(d.range=[o,a],10===c)d.country=l.toString('utf8',u+8,u+10);else if(t=l.readUInt32BE(u+8),-1>>>0>t){const e=t*s;d.country=N(f.toString('utf8',e,e+2)),d.region=N(f.toString('utf8',e+2,e+5)),d.metro=f.readInt32BE(e+5),d.ll[0]=l.readInt32BE(u+12)/1e4,d.ll[1]=l.readInt32BE(u+16)/1e4,d.area=l.readUInt32BE(u+20),d.eu=N(f.toString('utf8',e+9,e+10)),d.timezone=N(f.toString('utf8',e+10,e+42)),d.city=N(f.toString('utf8',e+42,e+s))}return d}if(n===i)return null;n===i-1?r===n?n=i:i=n:o>e?i=r:a<e&&(n=r)}};function A(f){let u,c;const d={...F};if('function'==typeof arguments[0])s.series([i=>{s.series([r=>{e(P.cityNames,'r',(e,t)=>{u=t,r(e)})},e=>{r(u,(r,t)=>{c=t.size,d.locationBuffer=Buffer.alloc(c),e(r)})},e=>{t(u,d.locationBuffer,0,c,0,e)},e=>{n(u,e)},r=>{e(P.city,'r',(e,t)=>{u=t,r(e)})},e=>{r(u,(r,t)=>{c=t.size,e(r)})}],t=>{if(t){if('ENOENT'!==t.code&&'EBADF'!==t.code)throw t;e(P.country,'r',(e,t)=>{e?i(e):(u=t,r(u,(e,r)=>{c=r.size,d.recordSize=10,i()}))})}else i()})},()=>{d.mainBuffer=Buffer.alloc(c),s.series([e=>{t(u,d.mainBuffer,0,c,0,e)},e=>{n(u,e)}],e=>{e||(d.lastLine=c/d.recordSize-1,d.lastIP=d.mainBuffer.readUInt32BE(d.lastLine*d.recordSize+4),d.firstIP=d.mainBuffer.readUInt32BE(0),U=d),f(e)})}]);else{try{if(u=i(P.cityNames,'r'),c=o(u).size,0===c){const e=new Error('Empty file');throw e.code='EMPTY_FILE',e}U.locationBuffer=Buffer.alloc(c),a(u,U.locationBuffer,0,c,0),l(u),u=i(P.city,'r'),c=o(u).size}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;u=i(P.country,'r'),c=o(u).size,U.recordSize=10}U.mainBuffer=Buffer.alloc(c),a(u,U.mainBuffer,0,c,0),l(u),U.lastLine=c/U.recordSize-1,U.lastIP=U.mainBuffer.readUInt32BE(U.lastLine*U.recordSize+4),U.firstIP=U.mainBuffer.readUInt32BE(0)}}function W(f){let u,c;const d={...L};if('function'==typeof arguments[0])s.series([t=>{s.series([r=>{e(P.city6,'r',(e,t)=>{u=t,r(e)})},e=>{r(u,(r,t)=>{c=t.size,e(r)})}],n=>{if(n){if('ENOENT'!==n.code&&'EBADF'!==n.code)throw n;e(P.country6,'r',(e,n)=>{e?t(e):(u=n,r(u,(e,r)=>{c=r.size,d.recordSize=34,t()}))})}else t()})},()=>{d.mainBuffer=Buffer.alloc(c),s.series([e=>{t(u,d.mainBuffer,0,c,0,e)},e=>{n(u,e)}],e=>{e||(d.lastLine=c/d.recordSize-1,d.lastIP=T(d.mainBuffer,d.lastLine,d.recordSize,1),d.firstIP=T(d.mainBuffer,0,d.recordSize,0),D=d),f(e)})}]);else{try{if(u=i(P.city6,'r'),c=o(u).size,0===c){const e=new Error('Empty file');throw e.code='EMPTY_FILE',e}}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;u=i(P.country6,'r'),c=o(u).size,D.recordSize=34}D.mainBuffer=Buffer.alloc(c),a(u,D.mainBuffer,0,c,0),l(u),D.lastLine=c/D.recordSize-1,D.lastIP=T(D.mainBuffer,D.lastLine,D.recordSize,1),D.firstIP=T(D.mainBuffer,0,D.recordSize,0)}}module.exports={cmp:E,lookup:e=>{if(!e)return null;if('number'==typeof e)return w(e);if(4===c(e))return w(d(e));if(6===c(e)){const r=(e=>{const r=e.toUpperCase();return r.startsWith("0:0:0:0:0:FFFF:")?r.substring(15):r.startsWith("::FFFF:")?r.substring(7):null})(e);return r?w(d(r)):(e=>{const r=D.mainBuffer,t=D.recordSize,n=U.locationBuffer,i=U.locationRecordSize,o={range:[null,null],country:'',region:'',city:'',ll:[0,0],metro:null,area:null,eu:'',timezone:''};let a,l,f=0,u=D.lastLine,c=D.lastIP,s=D.firstIP;if(y(e,D.lastIP)>0||y(e,D.firstIP)<0)return null;for(;;){if(a=Math.round((u-f)/2)+f,c=T(r,a,t,0),s=T(r,a,t,1),y(c,e)<=0&&y(s,e)>=0){const e=a*t;if(34===t)o.country=N(r.toString('utf8',e+32,e+34));else if(l=r.readUInt32BE(e+32),-1>>>0>l){const t=l*i;o.country=N(n.toString('utf8',t,t+2)),o.region=N(n.toString('utf8',t+2,t+5)),o.metro=n.readInt32BE(t+5),o.ll[0]=r.readInt32BE(e+36)/1e4,o.ll[1]=r.readInt32BE(e+40)/1e4,o.area=r.readUInt32BE(e+44),o.eu=N(n.toString('utf8',t+9,t+10)),o.timezone=N(n.toString('utf8',t+10,t+42)),o.city=N(n.toString('utf8',t+42,t+i))}return o}if(f===u)return null;f===u-1?a===f?f=u:u=f:y(c,e)>0?u=a:y(s,e)<0&&(f=a)}})(B(e))}return null},pretty:e=>'string'==typeof e?e:'number'==typeof e?I(e):Array.isArray(e)?m(e):e,startWatchingDataUpdate:e=>{S.makeFsWatchFilter(z,p,6e4,()=>{s.series([e=>{A(e)},e=>{W(e)}],e)})},stopWatchingDataUpdate:()=>S.stopWatching(z),clear:()=>{U={...F},D={...L}},reloadDataSync:()=>{A(),W()},reloadData:e=>{s.series([e=>{A(e)},e=>{W(e)}],e)},version:g},A(),W();
package/dist/utils.js CHANGED
@@ -1 +1 @@
1
- const t=module.exports={};t.aton4=t=>(t=t.split(/\./),(parseInt(t[0],10)<<24>>>0)+(parseInt(t[1],10)<<16>>>0)+(parseInt(t[2],10)<<8>>>0)+(parseInt(t[3],10)>>>0)),t.aton6=t=>{const n=(t=t.replace(/"/g,'').split(/:/)).length-1;let r;if(''===t[n]&&(t[n]=0),n<7)for(t.length=8,r=n;r>=0&&''!==t[r];r--)t[7-n+r]=t[r];for(r=0;r<8;r++)t[r]?t[r]=parseInt(t[r],16):t[r]=0;const e=[];for(r=0;r<4;r++)e.push((t[2*r]<<16)+t[2*r+1]>>>0);return e},t.cmp=(t,n)=>'number'==typeof t&&'number'==typeof n?t<n?-1:t>n?1:0:t instanceof Array&&n instanceof Array?this.cmp6(t,n):null,t.cmp6=(t,n)=>{for(let r=0;r<2;r++){if(t[r]<n[r])return-1;if(t[r]>n[r])return 1}return 0},t.isPrivateIP=t=>null!=(t=t.toString()).match(/^10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/)||null!=t.match(/^192\.168\.([0-9]{1,3})\.([0-9]{1,3})/)||null!=t.match(/^172\.16\.([0-9]{1,3})\.([0-9]{1,3})/)||null!=t.match(/^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/)||null!=t.match(/^169\.254\.([0-9]{1,3})\.([0-9]{1,3})/)||null!=t.match(/^fc00:/)||null!=t.match(/^fe80:/),t.ntoa4=t=>((t=t.toString())>>>24&255)+'.'+(t>>>16&255)+'.'+(t>>>8&255)+'.'+(255&t),t.ntoa6=t=>{let n='[';for(let r=0;r<t.length;r++)n+=(t[r]>>>16).toString(16)+':',n+=(65535&t[r]).toString(16)+':';return n=n.replace(/:$/,']').replace(/:0+/g,':').replace(/::+/,'::'),n};
1
+ const t=module.exports={};t.aton4=t=>{const r=t.split('.');return(parseInt(r[0],10)<<24>>>0)+(parseInt(r[1],10)<<16>>>0)+(parseInt(r[2],10)<<8>>>0)+(parseInt(r[3],10)>>>0)},t.ntoa4=t=>(t>>>24&255)+'.'+(t>>>16&255)+'.'+(t>>>8&255)+'.'+(255&t),t.aton6=t=>{const r=(t=t.replace(/"/g,'').split(':')).length-1;let e;if(''===t[r]&&(t[r]=0),r<7)for(t.length=8,e=r;e>=0&&''!==t[e];e--)t[7-r+e]=t[e];for(e=0;e<8;e++)t[e]?t[e]=parseInt(t[e],16):t[e]=0;const n=[];for(e=0;e<4;e++)n.push((t[2*e]<<16)+t[2*e+1]>>>0);return n},t.ntoa6=t=>{let r='[';for(let e=0;e<t.length;e++)r+=(t[e]>>>16).toString(16)+':',r+=(65535&t[e]).toString(16)+':';return r=r.replace(/:$/,']').replace(/:0+/g,':').replace(/::+/,'::'),r},t.cmp=(r,e)=>'number'==typeof r&&'number'==typeof e?r<e?-1:r>e?1:0:r instanceof Array&&e instanceof Array?t.cmp6(r,e):null,t.cmp6=(t,r)=>{for(let e=0;e<2;e++){if(t[e]<r[e])return-1;if(t[e]>r[e])return 1}return 0},t.isPrivateIP=t=>{const r=t.toString();return r.startsWith('10.')||r.startsWith('192.168.')||r.startsWith('172.16.')||r.startsWith('127.')||r.startsWith('169.254.')||r.startsWith('fc00:')||r.startsWith('fe80:')};
package/index.d.ts CHANGED
@@ -2,12 +2,12 @@ interface GeoIp2Location {
2
2
  range: [number | null, number | null];
3
3
  country: string;
4
4
  region: string;
5
- eu: '0' | '1';
5
+ eu: '0' | '1' | '';
6
6
  timezone: string;
7
7
  city: string;
8
8
  ll: [number | null, number | null];
9
- metro: number;
10
- area: number;
9
+ metro: number | null;
10
+ area: number | null;
11
11
  }
12
12
 
13
13
  export function lookup(ip: string | number): GeoIp2Location | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geoip-lite2",
3
- "version": "2.2.7",
3
+ "version": "2.2.8-beta.2",
4
4
  "description": "A light weight native JavaScript implementation of GeoIP API from MaxMind. Improved and faster version by Sefinek.",
5
5
  "keywords": [
6
6
  "city",
@@ -79,14 +79,14 @@
79
79
  "adm-zip": "^0.5.16",
80
80
  "async": "^3.2.6",
81
81
  "iconv-lite": "0.7.0",
82
- "ip-address": "^10.0.1",
83
- "rimraf": "^6.0.1"
82
+ "ip-address": "^10.1.0",
83
+ "rimraf": "^6.1.0"
84
84
  },
85
85
  "devDependencies": {
86
- "@eslint/js": "^9.35.0",
87
- "globals": "^16.3.0",
88
- "jest": "^30.1.3",
89
- "terser": "^5.44.0"
86
+ "@eslint/js": "^9.39.1",
87
+ "globals": "^16.5.0",
88
+ "jest": "^30.2.0",
89
+ "terser": "^5.44.1"
90
90
  },
91
91
  "engines": {
92
92
  "node": ">=10.3.0"
package/tools/updatedb.js CHANGED
@@ -1,7 +1,14 @@
1
- // Fetches and converts MaxMind lite databases
1
+ // ============================================================================
2
+ // GeoIP Database Updater
3
+ // Fetches and converts MaxMind GeoLite2 databases
4
+ // ============================================================================
2
5
 
3
6
  'use strict';
4
7
 
8
+ // ============================================================================
9
+ // Dependencies
10
+ // ============================================================================
11
+
5
12
  const { name, version } = require('../package.json');
6
13
  const UserAgent = `Mozilla/5.0 (compatible; ${name}/${version}; +https://github.com/sefinek/geoip-lite2)`;
7
14
 
@@ -19,6 +26,10 @@ const AdmZip = require('adm-zip');
19
26
  const utils = require('../lib/utils.js');
20
27
  const { Address6, Address4 } = require('ip-address');
21
28
 
29
+ // ============================================================================
30
+ // Configuration
31
+ // ============================================================================
32
+
22
33
  const args = process.argv.slice(2);
23
34
  let license_key = args.find(arg => arg.match(/^license_key=[a-zA-Z0-9]+/) !== null);
24
35
  if (typeof license_key === 'undefined' && typeof process.env.LICENSE_KEY !== 'undefined') {
@@ -67,6 +78,10 @@ const databases = [{
67
78
  dest: ['geoip-city-names.dat', 'geoip-city.dat', 'geoip-city6.dat'],
68
79
  }];
69
80
 
81
+ // ============================================================================
82
+ // Utility Functions
83
+ // ============================================================================
84
+
70
85
  function mkdir(dirName) {
71
86
  const dir = path.dirname(dirName);
72
87
  if (!fs.existsSync(dir)) fs.mkdirSync(dir);
@@ -118,6 +133,10 @@ function CSVtoArray(text) {
118
133
  return a;
119
134
  }
120
135
 
136
+ // ============================================================================
137
+ // HTTP Configuration
138
+ // ============================================================================
139
+
121
140
  function getHTTPOptions(downloadUrl) {
122
141
  const parsedUrl = new URL(downloadUrl);
123
142
  const options = {
@@ -140,6 +159,10 @@ function getHTTPOptions(downloadUrl) {
140
159
  return options;
141
160
  }
142
161
 
162
+ // ============================================================================
163
+ // Database Download Functions
164
+ // ============================================================================
165
+
143
166
  function check(database, cb) {
144
167
  if (args.indexOf('force') !== -1) {
145
168
  // We are forcing database upgrade,
@@ -156,6 +179,8 @@ function check(database, cb) {
156
179
 
157
180
  console.log('Checking', database.fileName);
158
181
 
182
+ const client = https.get(getHTTPOptions(checksumUrl), onResponse);
183
+
159
184
  function onResponse(response) {
160
185
  const status = response.statusCode;
161
186
  if ([301, 302, 303, 307, 308].includes(status)) {
@@ -190,8 +215,6 @@ function check(database, cb) {
190
215
  cb(null, database);
191
216
  });
192
217
  }
193
-
194
- var client = https.get(getHTTPOptions(checksumUrl), onResponse);
195
218
  });
196
219
  }
197
220
 
@@ -208,6 +231,8 @@ function fetch(database, cb) {
208
231
 
209
232
  console.log('Fetching', fileName);
210
233
 
234
+ const client = https.get(getHTTPOptions(downloadUrl), onResponse);
235
+
211
236
  function onResponse(response) {
212
237
  const status = response.statusCode;
213
238
  if ([301, 302, 303, 307, 308].includes(status)) {
@@ -235,8 +260,6 @@ function fetch(database, cb) {
235
260
 
236
261
  mkdir(tmpFile);
237
262
 
238
- var client = https.get(getHTTPOptions(downloadUrl), onResponse);
239
-
240
263
  process.stdout.write(`Retrieving ${fileName}...`);
241
264
  }
242
265
 
@@ -292,8 +315,22 @@ function processLookupCountry(src, cb) {
292
315
  });
293
316
  }
294
317
 
318
+ // ============================================================================
319
+ // Data Processing Functions
320
+ // ============================================================================
321
+
295
322
  async function processCountryData(src, dest) {
296
323
  let lines = 0;
324
+ const dataFile = path.join(dataPath, dest);
325
+ const tmpDataFile = path.join(tmpPath, src);
326
+
327
+ rimraf(dataFile);
328
+ mkdir(dataFile);
329
+
330
+ process.stdout.write('\nProcessing data (may take a moment)...');
331
+ let tstart = Date.now();
332
+ const datFile = fs.createWriteStream(dataFile);
333
+
297
334
  function processLine(line) {
298
335
  const fields = CSVtoArray(line);
299
336
  if (!fields || fields.length < 6) return console.warn('weird line: %s::', line);
@@ -353,16 +390,6 @@ async function processCountryData(src, dest) {
353
390
  }
354
391
  }
355
392
 
356
- const dataFile = path.join(dataPath, dest);
357
- const tmpDataFile = path.join(tmpPath, src);
358
-
359
- rimraf(dataFile);
360
- mkdir(dataFile);
361
-
362
- process.stdout.write('\nProcessing data (may take a moment)...');
363
- var tstart = Date.now();
364
- var datFile = fs.createWriteStream(dataFile);
365
-
366
393
  const rl = readline.createInterface({ input: fs.createReadStream(tmpDataFile), crlfDelay: Infinity });
367
394
  let i = 0;
368
395
  for await (const line of rl) {
@@ -376,6 +403,15 @@ async function processCountryData(src, dest) {
376
403
 
377
404
  async function processCityData(src, dest) {
378
405
  let lines = 0;
406
+ const dataFile = path.join(dataPath, dest);
407
+ const tmpDataFile = path.join(tmpPath, src);
408
+
409
+ rimraf(dataFile);
410
+
411
+ process.stdout.write('\nProcessing data (may take a moment)...');
412
+ let tstart = Date.now();
413
+ const datFile = fs.createWriteStream(dataFile);
414
+
379
415
  async function processLine(line) {
380
416
  if (line.match(/^Copyright/) || !line.match(/\d/)) return;
381
417
 
@@ -462,15 +498,6 @@ async function processCityData(src, dest) {
462
498
  }
463
499
  }
464
500
 
465
- const dataFile = path.join(dataPath, dest);
466
- const tmpDataFile = path.join(tmpPath, src);
467
-
468
- rimraf(dataFile);
469
-
470
- process.stdout.write('\nProcessing data (may take a moment)...');
471
- var tstart = Date.now();
472
- var datFile = fs.createWriteStream(dataFile);
473
-
474
501
  const rl = readline.createInterface({ input: fs.createReadStream(tmpDataFile), crlfDelay: Infinity });
475
502
  let i = 0;
476
503
  for await (const line of rl) {
@@ -484,6 +511,13 @@ async function processCityData(src, dest) {
484
511
  function processCityDataNames(src, dest, cb) {
485
512
  let locId = null;
486
513
  let linesCount = 0;
514
+ const dataFile = path.join(dataPath, dest);
515
+ const tmpDataFile = path.join(tmpPath, src);
516
+
517
+ rimraf(dataFile);
518
+
519
+ const datFile = fs.openSync(dataFile, 'w');
520
+
487
521
  function processLine(line) {
488
522
  if (line.match(/^Copyright/) || !line.match(/\d/)) return;
489
523
 
@@ -519,13 +553,6 @@ function processCityDataNames(src, dest, cb) {
519
553
  linesCount++;
520
554
  }
521
555
 
522
- const dataFile = path.join(dataPath, dest);
523
- const tmpDataFile = path.join(tmpPath, src);
524
-
525
- rimraf(dataFile);
526
-
527
- var datFile = fs.openSync(dataFile, 'w');
528
-
529
556
  const rl = readline.createInterface({ input: fs.createReadStream(tmpDataFile).pipe(decodeStream('utf-8')), output: process.stdout, terminal: false });
530
557
 
531
558
  let lineCount = 0;
@@ -538,6 +565,10 @@ function processCityDataNames(src, dest, cb) {
538
565
  rl.on('close', cb);
539
566
  }
540
567
 
568
+ // ============================================================================
569
+ // Main Processing Dispatcher
570
+ // ============================================================================
571
+
541
572
  function processData(database, cb) {
542
573
  if (database.skip) return cb(null, database);
543
574
 
@@ -573,6 +604,10 @@ function processData(database, cb) {
573
604
  }
574
605
  }
575
606
 
607
+ // ============================================================================
608
+ // Checksum Management
609
+ // ============================================================================
610
+
576
611
  function updateChecksum(database, cb) {
577
612
  if (database.skip || !database.checkValue) return cb(); // Don't need to update checksums because it was not fetched or did not change
578
613
 
@@ -582,6 +617,10 @@ function updateChecksum(database, cb) {
582
617
  });
583
618
  }
584
619
 
620
+ // ============================================================================
621
+ // Main Execution Flow
622
+ // ============================================================================
623
+
585
624
  if (!license_key) {
586
625
  console.error('ERROR: Missing license_key');
587
626
  process.exit(1);