mm_ip 1.0.0 → 1.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 +173 -0
- package/README_EN.md +173 -0
- package/cache/ip/black.json +27 -0
- package/cache/ip/violation.json +5 -0
- package/cache/ip/white.json +4 -0
- package/index.js +235 -4
- package/package.json +1 -1
- package/test.js +129 -0
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# mm_ip
|
|
2
|
+
|
|
3
|
+
[English](README_EN.md) | [中文](README.md)
|
|
4
|
+
|
|
5
|
+
一个功能强大的IP管理模块,支持白名单、黑名单管理、IP请求频率监控、违规记录和持久化存储。
|
|
6
|
+
|
|
7
|
+
## 功能特性
|
|
8
|
+
|
|
9
|
+
- ✅ **白名单管理** - 支持添加、删除、查询白名单IP
|
|
10
|
+
- ✅ **黑名单管理** - 支持添加、删除、查询黑名单IP,支持自动过期
|
|
11
|
+
- ✅ **IP请求频率监控** - 实时监控IP请求频率,防止高频访问
|
|
12
|
+
- ✅ **自动拉黑机制** - 支持高频访问自动拉黑和违规次数超限自动拉黑
|
|
13
|
+
- ✅ **违规记录系统** - 记录IP违规行为,支持违规次数统计和重置
|
|
14
|
+
- ✅ **持久化存储** - 支持数据分文件存储(白名单、黑名单、违规记录独立存储)
|
|
15
|
+
- ✅ **自动保存机制** - 支持定时自动保存和操作触发保存
|
|
16
|
+
- ✅ **重启数据恢复** - 支持重启后自动加载持久化数据
|
|
17
|
+
- ✅ **灵活配置** - 支持自定义各种阈值和参数
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install mm_ip
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 快速开始
|
|
26
|
+
|
|
27
|
+
### 基本使用
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const { Ip } = require('mm_ip');
|
|
31
|
+
|
|
32
|
+
// 创建IP管理实例
|
|
33
|
+
const ip_manager = new Ip();
|
|
34
|
+
|
|
35
|
+
// 设置日志器(可选)
|
|
36
|
+
ip_manager.setup(console);
|
|
37
|
+
|
|
38
|
+
// 添加白名单IP
|
|
39
|
+
ip_manager.addWhite('192.168.1.100');
|
|
40
|
+
|
|
41
|
+
// 添加黑名单IP
|
|
42
|
+
ip_manager.addBlack('10.0.0.100');
|
|
43
|
+
|
|
44
|
+
// 检查IP状态
|
|
45
|
+
console.log('192.168.1.100 在白名单:', ip_manager.isWhite('192.168.1.100'));
|
|
46
|
+
console.log('10.0.0.100 在黑名单:', ip_manager.isBlack('10.0.0.100'));
|
|
47
|
+
|
|
48
|
+
// 记录IP请求
|
|
49
|
+
console.log('192.168.1.100 请求结果:', ip_manager.record('192.168.1.100'));
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 持久化存储配置
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
// 创建带持久化配置的实例
|
|
56
|
+
const persistent_ip = new Ip({
|
|
57
|
+
dir: './cache/ip', // 存储目录
|
|
58
|
+
max_white: 1000, // 最大白名单数量
|
|
59
|
+
max_black: 1000 // 最大黑名单数量
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// 添加数据后会自动保存到文件
|
|
63
|
+
persistent_ip.addWhite('192.168.1.101');
|
|
64
|
+
persistent_ip.addBlack('10.0.0.101');
|
|
65
|
+
|
|
66
|
+
// 重启后自动加载数据
|
|
67
|
+
const new_ip = new Ip({ dir: './cache/ip' });
|
|
68
|
+
console.log('重启后白名单数量:', new_ip.getAllWhite().length);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## API文档
|
|
72
|
+
|
|
73
|
+
### 构造函数
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
new Ip(config)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**配置参数 (config):**
|
|
80
|
+
|
|
81
|
+
| 参数 | 类型 | 默认值 | 描述 |
|
|
82
|
+
|------|------|--------|------|
|
|
83
|
+
| `max_white` | number | 1000 | 最大白名单数量 |
|
|
84
|
+
| `max_black` | number | 1000 | 最大黑名单数量 |
|
|
85
|
+
| `check_interval` | number | 60000 | 检查间隔(毫秒) |
|
|
86
|
+
| `max_req_per_min` | number | 100 | 每分钟最大请求数 |
|
|
87
|
+
| `auto_black_enable` | boolean | true | 启用自动高频拉黑 |
|
|
88
|
+
| `auto_black_threshold` | number | 50 | 自动拉黑阈值 |
|
|
89
|
+
| `auto_black_duration` | number | 3600000 | 自动拉黑持续时间(毫秒) |
|
|
90
|
+
| `violation_enable` | boolean | true | 启用违规记录 |
|
|
91
|
+
| `violation_max_count` | number | 10 | 最大违规次数 |
|
|
92
|
+
| `violation_reset_time` | number | 86400000 | 违规记录重置时间(毫秒) |
|
|
93
|
+
| `violation_auto_black` | boolean | true | 违规次数超限自动拉黑 |
|
|
94
|
+
| `dir` | string | './cache/ip' | 持久化存储目录 |
|
|
95
|
+
|
|
96
|
+
### 主要方法
|
|
97
|
+
|
|
98
|
+
#### 白名单操作
|
|
99
|
+
- `addWhite(ip)` - 添加白名单IP
|
|
100
|
+
- `delWhite(ip)` - 删除白名单IP
|
|
101
|
+
- `isWhite(ip)` - 检查是否在白名单
|
|
102
|
+
- `getAllWhite()` - 获取所有白名单IP
|
|
103
|
+
- `clearWhite()` - 清空白名单
|
|
104
|
+
|
|
105
|
+
#### 黑名单操作
|
|
106
|
+
- `addBlack(ip)` - 添加黑名单IP
|
|
107
|
+
- `delBlack(ip)` - 删除黑名单IP
|
|
108
|
+
- `isBlack(ip)` - 检查是否在黑名单
|
|
109
|
+
- `getAllBlack()` - 获取所有黑名单IP
|
|
110
|
+
- `clearBlack()` - 清空黑名单
|
|
111
|
+
- `getBlackExpireTime(ip)` - 获取黑名单过期时间
|
|
112
|
+
|
|
113
|
+
#### IP请求记录
|
|
114
|
+
- `record(ip)` - 记录IP请求,返回是否允许访问
|
|
115
|
+
- `getReqCount(ip)` - 获取IP请求次数
|
|
116
|
+
- `getReqFreq(ip)` - 获取IP请求频率
|
|
117
|
+
|
|
118
|
+
#### 违规记录
|
|
119
|
+
- `recordViolation(ip, reason)` - 记录IP违规
|
|
120
|
+
- `getViolationCount(ip)` - 获取违规次数
|
|
121
|
+
- `resetViolation(ip)` - 重置违规记录
|
|
122
|
+
- `clearViolations()` - 清空所有违规记录
|
|
123
|
+
- `getAllViolations()` - 获取所有违规记录
|
|
124
|
+
|
|
125
|
+
#### 持久化存储
|
|
126
|
+
- `save()` - 手动保存数据
|
|
127
|
+
- `load()` - 手动加载数据
|
|
128
|
+
- `autoSave(interval)` - 开启自动保存
|
|
129
|
+
- `stopAutoSave()` - 停止自动保存
|
|
130
|
+
|
|
131
|
+
#### 综合操作
|
|
132
|
+
- `del(ip)` - 删除IP的所有记录
|
|
133
|
+
- `setup(logger)` - 设置日志器
|
|
134
|
+
|
|
135
|
+
## 存储文件结构
|
|
136
|
+
|
|
137
|
+
当启用持久化存储时,数据会分三个文件存储:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
cache/ip/
|
|
141
|
+
├── white.json # 白名单数据
|
|
142
|
+
├── black.json # 黑名单数据
|
|
143
|
+
└── violation.json # 违规记录数据
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
每个文件包含对应的数据数组和时间戳信息。
|
|
147
|
+
|
|
148
|
+
## 测试
|
|
149
|
+
|
|
150
|
+
运行测试用例:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
或直接运行:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
node test.js
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 许可证
|
|
163
|
+
|
|
164
|
+
ISC License
|
|
165
|
+
|
|
166
|
+
## 作者
|
|
167
|
+
|
|
168
|
+
qww
|
|
169
|
+
|
|
170
|
+
## 仓库地址
|
|
171
|
+
|
|
172
|
+
- Gitee: https://gitee.com/qiuwenwu91/mm_ip.git
|
|
173
|
+
- npm: https://www.npmjs.com/package/mm_ip
|
package/README_EN.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# mm_ip
|
|
2
|
+
|
|
3
|
+
[English](README_EN.md) | [中文](README.md)
|
|
4
|
+
|
|
5
|
+
A powerful IP management module that supports whitelist, blacklist management, IP request frequency monitoring, violation records, and persistent storage.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- ✅ **Whitelist Management** - Add, remove, and query whitelist IPs
|
|
10
|
+
- ✅ **Blacklist Management** - Add, remove, and query blacklist IPs with auto-expiration
|
|
11
|
+
- ✅ **IP Request Frequency Monitoring** - Real-time IP request frequency monitoring to prevent high-frequency access
|
|
12
|
+
- ✅ **Auto-Blacklist Mechanism** - Automatic blacklisting for high-frequency access and violation limit exceeding
|
|
13
|
+
- ✅ **Violation Record System** - Record IP violation behaviors with violation count statistics and reset
|
|
14
|
+
- ✅ **Persistent Storage** - Support for separate file storage (whitelist, blacklist, violation records stored independently)
|
|
15
|
+
- ✅ **Auto-Save Mechanism** - Support for timed auto-save and operation-triggered save
|
|
16
|
+
- ✅ **Data Recovery on Restart** - Automatic loading of persistent data after restart
|
|
17
|
+
- ✅ **Flexible Configuration** - Support for custom thresholds and parameters
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install mm_ip
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Basic Usage
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const { Ip } = require('mm_ip');
|
|
31
|
+
|
|
32
|
+
// Create IP management instance
|
|
33
|
+
const ip_manager = new Ip();
|
|
34
|
+
|
|
35
|
+
// Setup logger (optional)
|
|
36
|
+
ip_manager.setup(console);
|
|
37
|
+
|
|
38
|
+
// Add whitelist IP
|
|
39
|
+
ip_manager.addWhite('192.168.1.100');
|
|
40
|
+
|
|
41
|
+
// Add blacklist IP
|
|
42
|
+
ip_manager.addBlack('10.0.0.100');
|
|
43
|
+
|
|
44
|
+
// Check IP status
|
|
45
|
+
console.log('192.168.1.100 in whitelist:', ip_manager.isWhite('192.168.1.100'));
|
|
46
|
+
console.log('10.0.0.100 in blacklist:', ip_manager.isBlack('10.0.0.100'));
|
|
47
|
+
|
|
48
|
+
// Record IP request
|
|
49
|
+
console.log('192.168.1.100 request result:', ip_manager.record('192.168.1.100'));
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Persistent Storage Configuration
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
// Create instance with persistent storage configuration
|
|
56
|
+
const persistent_ip = new Ip({
|
|
57
|
+
dir: './cache/ip', // Storage directory
|
|
58
|
+
max_white: 1000, // Maximum whitelist count
|
|
59
|
+
max_black: 1000 // Maximum blacklist count
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Data will be automatically saved after adding
|
|
63
|
+
persistent_ip.addWhite('192.168.1.101');
|
|
64
|
+
persistent_ip.addBlack('10.0.0.101');
|
|
65
|
+
|
|
66
|
+
// Auto-load data after restart
|
|
67
|
+
const new_ip = new Ip({ dir: './cache/ip' });
|
|
68
|
+
console.log('Whitelist count after restart:', new_ip.getAllWhite().length);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## API Documentation
|
|
72
|
+
|
|
73
|
+
### Constructor
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
new Ip(config)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Configuration Parameters (config):**
|
|
80
|
+
|
|
81
|
+
| Parameter | Type | Default | Description |
|
|
82
|
+
|-----------|------|---------|-------------|
|
|
83
|
+
| `max_white` | number | 1000 | Maximum whitelist count |
|
|
84
|
+
| `max_black` | number | 1000 | Maximum blacklist count |
|
|
85
|
+
| `check_interval` | number | 60000 | Check interval (milliseconds) |
|
|
86
|
+
| `max_req_per_min` | number | 100 | Maximum requests per minute |
|
|
87
|
+
| `auto_black_enable` | boolean | true | Enable auto-blacklist for high frequency |
|
|
88
|
+
| `auto_black_threshold` | number | 50 | Auto-blacklist threshold |
|
|
89
|
+
| `auto_black_duration` | number | 3600000 | Auto-blacklist duration (milliseconds) |
|
|
90
|
+
| `violation_enable` | boolean | true | Enable violation records |
|
|
91
|
+
| `violation_max_count` | number | 10 | Maximum violation count |
|
|
92
|
+
| `violation_reset_time` | number | 86400000 | Violation record reset time (milliseconds) |
|
|
93
|
+
| `violation_auto_black` | boolean | true | Auto-blacklist when violation count exceeds limit |
|
|
94
|
+
| `dir` | string | './cache/ip' | Persistent storage directory |
|
|
95
|
+
|
|
96
|
+
### Main Methods
|
|
97
|
+
|
|
98
|
+
#### Whitelist Operations
|
|
99
|
+
- `addWhite(ip)` - Add IP to whitelist
|
|
100
|
+
- `delWhite(ip)` - Remove IP from whitelist
|
|
101
|
+
- `isWhite(ip)` - Check if IP is in whitelist
|
|
102
|
+
- `getAllWhite()` - Get all whitelist IPs
|
|
103
|
+
- `clearWhite()` - Clear all whitelist IPs
|
|
104
|
+
|
|
105
|
+
#### Blacklist Operations
|
|
106
|
+
- `addBlack(ip)` - Add IP to blacklist
|
|
107
|
+
- `delBlack(ip)` - Remove IP from blacklist
|
|
108
|
+
- `isBlack(ip)` - Check if IP is in blacklist
|
|
109
|
+
- `getAllBlack()` - Get all blacklist IPs
|
|
110
|
+
- `clearBlack()` - Clear all blacklist IPs
|
|
111
|
+
- `getBlackExpireTime(ip)` - Get blacklist expiration time
|
|
112
|
+
|
|
113
|
+
#### IP Request Recording
|
|
114
|
+
- `record(ip)` - Record IP request, return whether access is allowed
|
|
115
|
+
- `getReqCount(ip)` - Get IP request count
|
|
116
|
+
- `getReqFreq(ip)` - Get IP request frequency
|
|
117
|
+
|
|
118
|
+
#### Violation Records
|
|
119
|
+
- `recordViolation(ip, reason)` - Record IP violation
|
|
120
|
+
- `getViolationCount(ip)` - Get violation count
|
|
121
|
+
- `resetViolation(ip)` - Reset violation record
|
|
122
|
+
- `clearViolations()` - Clear all violation records
|
|
123
|
+
- `getAllViolations()` - Get all violation records
|
|
124
|
+
|
|
125
|
+
#### Persistent Storage
|
|
126
|
+
- `save()` - Manually save data
|
|
127
|
+
- `load()` - Manually load data
|
|
128
|
+
- `autoSave(interval)` - Enable auto-save
|
|
129
|
+
- `stopAutoSave()` - Stop auto-save
|
|
130
|
+
|
|
131
|
+
#### Comprehensive Operations
|
|
132
|
+
- `del(ip)` - Delete all records for an IP
|
|
133
|
+
- `setup(logger)` - Setup logger
|
|
134
|
+
|
|
135
|
+
## Storage File Structure
|
|
136
|
+
|
|
137
|
+
When persistent storage is enabled, data is stored in three separate files:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
cache/ip/
|
|
141
|
+
├── white.json # Whitelist data
|
|
142
|
+
├── black.json # Blacklist data
|
|
143
|
+
└── violation.json # Violation record data
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Each file contains corresponding data arrays and timestamp information.
|
|
147
|
+
|
|
148
|
+
## Testing
|
|
149
|
+
|
|
150
|
+
Run test cases:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Or run directly:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
node test.js
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
ISC License
|
|
165
|
+
|
|
166
|
+
## Author
|
|
167
|
+
|
|
168
|
+
qww
|
|
169
|
+
|
|
170
|
+
## Repository
|
|
171
|
+
|
|
172
|
+
- Gitee: https://gitee.com/qiuwenwu91/mm_ip.git
|
|
173
|
+
- npm: https://www.npmjs.com/package/mm_ip
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"black": [
|
|
3
|
+
"192.168.100.2",
|
|
4
|
+
"192.168.200.1",
|
|
5
|
+
"192.168.200.2",
|
|
6
|
+
"192.168.200.3"
|
|
7
|
+
],
|
|
8
|
+
"black_time": [
|
|
9
|
+
[
|
|
10
|
+
"172.16.0.2",
|
|
11
|
+
1765261940971
|
|
12
|
+
],
|
|
13
|
+
[
|
|
14
|
+
"192.168.100.2",
|
|
15
|
+
1765262134846
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
"192.168.200.2",
|
|
19
|
+
1765262135900
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"192.168.200.3",
|
|
23
|
+
1765262135908
|
|
24
|
+
]
|
|
25
|
+
],
|
|
26
|
+
"timestamp": 1765262142949
|
|
27
|
+
}
|
package/index.js
CHANGED
|
@@ -25,7 +25,8 @@ class Ip {
|
|
|
25
25
|
violation_enable: true, // 启用违规记录
|
|
26
26
|
violation_max_count: 10, // 最大违规次数
|
|
27
27
|
violation_reset_time: 86400000, // 违规记录重置时间(24小时)
|
|
28
|
-
violation_auto_black: true // 违规次数超限自动拉黑
|
|
28
|
+
violation_auto_black: true, // 违规次数超限自动拉黑
|
|
29
|
+
dir: './cache/ip' // 持久化存储目录
|
|
29
30
|
}, config || {});
|
|
30
31
|
|
|
31
32
|
this._white = new Set();
|
|
@@ -36,6 +37,11 @@ class Ip {
|
|
|
36
37
|
this._violation_count = new Map(); // 违规次数记录
|
|
37
38
|
this._violation_time = new Map(); // 违规时间记录
|
|
38
39
|
this._logger = $.log || console;
|
|
40
|
+
|
|
41
|
+
// 自动加载持久化数据
|
|
42
|
+
if (this._config.dir) {
|
|
43
|
+
this.load();
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
|
|
@@ -75,6 +81,12 @@ Ip.prototype.addWhite = function (ip) {
|
|
|
75
81
|
|
|
76
82
|
this._white.add(ip);
|
|
77
83
|
this.logger('info', '添加白名单IP:', ip);
|
|
84
|
+
|
|
85
|
+
// 自动保存到持久化存储
|
|
86
|
+
if (this._config.dir) {
|
|
87
|
+
this.save();
|
|
88
|
+
}
|
|
89
|
+
|
|
78
90
|
return true;
|
|
79
91
|
};
|
|
80
92
|
|
|
@@ -94,6 +106,12 @@ Ip.prototype.addBlack = function (ip) {
|
|
|
94
106
|
|
|
95
107
|
this._black.add(ip);
|
|
96
108
|
this.logger('info', '添加黑名单IP:', ip);
|
|
109
|
+
|
|
110
|
+
// 自动保存到持久化存储
|
|
111
|
+
if (this._config.dir) {
|
|
112
|
+
this.save();
|
|
113
|
+
}
|
|
114
|
+
|
|
97
115
|
return true;
|
|
98
116
|
};
|
|
99
117
|
|
|
@@ -109,6 +127,11 @@ Ip.prototype.delWhite = function (ip) {
|
|
|
109
127
|
const result = this._white.delete(ip);
|
|
110
128
|
if (result) {
|
|
111
129
|
this.logger('info', '删除白名单IP:', ip);
|
|
130
|
+
|
|
131
|
+
// 自动保存到持久化存储
|
|
132
|
+
if (this._config.dir) {
|
|
133
|
+
this.save();
|
|
134
|
+
}
|
|
112
135
|
}
|
|
113
136
|
return result;
|
|
114
137
|
};
|
|
@@ -125,6 +148,11 @@ Ip.prototype.delBlack = function (ip) {
|
|
|
125
148
|
const result = this._black.delete(ip);
|
|
126
149
|
if (result) {
|
|
127
150
|
this.logger('info', '删除黑名单IP:', ip);
|
|
151
|
+
|
|
152
|
+
// 自动保存到持久化存储
|
|
153
|
+
if (this._config.dir) {
|
|
154
|
+
this.save();
|
|
155
|
+
}
|
|
128
156
|
}
|
|
129
157
|
return result;
|
|
130
158
|
};
|
|
@@ -294,17 +322,27 @@ Ip.prototype.getAllReqIps = function () {
|
|
|
294
322
|
/**
|
|
295
323
|
* 清空白名单
|
|
296
324
|
*/
|
|
297
|
-
Ip.prototype.clearWhite = function
|
|
325
|
+
Ip.prototype.clearWhite = function() {
|
|
298
326
|
this._white.clear();
|
|
299
327
|
this.logger('info', '清空白名单');
|
|
328
|
+
|
|
329
|
+
// 自动保存到持久化存储
|
|
330
|
+
if (this._config.dir) {
|
|
331
|
+
this.save();
|
|
332
|
+
}
|
|
300
333
|
};
|
|
301
334
|
|
|
302
335
|
/**
|
|
303
336
|
* 清空黑名单
|
|
304
337
|
*/
|
|
305
|
-
Ip.prototype.clearBlack = function
|
|
338
|
+
Ip.prototype.clearBlack = function() {
|
|
306
339
|
this._black.clear();
|
|
307
340
|
this.logger('info', '清空黑名单');
|
|
341
|
+
|
|
342
|
+
// 自动保存到持久化存储
|
|
343
|
+
if (this._config.dir) {
|
|
344
|
+
this.save();
|
|
345
|
+
}
|
|
308
346
|
};
|
|
309
347
|
|
|
310
348
|
/**
|
|
@@ -620,6 +658,194 @@ Ip.prototype.clearViolations = function() {
|
|
|
620
658
|
this._violation_count.clear();
|
|
621
659
|
this._violation_time.clear();
|
|
622
660
|
this.logger('info', '清空所有违规记录');
|
|
661
|
+
|
|
662
|
+
// 自动保存到持久化存储
|
|
663
|
+
if (this._config.dir) {
|
|
664
|
+
this.save();
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* 保存IP数据到文件(持久化存储)
|
|
670
|
+
* @returns {boolean} 是否保存成功
|
|
671
|
+
*/
|
|
672
|
+
Ip.prototype.save = function() {
|
|
673
|
+
try {
|
|
674
|
+
const fs = require('fs');
|
|
675
|
+
const path = require('path');
|
|
676
|
+
|
|
677
|
+
// 确保存储目录存在
|
|
678
|
+
const dir = this._config.dir;
|
|
679
|
+
dir.addDir();
|
|
680
|
+
|
|
681
|
+
// 分别保存不同数据到不同文件
|
|
682
|
+
const timestamp = Date.now();
|
|
683
|
+
|
|
684
|
+
// 保存白名单数据
|
|
685
|
+
const whiteData = {
|
|
686
|
+
white: this.getAllWhite(),
|
|
687
|
+
timestamp: timestamp
|
|
688
|
+
};
|
|
689
|
+
const whitePath = path.join(dir, 'white.json');
|
|
690
|
+
fs.writeFileSync(whitePath, JSON.stringify(whiteData, null, 2), 'utf8');
|
|
691
|
+
|
|
692
|
+
// 保存黑名单数据
|
|
693
|
+
const blackData = {
|
|
694
|
+
black: this.getAllBlack(),
|
|
695
|
+
black_time: Array.from(this._black_time.entries()),
|
|
696
|
+
timestamp: timestamp
|
|
697
|
+
};
|
|
698
|
+
const blackPath = path.join(dir, 'black.json');
|
|
699
|
+
fs.writeFileSync(blackPath, JSON.stringify(blackData, null, 2), 'utf8');
|
|
700
|
+
|
|
701
|
+
// 保存违规记录数据
|
|
702
|
+
const violationData = {
|
|
703
|
+
violation_count: Array.from(this._violation_count.entries()),
|
|
704
|
+
violation_time: Array.from(this._violation_time.entries()),
|
|
705
|
+
timestamp: timestamp
|
|
706
|
+
};
|
|
707
|
+
const violationPath = path.join(dir, 'violation.json');
|
|
708
|
+
fs.writeFileSync(violationPath, JSON.stringify(violationData, null, 2), 'utf8');
|
|
709
|
+
|
|
710
|
+
this.logger('info', 'IP数据已分文件保存:', {
|
|
711
|
+
white: whitePath,
|
|
712
|
+
black: blackPath,
|
|
713
|
+
violation: violationPath
|
|
714
|
+
});
|
|
715
|
+
return true;
|
|
716
|
+
} catch (err) {
|
|
717
|
+
this.logger('error', '保存IP数据失败:', err.message);
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* 从文件加载IP数据(持久化存储)
|
|
724
|
+
* @returns {boolean} 是否加载成功
|
|
725
|
+
*/
|
|
726
|
+
Ip.prototype.load = function() {
|
|
727
|
+
try {
|
|
728
|
+
const fs = require('fs');
|
|
729
|
+
const path = require('path');
|
|
730
|
+
|
|
731
|
+
const dir = this._config.dir;
|
|
732
|
+
let loadedCount = 0;
|
|
733
|
+
|
|
734
|
+
// 加载白名单数据
|
|
735
|
+
const whitePath = path.join(dir, 'white.json');
|
|
736
|
+
if (fs.existsSync(whitePath)) {
|
|
737
|
+
const content = fs.readFileSync(whitePath, 'utf8');
|
|
738
|
+
const data = JSON.parse(content);
|
|
739
|
+
|
|
740
|
+
if (Array.isArray(data.white)) {
|
|
741
|
+
for (const ip of data.white) {
|
|
742
|
+
if (typeof ip === 'string') {
|
|
743
|
+
this._white.add(ip);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
loadedCount++;
|
|
747
|
+
this.logger('info', '白名单数据已加载:', whitePath);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// 加载黑名单数据
|
|
752
|
+
const blackPath = path.join(dir, 'black.json');
|
|
753
|
+
if (fs.existsSync(blackPath)) {
|
|
754
|
+
const content = fs.readFileSync(blackPath, 'utf8');
|
|
755
|
+
const data = JSON.parse(content);
|
|
756
|
+
|
|
757
|
+
// 加载黑名单
|
|
758
|
+
if (Array.isArray(data.black)) {
|
|
759
|
+
for (const ip of data.black) {
|
|
760
|
+
if (typeof ip === 'string') {
|
|
761
|
+
this._black.add(ip);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// 加载黑名单过期时间
|
|
767
|
+
if (Array.isArray(data.black_time)) {
|
|
768
|
+
for (const [ip, time] of data.black_time) {
|
|
769
|
+
if (typeof ip === 'string' && typeof time === 'number') {
|
|
770
|
+
this._black_time.set(ip, time);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
loadedCount++;
|
|
776
|
+
this.logger('info', '黑名单数据已加载:', blackPath);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// 加载违规记录数据
|
|
780
|
+
const violationPath = path.join(dir, 'violation.json');
|
|
781
|
+
if (fs.existsSync(violationPath)) {
|
|
782
|
+
const content = fs.readFileSync(violationPath, 'utf8');
|
|
783
|
+
const data = JSON.parse(content);
|
|
784
|
+
|
|
785
|
+
// 加载违规记录
|
|
786
|
+
if (Array.isArray(data.violation_count)) {
|
|
787
|
+
for (const [ip, count] of data.violation_count) {
|
|
788
|
+
if (typeof ip === 'string' && typeof count === 'number') {
|
|
789
|
+
this._violation_count.set(ip, count);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (Array.isArray(data.violation_time)) {
|
|
795
|
+
for (const [ip, time] of data.violation_time) {
|
|
796
|
+
if (typeof ip === 'string' && typeof time === 'number') {
|
|
797
|
+
this._violation_time.set(ip, time);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
loadedCount++;
|
|
803
|
+
this.logger('info', '违规记录数据已加载:', violationPath);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (loadedCount === 0) {
|
|
807
|
+
this.logger('info', '未找到任何IP数据文件,跳过加载');
|
|
808
|
+
} else {
|
|
809
|
+
this.logger('info', 'IP数据加载完成,统计:', {
|
|
810
|
+
white_count: this.getAllWhite().length,
|
|
811
|
+
black_count: this.getAllBlack().length,
|
|
812
|
+
violation_count: this.getAllViolationIps().length,
|
|
813
|
+
files_loaded: loadedCount
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return true;
|
|
818
|
+
} catch (err) {
|
|
819
|
+
this.logger('error', '加载IP数据失败:', err.message);
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* 自动保存数据(定时保存)
|
|
826
|
+
* @param {number} interval - 保存间隔(毫秒),默认5分钟
|
|
827
|
+
*/
|
|
828
|
+
Ip.prototype.autoSave = function(interval = 300000) {
|
|
829
|
+
if (this._autoSaveTimer) {
|
|
830
|
+
clearInterval(this._autoSaveTimer);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
this._autoSaveTimer = setInterval(() => {
|
|
834
|
+
this.save();
|
|
835
|
+
}, interval);
|
|
836
|
+
|
|
837
|
+
this.logger('info', '自动保存已启动,间隔:', interval, 'ms');
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* 停止自动保存
|
|
842
|
+
*/
|
|
843
|
+
Ip.prototype.stopAutoSave = function() {
|
|
844
|
+
if (this._autoSaveTimer) {
|
|
845
|
+
clearInterval(this._autoSaveTimer);
|
|
846
|
+
this._autoSaveTimer = null;
|
|
847
|
+
this.logger('info', '自动保存已停止');
|
|
848
|
+
}
|
|
623
849
|
};
|
|
624
850
|
|
|
625
851
|
/**
|
|
@@ -669,9 +895,14 @@ Ip.prototype.del = function(ip) {
|
|
|
669
895
|
result.black_time = true;
|
|
670
896
|
}
|
|
671
897
|
|
|
672
|
-
//
|
|
898
|
+
// 如果有任何删除操作,记录日志并自动保存
|
|
673
899
|
if (Object.values(result).some(Boolean)) {
|
|
674
900
|
this.logger('info', '删除IP记录:', { ip, result });
|
|
901
|
+
|
|
902
|
+
// 自动保存到持久化存储
|
|
903
|
+
if (this._config.dir) {
|
|
904
|
+
this.save();
|
|
905
|
+
}
|
|
675
906
|
}
|
|
676
907
|
|
|
677
908
|
return result;
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -198,6 +198,135 @@ setTimeout(() => {
|
|
|
198
198
|
ip_manager.clearViolations();
|
|
199
199
|
console.log('清空后违规记录数量:', Object.keys(ip_manager.getAllViolations()).length);
|
|
200
200
|
|
|
201
|
+
// 测试13: 持久化存储功能(分文件存储)
|
|
202
|
+
console.log('\n13. 测试持久化存储功能(分文件存储):');
|
|
203
|
+
|
|
204
|
+
// 创建带持久化配置的实例
|
|
205
|
+
const persistent_ip = new Ip({
|
|
206
|
+
dir: './cache/ip',
|
|
207
|
+
max_white: 3,
|
|
208
|
+
max_black: 3
|
|
209
|
+
});
|
|
210
|
+
persistent_ip.setup(logger);
|
|
211
|
+
|
|
212
|
+
// 添加测试数据
|
|
213
|
+
console.log('添加测试数据到持久化实例:');
|
|
214
|
+
persistent_ip.addWhite('192.168.300.1');
|
|
215
|
+
persistent_ip.addWhite('192.168.300.2');
|
|
216
|
+
persistent_ip.addBlack('10.0.300.1');
|
|
217
|
+
persistent_ip.addBlack('10.0.300.2');
|
|
218
|
+
persistent_ip.recordViolation('172.16.300.1', '测试违规');
|
|
219
|
+
|
|
220
|
+
console.log('保存前数据统计:');
|
|
221
|
+
console.log('白名单数量:', persistent_ip.getAllWhite().length);
|
|
222
|
+
console.log('黑名单数量:', persistent_ip.getAllBlack().length);
|
|
223
|
+
console.log('违规记录数量:', persistent_ip.getAllViolationIps().length);
|
|
224
|
+
|
|
225
|
+
// 保存数据到分文件
|
|
226
|
+
console.log('保存数据到分文件:', persistent_ip.save());
|
|
227
|
+
|
|
228
|
+
// 验证文件是否创建
|
|
229
|
+
const fs = require('fs');
|
|
230
|
+
const path = require('path');
|
|
231
|
+
const whiteFile = path.join('./cache/ip', 'white.json');
|
|
232
|
+
const blackFile = path.join('./cache/ip', 'black.json');
|
|
233
|
+
const violationFile = path.join('./cache/ip', 'violation.json');
|
|
234
|
+
|
|
235
|
+
console.log('检查分文件存储:');
|
|
236
|
+
console.log('白名单文件存在:', fs.existsSync(whiteFile));
|
|
237
|
+
console.log('黑名单文件存在:', fs.existsSync(blackFile));
|
|
238
|
+
console.log('违规记录文件存在:', fs.existsSync(violationFile));
|
|
239
|
+
|
|
240
|
+
// 验证文件内容
|
|
241
|
+
if (fs.existsSync(whiteFile)) {
|
|
242
|
+
const whiteData = JSON.parse(fs.readFileSync(whiteFile, 'utf8'));
|
|
243
|
+
console.log('白名单文件数据:', whiteData.white);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (fs.existsSync(blackFile)) {
|
|
247
|
+
const blackData = JSON.parse(fs.readFileSync(blackFile, 'utf8'));
|
|
248
|
+
console.log('黑名单文件数据:', blackData.black);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (fs.existsSync(violationFile)) {
|
|
252
|
+
const violationData = JSON.parse(fs.readFileSync(violationFile, 'utf8'));
|
|
253
|
+
console.log('违规记录文件数据:', violationData.violation_count);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 创建新实例并加载数据
|
|
257
|
+
console.log('创建新实例并加载数据:');
|
|
258
|
+
const loaded_ip = new Ip({
|
|
259
|
+
dir: './cache/ip'
|
|
260
|
+
});
|
|
261
|
+
loaded_ip.setup(logger);
|
|
262
|
+
|
|
263
|
+
console.log('加载后数据统计:');
|
|
264
|
+
console.log('白名单数量:', loaded_ip.getAllWhite().length);
|
|
265
|
+
console.log('黑名单数量:', loaded_ip.getAllBlack().length);
|
|
266
|
+
console.log('违规记录数量:', loaded_ip.getAllViolationIps().length);
|
|
267
|
+
|
|
268
|
+
// 验证数据一致性
|
|
269
|
+
console.log('验证数据一致性:');
|
|
270
|
+
console.log('192.168.300.1 在白名单:', loaded_ip.isWhite('192.168.300.1'));
|
|
271
|
+
console.log('10.0.300.1 在黑名单:', loaded_ip.isBlack('10.0.300.1'));
|
|
272
|
+
console.log('172.16.300.1 违规次数:', loaded_ip.getViolationCount('172.16.300.1'));
|
|
273
|
+
|
|
274
|
+
// 测试自动保存
|
|
275
|
+
console.log('\n测试自动保存功能:');
|
|
276
|
+
loaded_ip.autoSave(2000); // 2秒间隔便于测试
|
|
277
|
+
|
|
278
|
+
// 添加新数据
|
|
279
|
+
setTimeout(() => {
|
|
280
|
+
console.log('添加新数据触发自动保存:');
|
|
281
|
+
loaded_ip.addWhite('192.168.300.3');
|
|
282
|
+
|
|
283
|
+
// 停止自动保存
|
|
284
|
+
setTimeout(() => {
|
|
285
|
+
loaded_ip.stopAutoSave();
|
|
286
|
+
console.log('自动保存已停止');
|
|
287
|
+
|
|
288
|
+
// 测试删除操作触发自动保存
|
|
289
|
+
console.log('测试删除操作触发自动保存:');
|
|
290
|
+
loaded_ip.del('192.168.300.1');
|
|
291
|
+
|
|
292
|
+
// 测试清空操作触发自动保存
|
|
293
|
+
console.log('测试清空操作触发自动保存:');
|
|
294
|
+
loaded_ip.clearWhite();
|
|
295
|
+
|
|
296
|
+
console.log('持久化存储功能测试完成');
|
|
297
|
+
|
|
298
|
+
// 测试14: 删除IP记录功能
|
|
299
|
+
console.log('\n14. 测试删除IP记录功能:');
|
|
300
|
+
|
|
301
|
+
// 准备测试数据
|
|
302
|
+
ip_manager.addBlack('192.168.300.1');
|
|
303
|
+
ip_manager.addWhite('192.168.300.1');
|
|
304
|
+
ip_manager.recordViolation('192.168.300.1', '测试违规');
|
|
305
|
+
|
|
306
|
+
console.log('删除前状态:');
|
|
307
|
+
console.log('192.168.300.1 在黑名单:', ip_manager.isBlack('192.168.300.1'));
|
|
308
|
+
console.log('192.168.300.1 在白名单:', ip_manager.isWhite('192.168.300.1'));
|
|
309
|
+
console.log('192.168.300.1 违规次数:', ip_manager.getViolationCount('192.168.300.1'));
|
|
310
|
+
console.log('192.168.300.1 黑名单过期时间:', ip_manager.getBlackExpireTime('192.168.300.1'));
|
|
311
|
+
|
|
312
|
+
// 删除IP记录
|
|
313
|
+
const delete_result = ip_manager.del('192.168.300.1');
|
|
314
|
+
console.log('删除结果:', delete_result);
|
|
315
|
+
|
|
316
|
+
console.log('删除后状态:');
|
|
317
|
+
console.log('192.168.300.1 在黑名单:', ip_manager.isBlack('192.168.300.1'));
|
|
318
|
+
console.log('192.168.300.1 在白名单:', ip_manager.isWhite('192.168.300.1'));
|
|
319
|
+
console.log('192.168.300.1 违规次数:', ip_manager.getViolationCount('192.168.300.1'));
|
|
320
|
+
console.log('192.168.300.1 黑名单过期时间:', ip_manager.getBlackExpireTime('192.168.300.1'));
|
|
321
|
+
|
|
322
|
+
// 测试删除不存在的IP
|
|
323
|
+
const delete_none_result = ip_manager.del('192.168.999.999');
|
|
324
|
+
console.log('删除不存在IP的结果:', delete_none_result);
|
|
325
|
+
|
|
326
|
+
console.log('\n=== IP管理模块测试结束 ===');
|
|
327
|
+
}, 3000);
|
|
328
|
+
}, 1000);
|
|
329
|
+
|
|
201
330
|
// 测试违规记录过期清理
|
|
202
331
|
console.log('\n测试违规记录过期清理:');
|
|
203
332
|
console.log('等待12秒后检查违规记录过期清理...');
|