@liberstudio/cloudflare-list 2.4.1 → 2.4.3

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.
@@ -44,12 +44,15 @@ let AttacksService = class AttacksService {
44
44
  return null;
45
45
  }
46
46
  const asnRange = await this.lookupAsnRange(rawIp);
47
- if (asnRange) {
47
+ if (asnRange && !(await (0, utils_1.googleBotOverlapsCidr)(asnRange))) {
48
48
  this.logger.error(`ASN range trovato per ${rawIp}: ${asnRange} — blocco intera subnet`);
49
49
  const result = await this.updateIpList(asnRange);
50
50
  this.sendWhatsappNotification(rawIp, asnRange);
51
51
  return result;
52
52
  }
53
+ if (asnRange) {
54
+ this.logger.warn(`ASN range ${asnRange} sovrapposto a range Googlebot — ban limitato all'IP singolo`);
55
+ }
53
56
  const cidr = (0, utils_1.normalizeIp)(rawIp);
54
57
  if (!cidr)
55
58
  throw new Error(`IP non valido: ${rawIp}`);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * True se l'IP appartiene ai crawler Google (Googlebot, special crawlers, fetcher).
2
+ * True se l'IP appartiene ai crawler di Google Search (googlebot.json ufficiale).
3
3
  *
4
4
  * Strategia hybrid:
5
5
  * 1. match veloce sulle liste IP ufficiali (cache 24h, auto-aggiornate);
@@ -9,3 +9,10 @@
9
9
  * (non bannare) per non rischiare di bloccare Googlebot durante un disservizio.
10
10
  */
11
11
  export declare function isGoogleBotIp(ip: string): Promise<boolean>;
12
+ /**
13
+ * True se il CIDR dato si sovrappone con almeno un range Googlebot.
14
+ * Usato prima di bannare un'intera subnet ASN: se la subnet contiene IP Google,
15
+ * meglio bannare solo l'IP singolo per non bloccare il crawler.
16
+ * Fail-safe: in caso di errore ritorna false (lascia procedere il ban della subnet).
17
+ */
18
+ export declare function googleBotOverlapsCidr(cidr: string): Promise<boolean>;
@@ -4,14 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isGoogleBotIp = isGoogleBotIp;
7
+ exports.googleBotOverlapsCidr = googleBotOverlapsCidr;
7
8
  const axios_1 = __importDefault(require("axios"));
8
9
  const dns_1 = require("dns");
9
10
  const cidr_util_1 = require("./cidr.util");
10
- // Liste IP ufficiali pubblicate (e aggiornate) da Google.
11
+ // Solo il crawler di Google Search. special-crawlers e user-triggered-fetchers
12
+ // includono range GCP molto ampi (Lighthouse, PageSpeed, Feed Fetcher) e causano
13
+ // falsi positivi — non meritano protezione "skip ban".
11
14
  const GOOGLE_IP_LIST_URLS = [
12
15
  "https://developers.google.com/static/search/apis/ipranges/googlebot.json",
13
- "https://developers.google.com/static/search/apis/ipranges/special-crawlers.json",
14
- "https://developers.google.com/static/search/apis/ipranges/user-triggered-fetchers.json",
15
16
  ];
16
17
  // Domini dei crawler verificati da Google (per il fallback reverse DNS).
17
18
  const GOOGLE_HOSTS = [".googlebot.com", ".google.com", ".googleusercontent.com"];
@@ -60,7 +61,7 @@ async function verifyByReverseDns(pureIp, version) {
60
61
  }
61
62
  }
62
63
  /**
63
- * True se l'IP appartiene ai crawler Google (Googlebot, special crawlers, fetcher).
64
+ * True se l'IP appartiene ai crawler di Google Search (googlebot.json ufficiale).
64
65
  *
65
66
  * Strategia hybrid:
66
67
  * 1. match veloce sulle liste IP ufficiali (cache 24h, auto-aggiornate);
@@ -93,3 +94,30 @@ async function isGoogleBotIp(ip) {
93
94
  // se nemmeno la lista era raggiungibile → fail-open.
94
95
  return !listAvailable;
95
96
  }
97
+ /**
98
+ * True se il CIDR dato si sovrappone con almeno un range Googlebot.
99
+ * Usato prima di bannare un'intera subnet ASN: se la subnet contiene IP Google,
100
+ * meglio bannare solo l'IP singolo per non bloccare il crawler.
101
+ * Fail-safe: in caso di errore ritorna false (lascia procedere il ban della subnet).
102
+ */
103
+ async function googleBotOverlapsCidr(cidr) {
104
+ const networkAddr = (0, cidr_util_1.purifyIp)(cidr);
105
+ const version = (0, cidr_util_1.ipVersion)(networkAddr);
106
+ if (!version)
107
+ return false;
108
+ try {
109
+ const { v4, v6 } = await loadGoogleIps();
110
+ const googlebotCidrs = version === 4 ? v4 : v6;
111
+ // Il network address della subnet ASN cade in un range Googlebot?
112
+ if ((0, cidr_util_1.isIpInAnyCidr)(networkAddr, googlebotCidrs, version))
113
+ return true;
114
+ // Il network address di un range Googlebot cade nella subnet ASN?
115
+ return googlebotCidrs.some((gbCidr) => {
116
+ const gbNet = (0, cidr_util_1.purifyIp)(gbCidr);
117
+ return version === 4 ? (0, cidr_util_1.isInCidrV4)(gbNet, cidr) : (0, cidr_util_1.isInCidrV6)(gbNet, cidr);
118
+ });
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liberstudio/cloudflare-list",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "description": "Modulo NestJS per gestione IP List Cloudflare",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,15 +26,15 @@
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@nestjs/axios": ">=3.0.0",
29
- "@nestjs/common": ">=10.0.0",
30
- "@nestjs/core": ">=10.0.0",
31
- "axios": ">=1.0.0",
29
+ "@nestjs/common": ">=10.4.3",
30
+ "@nestjs/core": ">=10.4.3",
31
+ "axios": ">=1.18.0",
32
32
  "rxjs": ">=7.0.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@nestjs/axios": "^4.0.1",
36
- "@nestjs/common": "^11.1.26",
37
- "@nestjs/core": "^11.1.26",
36
+ "@nestjs/common": "^11.1.27",
37
+ "@nestjs/core": "^11.1.27",
38
38
  "@types/express": "^5.0.6",
39
39
  "@types/node": "^20.19.43",
40
40
  "axios": "^1.18.0",