@liberstudio/cloudflare-list 2.3.6 → 2.3.8

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
@@ -76,6 +76,7 @@ import { CloudflareAttacksModule } from "@liberstudio/cloudflare-list";
76
76
  excludedPaths: ["/api/health", "/api/webhook"],
77
77
  silentPaths: ["/auth/me", "/auth/refresh"],
78
78
  verbose: false,
79
+ whatsappNotify: { phone: "393331234567" },
79
80
  }),
80
81
  ],
81
82
  })
@@ -102,6 +103,9 @@ import { CloudflareAttacksModule } from "@liberstudio/cloudflare-list";
102
103
  excludedPaths: ["/api/health", "/api/webhook", /^\/api\/public\/.*/],
103
104
  silentPaths: ["/auth/me", "/auth/refresh"],
104
105
  verbose: false,
106
+ whatsappNotify: {
107
+ phone: config.getOrThrow<string>("WA_NOTIFY_PHONE"),
108
+ },
105
109
  }),
106
110
  }),
107
111
  ],
@@ -124,6 +128,33 @@ export class AppModule {}
124
128
  | `excludedPaths` | `(string \| RegExp)[]` | no | Path esclusi da ogni rilevamento e log |
125
129
  | `silentPaths` | `(string \| RegExp)[]` | no | Path bloccati su Cloudflare ma senza log su file |
126
130
  | `verbose` | `boolean` | no | Se `true`, il log include body, query, params e stack |
131
+ | `whatsappNotify` | `{ phone: string }` | no | Invia una notifica WhatsApp quando un IP viene bannato |
132
+
133
+ ### `whatsappNotify` — notifiche ban su WhatsApp
134
+
135
+ Quando configurato, invia un messaggio WhatsApp ad un numero specifico ogni volta che un IP viene bloccato su Cloudflare. Richiede le variabili d'ambiente `WA_URL`, `WA_USER`, `WA_PASSWORD` e `WA_DEVICE_ID` già presenti nel progetto (lette automaticamente da `process.env`).
136
+
137
+ ```typescript
138
+ whatsappNotify: {
139
+ phone: "393331234567", // numero con prefisso internazionale, senza +
140
+ }
141
+ ```
142
+
143
+ Il messaggio inviato sarà:
144
+ ```
145
+ 🚨 IP bannato su Cloudflare
146
+ IP: 1.2.3.4
147
+ Subnet bloccata: 1.2.0.0/16
148
+ ```
149
+
150
+ Variabili d'ambiente richieste (lette automaticamente da `process.env`):
151
+ ```env
152
+ WA_URL=https://messaggistica.liberdesign.eu
153
+ WA_USER=your-user
154
+ WA_PASSWORD=your-password
155
+ WA_DEVICE_ID=your-device-id
156
+ WA_NOTIFY_PHONE=393331234567
157
+ ```
127
158
 
128
159
  ### `allowedIps` — whitelist server
129
160
 
@@ -8,6 +8,7 @@ export declare class AttacksService {
8
8
  private readonly ASN_LOOKUP_URL;
9
9
  constructor(httpService: HttpService, options: CloudflareAttacksOptions);
10
10
  blockIp(rawIp: string): Promise<CloudflareResponse | null>;
11
+ private sendWhatsappNotification;
11
12
  private lookupAsnRange;
12
13
  updateIpList(cidr: string): Promise<CloudflareResponse>;
13
14
  }
@@ -41,13 +41,36 @@ let AttacksService = class AttacksService {
41
41
  }
42
42
  const asnRange = await this.lookupAsnRange(rawIp);
43
43
  if (asnRange) {
44
- this.logger.log(`ASN range trovato per ${rawIp}: ${asnRange} — blocco intera subnet`);
45
- return this.updateIpList(asnRange);
44
+ this.logger.error(`ASN range trovato per ${rawIp}: ${asnRange} — blocco intera subnet`);
45
+ const result = await this.updateIpList(asnRange);
46
+ this.sendWhatsappNotification(rawIp, asnRange);
47
+ return result;
46
48
  }
47
49
  const cidr = (0, utils_1.normalizeIp)(rawIp);
48
50
  if (!cidr)
49
51
  throw new Error(`IP non valido: ${rawIp}`);
50
- return this.updateIpList(cidr);
52
+ const result = await this.updateIpList(cidr);
53
+ this.sendWhatsappNotification(rawIp, cidr);
54
+ return result;
55
+ }
56
+ sendWhatsappNotification(rawIp, cidr) {
57
+ const wa = this.options.whatsappNotify;
58
+ if (!wa)
59
+ return;
60
+ const url = process.env["WA_URL"];
61
+ const user = process.env["WA_USER"];
62
+ const password = process.env["WA_PASSWORD"];
63
+ const deviceId = process.env["WA_DEVICE_ID"];
64
+ if (!url || !user || !password || !deviceId) {
65
+ this.logger.warn("Notifica WhatsApp saltata: WA_URL, WA_USER, WA_PASSWORD o WA_DEVICE_ID mancanti");
66
+ return;
67
+ }
68
+ const auth = Buffer.from(`${user}:${password}`).toString("base64");
69
+ const message = `🚨 IP bannato su Cloudflare\nIP: ${rawIp}\nSubnet bloccata: ${cidr}`;
70
+ (0, rxjs_1.firstValueFrom)(this.httpService.post(`${url}/send/message`, { phone: wa.phone, message }, { headers: { Authorization: `Basic ${auth}`, "X-Device-Id": deviceId } })).catch((err) => {
71
+ const msg = err instanceof Error ? err.message : "Errore sconosciuto";
72
+ this.logger.warn(`Notifica WhatsApp fallita: ${msg}`);
73
+ });
51
74
  }
52
75
  async lookupAsnRange(ip) {
53
76
  try {
@@ -61,7 +84,7 @@ let AttacksService = class AttacksService {
61
84
  async updateIpList(cidr) {
62
85
  const { accountId, listId, apiToken, comment } = this.options;
63
86
  const url = `${this.API_URL}/${accountId}/rules/lists/${listId}/items`;
64
- this.logger.log(`Aggiungo ${cidr} alla lista Cloudflare`);
87
+ this.logger.error(`Aggiungo ${cidr} alla lista Cloudflare`);
65
88
  const body = [{ ip: cidr, comment }];
66
89
  try {
67
90
  const response = await (0, rxjs_1.firstValueFrom)(this.httpService.post(url, body, {
@@ -1,3 +1,6 @@
1
+ export interface WhatsappNotifyOptions {
2
+ phone: string;
3
+ }
1
4
  export interface CloudflareAttacksOptions {
2
5
  apiToken: string;
3
6
  accountId: string;
@@ -8,6 +11,7 @@ export interface CloudflareAttacksOptions {
8
11
  excludedPaths?: (string | RegExp)[];
9
12
  silentPaths?: (string | RegExp)[];
10
13
  verbose?: boolean;
14
+ whatsappNotify?: WhatsappNotifyOptions;
11
15
  }
12
16
  export interface CloudflareAttacksAsyncOptions {
13
17
  imports?: any[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liberstudio/cloudflare-list",
3
- "version": "2.3.6",
3
+ "version": "2.3.8",
4
4
  "description": "Modulo NestJS per gestione IP List Cloudflare",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,7 +16,7 @@
16
16
  "build": "npx tsc",
17
17
  "prepublishOnly": "npm run build",
18
18
  "version:bump": "npx tsx src/scripts/version-bump.ts",
19
- "pub": "npm publish --access public"
19
+ "pub": "npm run build && npm publish --access public"
20
20
  },
21
21
  "publishConfig": {
22
22
  "access": "public"