@roflsec/fail2scan 0.0.7 → 0.0.9

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 (2) hide show
  1. package/bin/daemon.js +41 -19
  2. package/package.json +1 -1
package/bin/daemon.js CHANGED
@@ -8,18 +8,23 @@ require('dotenv').config({ quiet:true})
8
8
 
9
9
  // -------------------- IPGeolocation --------------------
10
10
  let getGeo = async (ip) => null;
11
- if(process.env.IPGEO_API_KEY){
12
- const IPGeolocationAPI = require("ip-geolocation-api-javascript-sdk");
13
- const GeolocationParams = require("ip-geolocation-api-javascript-sdk/GeolocationParams.js");
14
- const ipGeo = new IPGeolocationAPI(`${process.env.IPGEO_API_KEY}`, true);
15
-
16
- getGeo = (ip) => {
17
- return new Promise((resolve) => {
18
- const params = new GeolocationParams();
11
+
12
+ if (process.env.IPGEO_API_KEY) {
13
+ const { IPGeolocationAPI, GeolocationParams } = require("ip-geolocation-api-javascript-sdk");
14
+ const geoApi = new IPGeolocationAPI(new GeolocationParams({ apiKey: process.env.IPGEO_API_KEY }));
15
+
16
+ getGeo = async (ip) => {
17
+ try {
18
+ const params = new GeolocationParams({ apiKey: process.env.IPGEO_API_KEY });
19
19
  params.setIPAddress(ip);
20
20
  params.setFields("geo,time_zone,currency,asn,security");
21
- ipGeo.getGeolocation((res) => resolve(res), params);
22
- });
21
+
22
+ return await new Promise((resolve, reject) => {
23
+ geoApi.getGeolocation(resolve, reject, params);
24
+ });
25
+ } catch {
26
+ return null;
27
+ }
23
28
  };
24
29
  }
25
30
 
@@ -64,7 +69,14 @@ function saveState(s){try{fs.mkdirSync(path.dirname(STATE_FILE),{recursive:true,
64
69
  const STATE=loadState();
65
70
 
66
71
  // -------------------- IP extraction --------------------
67
- function extractIpFromLine(line){const v4=line.match(/\b(?:\d{1,3}\.){3}\d{1,3}\b/);if(v4&&v4[0])return v4[0];const v6=line.match(/\b([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b/);if(v6&&v6[0])return v6[0];return null;}
72
+ function extractIpFromLine(line){
73
+ // garde ton extracteur d’origine (IPv4 + IPv6)
74
+ const v4 = line.match(/\b(?:\d{1,3}\.){3}\d{1,3}\b/);
75
+ if(v4&&v4[0]) return v4[0];
76
+ const v6 = line.match(/\b([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b/);
77
+ if(v6&&v6[0]) return v6[0];
78
+ return null;
79
+ }
68
80
 
69
81
  // -------------------- nmap helpers (parallel support) --------------------
70
82
  function spawnOneNmap(args, outFile) {
@@ -153,20 +165,17 @@ async function performScan(ip){
153
165
 
154
166
  try{ fs.writeFileSync(path.join(outDir,'summary.json'),JSON.stringify(summary,null,2)); } catch (e) {}
155
167
 
156
- // geo non bloquant
157
168
  if(process.env.IPGEO_API_KEY){
158
169
  getGeo(ip)
159
- .then(geo => {
160
- try{ fs.writeFileSync(path.join(outDir,'geo.json'), JSON.stringify(geo, null, 2)); } catch(e){}
161
- })
162
- .catch(e=>{});
170
+ .then(geo => { try{ fs.writeFileSync(path.join(outDir,'geo.json'), JSON.stringify(geo, null, 2)); }catch{} })
171
+ .catch(()=>{});
163
172
  }
164
173
 
165
174
  try{ fs.chmodSync(outDir,0o750); } catch (e) {}
166
175
  log('Scan written for',ip,'->',outDir);
167
176
  }
168
177
 
169
- // -------------------- queue optimized --------------------
178
+ // -------------------- queue --------------------
170
179
  class ScanQueue{
171
180
  constructor(concurrency=1){this.concurrency=concurrency;this.running=0;this.q=[];this.set=STATE.seen;this.tmpCache=new Set();}
172
181
  push(ip){
@@ -200,7 +209,9 @@ const concurrency = CORE_OVERRIDE||USER_CONCURRENCY||os.cpus().length||1;
200
209
  const q = new ScanQueue(concurrency);
201
210
  log(`Fail2Scan started. Watching ${LOG_PATH} -> output ${OUT_ROOT}, concurrency ${concurrency}`);
202
211
 
203
- const BAN_RE = /\bBan\b/i;
212
+ // -------------------- FIX : regex BAN correct --------------------
213
+ const BAN_RE = /Ban\s+(\d{1,3}(?:\.\d{1,3}){3})/;
214
+
204
215
  class FileTail{
205
216
  constructor(filePath,onLine){this.filePath=filePath;this.onLine=onLine;this.pos=0;this.inode=null;this.buf='';this.watch=null;this.start();}
206
217
  start(){try{const st=fs.statSync(this.filePath);this.inode=st.ino;this.pos=st.size;}catch{this.inode=null;this.pos=0;}this._watch();this._readNew().catch(()=>{});}
@@ -208,7 +219,18 @@ class FileTail{
208
219
  async _readNew(){try{const st=fs.statSync(this.filePath);if(st.size<this.pos)this.pos=0;if(st.size===this.pos)return;const stream=fs.createReadStream(this.filePath,{start:this.pos,end:st.size-1,encoding:'utf8'});for await(const chunk of stream){this.buf+=chunk;let idx;while((idx=this.buf.indexOf('\n'))>=0){const line=this.buf.slice(0,idx);this.buf=this.buf.slice(idx+1);if(line.trim())this.onLine(line);}}this.pos=st.size;}catch{}}
209
220
  close(){try{this.watch?.close();}catch{}}
210
221
  }
211
- const tail=new FileTail(LOG_PATH,line=>{try{if(!BAN_RE.test(line))return;const ip=extractIpFromLine(line);if(!ip)return;q.push(ip);}catch(e){log('onLine handler error',e.message||e);}});
222
+
223
+ const tail=new FileTail(LOG_PATH,line=>{
224
+ try{
225
+ const m=line.match(BAN_RE);
226
+ if(!m) return;
227
+ const ip = m[1];
228
+ if(!ip) return;
229
+ q.push(ip);
230
+ }catch(e){
231
+ log('onLine handler error',e.message||e);
232
+ }
233
+ });
212
234
 
213
235
  function shutdown(){log('Shutting down Fail2Scan...');tail.close();const start=Date.now();const wait=()=>{if(q.running===0||Date.now()-start>10000)process.exit(0);setTimeout(wait,500);};wait();}
214
236
  process.on('SIGINT',shutdown);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roflsec/fail2scan",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Fail2Scan daemon - watches fail2ban logs and scans banned IPs using nmap, dig and whois.",
5
5
  "bin": {
6
6
  "fail2scan-daemon": "./bin/daemon.js"