@liberstudio/cloudflare-list 2.0.1

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 ADDED
@@ -0,0 +1,31 @@
1
+ # Modulo NestJS per la gestione IP List Cloudflare
2
+ *npm run build*
3
+ *npm publish --access public*
4
+
5
+ ## Installazione
6
+
7
+ ```bash
8
+ npm install @lbr/cloudflare-list
9
+ ```
10
+
11
+ ## Utilizzo
12
+
13
+ ### Configurazione
14
+
15
+ Nel file di configurazione del progetto, aggiungere il modulo all'import della configurazione:
16
+
17
+ ```typescript
18
+ import { CloudflareAttacksModule } from "@lbr/cloudflare-list";
19
+
20
+ @Module({
21
+ imports: [
22
+ CloudflareAttacksModule.forRoot({
23
+ accountId: "<account_id>",
24
+ listId: "<list_id>",
25
+ apiToken: "<api_token>",
26
+ comment: "<comment>",
27
+ }),
28
+ ],
29
+ })
30
+ export class AppModule {}
31
+ ```
@@ -0,0 +1,7 @@
1
+ import { DynamicModule, type MiddlewareConsumer, NestModule } from "@nestjs/common";
2
+ import type { CloudflareAttacksAsyncOptions, CloudflareAttacksOptions } from "./interfaces";
3
+ export declare class CloudflareAttacksModule implements NestModule {
4
+ configure(consumer: MiddlewareConsumer): void;
5
+ static forRoot(options: CloudflareAttacksOptions): DynamicModule;
6
+ static forRootAsync(options: CloudflareAttacksAsyncOptions): DynamicModule;
7
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var CloudflareAttacksModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.CloudflareAttacksModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const axios_1 = require("@nestjs/axios");
13
+ const attacks_service_1 = require("./attacks.service");
14
+ const middleware_1 = require("./middleware");
15
+ let CloudflareAttacksModule = CloudflareAttacksModule_1 = class CloudflareAttacksModule {
16
+ configure(consumer) {
17
+ consumer.apply(middleware_1.AttackLoggerMiddleware).forRoutes("*"); // Oppure specifica rotte precise
18
+ }
19
+ static forRoot(options) {
20
+ return {
21
+ module: CloudflareAttacksModule_1,
22
+ imports: [axios_1.HttpModule],
23
+ providers: [
24
+ {
25
+ provide: "CLOUDFLARE_OPTIONS",
26
+ useValue: options,
27
+ },
28
+ ],
29
+ };
30
+ }
31
+ static forRootAsync(options) {
32
+ return {
33
+ module: CloudflareAttacksModule_1,
34
+ imports: [axios_1.HttpModule, ...(options.imports || [])],
35
+ providers: [
36
+ {
37
+ provide: "CLOUDFLARE_OPTIONS",
38
+ useFactory: options.useFactory,
39
+ inject: options.inject || [],
40
+ },
41
+ ],
42
+ };
43
+ }
44
+ };
45
+ exports.CloudflareAttacksModule = CloudflareAttacksModule;
46
+ exports.CloudflareAttacksModule = CloudflareAttacksModule = CloudflareAttacksModule_1 = __decorate([
47
+ (0, common_1.Module)({
48
+ imports: [axios_1.HttpModule],
49
+ providers: [attacks_service_1.AttacksService, middleware_1.AttackLoggerMiddleware],
50
+ exports: [attacks_service_1.AttacksService, axios_1.HttpModule],
51
+ })
52
+ ], CloudflareAttacksModule);
@@ -0,0 +1,10 @@
1
+ import { HttpService } from '@nestjs/axios';
2
+ import type { CloudflareAttacksOptions, CloudflareResponse } from './interfaces';
3
+ export declare class AttacksService {
4
+ private readonly httpService;
5
+ private readonly options;
6
+ private readonly logger;
7
+ private readonly API_URL;
8
+ constructor(httpService: HttpService, options: CloudflareAttacksOptions);
9
+ updateIpList(ip: string): Promise<CloudflareResponse>;
10
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.AttacksService = void 0;
19
+ // attacks.service.ts
20
+ const common_1 = require("@nestjs/common");
21
+ const axios_1 = require("@nestjs/axios");
22
+ const axios_2 = __importDefault(require("axios"));
23
+ const rxjs_1 = require("rxjs");
24
+ let AttacksService = class AttacksService {
25
+ constructor(httpService, options) {
26
+ this.httpService = httpService;
27
+ this.options = options;
28
+ this.logger = new common_1.Logger('AttackLogger');
29
+ this.API_URL = `https://api.cloudflare.com/client/v4/accounts`;
30
+ }
31
+ async updateIpList(ip) {
32
+ const { accountId, listId, apiToken, comment } = this.options;
33
+ const url = `${this.API_URL}/${accountId}/rules/lists/${listId}/items`;
34
+ this.logger.error(`Aggiungo IP ${ip} alla lista Cloudflare`);
35
+ const formattedIp = ip.includes('/') ? ip : `${ip}/32`;
36
+ const body = [{ ip: formattedIp, comment }];
37
+ try {
38
+ const response = await (0, rxjs_1.firstValueFrom)(this.httpService.post(url, body, {
39
+ headers: {
40
+ Authorization: `Bearer ${apiToken}`,
41
+ 'Content-Type': 'application/json',
42
+ },
43
+ }));
44
+ return response.data;
45
+ }
46
+ catch (error) {
47
+ if (axios_2.default.isAxiosError(error)) {
48
+ const data = error.response?.data;
49
+ const message = data?.errors?.[0]?.message || 'Errore Cloudflare API';
50
+ const status = error.response?.status || 500;
51
+ throw new common_1.HttpException(message, status);
52
+ }
53
+ throw new common_1.HttpException('Internal Server Error', 500);
54
+ }
55
+ }
56
+ };
57
+ exports.AttacksService = AttacksService;
58
+ exports.AttacksService = AttacksService = __decorate([
59
+ (0, common_1.Injectable)(),
60
+ __param(1, (0, common_1.Inject)('CLOUDFLARE_OPTIONS')),
61
+ __metadata("design:paramtypes", [axios_1.HttpService, Object])
62
+ ], AttacksService);
@@ -0,0 +1,4 @@
1
+ export * from './interfaces';
2
+ export * from './middleware';
3
+ export * from './attacks.module';
4
+ export * from './attacks.service';
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./interfaces"), exports);
18
+ __exportStar(require("./middleware"), exports);
19
+ __exportStar(require("./attacks.module"), exports);
20
+ __exportStar(require("./attacks.service"), exports);
@@ -0,0 +1,11 @@
1
+ export interface CloudflareAttacksOptions {
2
+ apiToken: string;
3
+ accountId: string;
4
+ listId: string;
5
+ comment: string;
6
+ }
7
+ export interface CloudflareAttacksAsyncOptions {
8
+ imports?: any[];
9
+ inject?: any[];
10
+ useFactory: (...args: any[]) => Promise<CloudflareAttacksOptions> | CloudflareAttacksOptions;
11
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ export interface CloudflareResponse {
2
+ success: boolean;
3
+ errors: any[];
4
+ messages: any[];
5
+ result: {
6
+ operation_id: string;
7
+ };
8
+ }
9
+ export interface CloudflareErrorData {
10
+ errors?: Array<{
11
+ message: string;
12
+ }>;
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export * from './cloudflare-attacks.interface';
2
+ export * from './cloudflare-response.interface';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./cloudflare-attacks.interface"), exports);
18
+ __exportStar(require("./cloudflare-response.interface"), exports);
@@ -0,0 +1,12 @@
1
+ import { NestMiddleware } from "@nestjs/common";
2
+ import { NextFunction, Request, Response } from "express";
3
+ import { AttacksService } from "../attacks.service";
4
+ export declare class AttackLoggerMiddleware implements NestMiddleware {
5
+ private readonly attSrv;
6
+ private readonly logger;
7
+ private readonly logPath;
8
+ constructor(attSrv: AttacksService);
9
+ use(req: Request, res: Response, next: NextFunction): void;
10
+ private processSuspiciousRequest;
11
+ private getClientIp;
12
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.AttackLoggerMiddleware = void 0;
46
+ const fs = __importStar(require("fs/promises")); // Passiamo alla versione asincrona
47
+ const common_1 = require("@nestjs/common");
48
+ const attacks_service_1 = require("../attacks.service");
49
+ let AttackLoggerMiddleware = class AttackLoggerMiddleware {
50
+ constructor(attSrv) {
51
+ this.attSrv = attSrv;
52
+ this.logger = new common_1.Logger("AttackLogger");
53
+ this.logPath = "/var/log/nestjs-attacks.log";
54
+ }
55
+ use(req, res, next) {
56
+ res.on("finish", () => {
57
+ if (res.statusCode === 404) {
58
+ this.processSuspiciousRequest(req).catch((err) => {
59
+ const msg = err instanceof Error ? err.message : "Unknown error";
60
+ this.logger.error(`Errore nel processando attacco: ${msg}`);
61
+ });
62
+ }
63
+ });
64
+ next();
65
+ }
66
+ async processSuspiciousRequest(req) {
67
+ const ip = this.getClientIp(req);
68
+ if (ip === "unknown")
69
+ return;
70
+ const logEntry = `${new Date().toISOString()} [ATTACK] IP=${ip} METHOD=${req.method} URL=${req.url}\n`;
71
+ await this.attSrv.updateIpList(ip);
72
+ try {
73
+ await fs.appendFile(this.logPath, logEntry);
74
+ }
75
+ catch (error) {
76
+ const msg = error instanceof Error ? error.message : "FS Error";
77
+ this.logger.error(`Impossibile scrivere log su ${this.logPath}: ${msg}`);
78
+ }
79
+ }
80
+ getClientIp(req) {
81
+ const cfIp = req.headers["cf-connecting-ip"];
82
+ if (typeof cfIp === "string")
83
+ return cfIp;
84
+ const xRealIp = req.headers["x-real-ip"];
85
+ if (typeof xRealIp === "string")
86
+ return xRealIp;
87
+ const xForwardedFor = req.headers["x-forwarded-for"];
88
+ if (typeof xForwardedFor === "string") {
89
+ return xForwardedFor.split(",")[0].trim();
90
+ }
91
+ return req.socket.remoteAddress ?? "unknown";
92
+ }
93
+ };
94
+ exports.AttackLoggerMiddleware = AttackLoggerMiddleware;
95
+ exports.AttackLoggerMiddleware = AttackLoggerMiddleware = __decorate([
96
+ (0, common_1.Injectable)(),
97
+ __metadata("design:paramtypes", [attacks_service_1.AttacksService])
98
+ ], AttackLoggerMiddleware);
@@ -0,0 +1 @@
1
+ export * from './attack-logger.middleware';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./attack-logger.middleware"), exports);
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@liberstudio/cloudflare-list",
3
+ "version": "2.0.1",
4
+ "description": "Modulo NestJS per gestione IP List Cloudflare",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "npx tsc",
12
+ "prepublishOnly": "npm run build",
13
+ "version:bump": "npm version patch --no-git-tag-version"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "simple-git-hooks": {
19
+ "pre-commit": "npm run version:bump && git add package.json package-lock.json"
20
+ },
21
+ "dependencies": {},
22
+ "peerDependencies": {
23
+ "@nestjs/axios": ">=3.0.0",
24
+ "@nestjs/common": ">=10.0.0",
25
+ "axios": ">=1.0.0",
26
+ "rxjs": ">=7.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@nestjs/axios": ">=3.0.0",
30
+ "@nestjs/common": ">=10.0.0",
31
+ "axios": ">=1.0.0",
32
+ "rxjs": "^7.8.0",
33
+ "@types/express": "^5.0.6",
34
+ "@types/node": "^20.9.0",
35
+ "simple-git-hooks": "^2.13.1",
36
+ "typescript": ">=5.0.0"
37
+ }
38
+ }