block-proxy 0.1.9 → 0.1.10
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/.claude/settings.local.json +11 -0
- package/.claude/skills/commit/skill.md +32 -0
- package/.claude/skills/pcap-analyse/skill.md +100 -0
- package/CLAUDE.md +114 -0
- package/Dockerfile +1 -0
- package/README.md +3 -2
- package/bin/start.js +0 -1
- package/build/index.html +2 -1
- package/build/static/css/main.098e0e65.css +2 -0
- package/build/static/css/main.098e0e65.css.map +1 -0
- package/build/static/js/main.e8a52b27.js +3 -0
- package/build/static/js/main.e8a52b27.js.LICENSE.txt +49 -0
- package/build/static/js/main.e8a52b27.js.map +1 -0
- package/config.json +1 -1
- package/example/rule.js +1 -0
- package/hack-of-anyproxy/lib/requestHandler.js +33 -1
- package/package.json +2 -2
- package/proxy/proxy.js +7 -4
- package/proxy/scan.js +49 -3
- package/server/express.js +1 -0
- package/socks5/test_tls_reuse.js +1 -0
- package/src/setupTests.js +1 -0
- package/tools/speed_test.sh +1 -0
- package/tools/tcpdump/output.pcap +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Skill: Smart Git Commit
|
|
2
|
+
|
|
3
|
+
Use this skill when the user runs `/commit` or asks to commit changes.
|
|
4
|
+
|
|
5
|
+
## Instructions
|
|
6
|
+
|
|
7
|
+
1. **Analyze Context**:
|
|
8
|
+
- Run `git status` to identify modified, added, or deleted files.
|
|
9
|
+
- Run `git diff` to inspect the actual code changes in unstaged files.
|
|
10
|
+
- Run `git diff --cached` to inspect changes in staged files.
|
|
11
|
+
|
|
12
|
+
2. **Stage Changes**:
|
|
13
|
+
- If there are unstaged changes, run `git add -A` to stage all changes (unless the user specifically asked to partial commit).
|
|
14
|
+
|
|
15
|
+
3. **Generate Commit Message**:
|
|
16
|
+
- Analyze the diffs to understand the *intent* of the changes.
|
|
17
|
+
- Draft a commit message following the **Conventional Commits** specification:
|
|
18
|
+
```
|
|
19
|
+
<type>(<scope>): <description>
|
|
20
|
+
|
|
21
|
+
[optional body]
|
|
22
|
+
```
|
|
23
|
+
- **Types**: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`.
|
|
24
|
+
- **Scope**: (Optional) The module or file affected (e.g., `proxy`, `ui`, `deps`).
|
|
25
|
+
- **Description**: Concise summary in imperative mood (e.g., "add support for...", not "added").
|
|
26
|
+
|
|
27
|
+
4. **Execute Commit**:
|
|
28
|
+
- Run `git commit -m "generated_message"`.
|
|
29
|
+
- If the message has a body, use multiple `-m` flags or a heredoc.
|
|
30
|
+
|
|
31
|
+
5. **Report**:
|
|
32
|
+
- Inform the user of the commit message used and the result.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
model: default
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Pcap Analyse Skill
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
分析 pcap/pcapng 网络抓包文件,专注于代理服务器(Socks5 over TLS/HTTP)场景下的连接诊断、性能评估和异常检测。
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
当用户请求分析 pcap 文件,或者提供一个抓包文件并询问网络连接质量、异常或性能问题时使用此 skill。
|
|
12
|
+
|
|
13
|
+
## Instructions
|
|
14
|
+
执行此 skill 时,请遵循以下步骤进行分析。如果用户没有提供 pcap 文件路径,请先询问。
|
|
15
|
+
|
|
16
|
+
**重要**:你不能直接读取二进制 pcap 文件。你必须编写并执行 Python 脚本(推荐使用 `scapy` 库,如果环境没有则尝试使用 `tshark` 命令行工具)来提取信息。
|
|
17
|
+
|
|
18
|
+
### 1. 编写分析脚本
|
|
19
|
+
编写一个 Python 脚本来解析 pcap 文件,脚本需要提取并计算以下指标:
|
|
20
|
+
|
|
21
|
+
#### A. 基础信息与抓包点推断
|
|
22
|
+
- 统计源 IP 和目的 IP 的出现频率。
|
|
23
|
+
- 分析 TCP SYN 包的 TTL (Time To Live) 和 MSS (Max Segment Size)。通常客户端发出的包 TTL 较大(如 64, 128),经过路由后会减少。如果抓到的入站包 TTL 接近默认值(未减少太多),可能是服务端抓包;如果出站包 TTL 是默认值,则是本地发出的。
|
|
24
|
+
- 结合端口号(如 8001, 8002)判断流量方向。
|
|
25
|
+
|
|
26
|
+
#### B. 连接异常分析
|
|
27
|
+
- **重传率 (Retransmission Rate)**: 重传包数 / 总包数。
|
|
28
|
+
- **复位连接 (RST)**: 统计 RST 包的数量及出现阶段(握手期、数据传输期、结束期)。
|
|
29
|
+
- **握手失败**: 有 SYN 但无 SYN/ACK 的比例。
|
|
30
|
+
- **TLS 错误**: 检查是否有 TLS Alert 消息。
|
|
31
|
+
|
|
32
|
+
#### C. 性能分析
|
|
33
|
+
- **TCP 握手延迟 (RTT)**: SYN 到 SYN/ACK 的时间差。
|
|
34
|
+
- **TLS 握手延迟**: Client Hello 到 Handshake Finished 的时间。
|
|
35
|
+
- **数据传输 RTT**: 数据包与对应 ACK 之间的时间差统计(平均值、最大值、最小值、抖动)。
|
|
36
|
+
|
|
37
|
+
#### D. 连接复用情况
|
|
38
|
+
- 统计每个 TCP 流 (Stream) 的持续时间。
|
|
39
|
+
- 统计每个流的数据传输量。
|
|
40
|
+
- 判断长连接 (Keep-Alive) 的使用情况:是否有长时间空闲但未断开的连接,或者单连接承载多次数据交互。
|
|
41
|
+
|
|
42
|
+
#### E. 阻塞与拥塞分析
|
|
43
|
+
- **Zero Window**: 统计 TCP Zero Window 通告次数(接收端缓冲区满,通知发送端暂停发送)。
|
|
44
|
+
- **Window Full**: 统计发送端未收到 ACK 而导致发送窗口耗尽的情况。
|
|
45
|
+
- **吞吐量波动**: 检查是否有明显的吞吐量骤降。
|
|
46
|
+
|
|
47
|
+
#### F. 高并发与吞吐量评估
|
|
48
|
+
- **并发连接数**: 统计每一秒内的活跃 TCP 连接数峰值。
|
|
49
|
+
- **每秒请求数 (RPS)**: 如果是 HTTP,估算请求速率。
|
|
50
|
+
- **峰值带宽**: 计算每秒传输的最大字节数。
|
|
51
|
+
|
|
52
|
+
### 2. 执行分析与报告
|
|
53
|
+
运行脚本获取输出,并生成一份详细的分析报告。报告必须包含以下章节:
|
|
54
|
+
|
|
55
|
+
1. **抓包环境推断**:
|
|
56
|
+
- 结论:是客户端抓包还是代理服务器端抓包?
|
|
57
|
+
- 依据:IP 分布、TTL 特征、端口方向。
|
|
58
|
+
|
|
59
|
+
2. **连接健康度与异常**:
|
|
60
|
+
- 异常连接比例。
|
|
61
|
+
- 具体的错误类型(重传、RST、超时等)及其对用户体验的潜在影响。
|
|
62
|
+
|
|
63
|
+
3. **性能指标**:
|
|
64
|
+
- 平均/P95 延迟数据。
|
|
65
|
+
- 握手耗时分析。
|
|
66
|
+
|
|
67
|
+
4. **连接复用分析**:
|
|
68
|
+
- 连接是否被有效复用(Socks5/HTTP Keep-Alive)。
|
|
69
|
+
- 是否存在频繁新建连接导致的开销。
|
|
70
|
+
|
|
71
|
+
5. **阻塞情况**:
|
|
72
|
+
- 是否发现 Zero Window 或流控阻塞。
|
|
73
|
+
- 是否有队头阻塞迹象。
|
|
74
|
+
|
|
75
|
+
6. **负载能力评估**:
|
|
76
|
+
- 当前并发峰值和吞吐峰值。
|
|
77
|
+
- 基于当前性能指标(如 RTT 抖动、丢包率随流量变化),预估系统在高并发下的抗压能力。
|
|
78
|
+
|
|
79
|
+
### 3. 示例 Python 代码结构 (供参考)
|
|
80
|
+
```python
|
|
81
|
+
from scapy.all import *
|
|
82
|
+
import collections
|
|
83
|
+
|
|
84
|
+
# 读取 pcap
|
|
85
|
+
packets = rdpcap("path/to/file.pcap")
|
|
86
|
+
|
|
87
|
+
# 初始化统计变量
|
|
88
|
+
# ...
|
|
89
|
+
|
|
90
|
+
for pkt in packets:
|
|
91
|
+
if TCP in pkt:
|
|
92
|
+
# 统计逻辑
|
|
93
|
+
# ...
|
|
94
|
+
|
|
95
|
+
# 输出结果
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**注意**: 如果环境不支持 Python scapy,请尝试使用 `tshark` 命令:
|
|
99
|
+
`tshark -r file.pcap -q -z io,stat,1 -z conv,tcp`
|
|
100
|
+
以及 `tshark -r file.pcap -Y "tcp.analysis.flags"` 来分析异常。
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Common Commands
|
|
6
|
+
|
|
7
|
+
### Development
|
|
8
|
+
- `npm run dev` – Start development mode with BLOCK_PROXY_DEV=1 (starts all services)
|
|
9
|
+
- `npm run craco` – Start React development server with CRACO (port 3000)
|
|
10
|
+
- `npm run start` / `npm run express` – Start backend + proxy server for production
|
|
11
|
+
- `npm run proxy` – Start proxy only (no admin interface)
|
|
12
|
+
- `npm run socks5` – Start SOCKS5 server only
|
|
13
|
+
|
|
14
|
+
### Build & Deployment
|
|
15
|
+
- `npm run build` – Build React frontend
|
|
16
|
+
- `npm run docker:build` – Build Docker image for current architecture
|
|
17
|
+
- `npm run docker:build_arm` – Build ARM64 Docker image
|
|
18
|
+
- `npm test` – Run React tests
|
|
19
|
+
- `npm run eject` – Eject from Create React App (irreversible)
|
|
20
|
+
|
|
21
|
+
### Global CLI
|
|
22
|
+
- `block-proxy` – Start the proxy system (auto-restart on failure)
|
|
23
|
+
- `block-proxy -c rule.js` – Start with external MITM rule configuration
|
|
24
|
+
|
|
25
|
+
## Architecture Overview
|
|
26
|
+
|
|
27
|
+
Block-Proxy is a MITM-based proxy filtering tool designed for parental control and ad blocking, built with Node.js, React, and a custom AnyProxy fork. It runs on OpenWRT routers or Docker containers.
|
|
28
|
+
|
|
29
|
+
### Core Components
|
|
30
|
+
|
|
31
|
+
1. **Proxy Engine** (`/proxy/`)
|
|
32
|
+
- `proxy.js` – Main AnyProxy integration with MITM logic
|
|
33
|
+
- `mitm/` – MITM rule implementations (YouTube ads, dictionary, etc.)
|
|
34
|
+
- `scan.js` – Network scanning for device discovery (every 2 hours)
|
|
35
|
+
- `fs.js` – Configuration file management
|
|
36
|
+
|
|
37
|
+
2. **SOCKS5 Proxy** (`/socks5/`)
|
|
38
|
+
- `server.js` – SOCKS5 over TLS implementation (port 8002)
|
|
39
|
+
- `start.js` – SOCKS5 server entry point
|
|
40
|
+
|
|
41
|
+
3. **Backend Server** (`/server/`)
|
|
42
|
+
- `express.js` – Express.js API server for admin interface (port 8004)
|
|
43
|
+
- `start.js` – Main server entry point (decides whether to start admin UI)
|
|
44
|
+
|
|
45
|
+
4. **React Frontend** (`/src/`)
|
|
46
|
+
- `App.js` – Admin interface for managing blocking rules
|
|
47
|
+
- Built with Create React App, configured via CRACO
|
|
48
|
+
|
|
49
|
+
5. **CLI Interface** (`/bin/`)
|
|
50
|
+
- `start.js` – Global CLI entry point with auto-restart capabilities and config cleanup
|
|
51
|
+
|
|
52
|
+
6. **Configuration** (`config.json`)
|
|
53
|
+
- Runtime configuration: ports, blocked hosts, authentication
|
|
54
|
+
- Auto-saved from admin interface
|
|
55
|
+
|
|
56
|
+
### Port Configuration
|
|
57
|
+
- `8001` – HTTP proxy port (mandatory)
|
|
58
|
+
- `8002` – SOCKS5 over TLS port (optional)
|
|
59
|
+
- `8003` – AnyProxy monitoring interface (optional)
|
|
60
|
+
- `8004` – Admin configuration interface (optional)
|
|
61
|
+
- `3000` – React development server (dev only)
|
|
62
|
+
|
|
63
|
+
### Entry Points
|
|
64
|
+
- **Primary**: `bin/start.js` (CLI) → `server/start.js` → decides between proxy-only or full stack
|
|
65
|
+
- **Proxy-only**: `proxy/start.js` → `proxy/proxy.js`
|
|
66
|
+
- **Development**: `npm run dev` → starts everything with dev flag
|
|
67
|
+
|
|
68
|
+
## Key Patterns
|
|
69
|
+
|
|
70
|
+
### MITM Rule System
|
|
71
|
+
- Host-based blocking with regex pattern matching
|
|
72
|
+
- Time-based restrictions (start/end times, weekdays)
|
|
73
|
+
- MAC address targeting for device-specific rules
|
|
74
|
+
- YouTube ad blocking with predefined regex patterns
|
|
75
|
+
- Custom rule injection via external `rule.js` configuration
|
|
76
|
+
|
|
77
|
+
### Configuration Management
|
|
78
|
+
- Configuration stored in `config.json` at runtime
|
|
79
|
+
- Supports external rule files via `-c` flag
|
|
80
|
+
- Network device scanning every 2 hours (stored in `config.json`)
|
|
81
|
+
- Auto-clears global config file on exit/restart
|
|
82
|
+
|
|
83
|
+
### Deployment Patterns
|
|
84
|
+
- Designed for OpenWRT router deployment with host networking (`--network=host`)
|
|
85
|
+
- Docker container with volume mounting for configuration
|
|
86
|
+
- Multi-architecture support (ARM/X86)
|
|
87
|
+
- Auto-restart on failure with config cleanup
|
|
88
|
+
- Production vs. development modes controlled by `BLOCK_PROXY_DEV` env var
|
|
89
|
+
|
|
90
|
+
### Development Workflow
|
|
91
|
+
1. **Development**: `npm run dev` starts proxy + admin UI + SOCKS5 (if enabled)
|
|
92
|
+
2. **Testing**: Proxy-only mode with `npm run proxy`
|
|
93
|
+
3. **Building**: `npm run build` compiles React frontend to `/build/`
|
|
94
|
+
4. **Docker**: Separate commands for x86 and ARM architectures
|
|
95
|
+
|
|
96
|
+
### Dependencies
|
|
97
|
+
- `@bachi/anyproxy` – Modified AnyProxy fork for MITM
|
|
98
|
+
- `express` – Backend API server
|
|
99
|
+
- `react`, `react-dom` – Frontend framework
|
|
100
|
+
- `commander` – CLI argument parsing
|
|
101
|
+
- `axios` – HTTP client for API calls
|
|
102
|
+
- `qrcode` – Certificate QR code generation for MITM setup
|
|
103
|
+
|
|
104
|
+
## Important Notes
|
|
105
|
+
- SOCKS5 proxy does not support MAC address targeting (only HTTP proxy does)
|
|
106
|
+
- Clients must install AnyProxy certificate for HTTPS MITM inspection
|
|
107
|
+
- Service needs network scanning permissions (best deployed on OpenWRT gateway)
|
|
108
|
+
- Admin interface allows real-time rule management with proxy restart
|
|
109
|
+
- Docker builds use Chinese npm registry (registry.npmmirror.com) by default
|
|
110
|
+
|
|
111
|
+
# Project Rules & Skills
|
|
112
|
+
|
|
113
|
+
- **Import Skill**: 实时遵循 `.claude/skills/*/skill.md` 中的指令。
|
|
114
|
+
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
package/bin/start.js
CHANGED
package/build/index.html
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.2247fb80.js"></script><link href="/static/css/main.8bfa3d5f.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.2247fb80.js"></script><link href="/static/css/main.8bfa3d5f.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
|
2
|
+
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.server-info p{margin:5px 0}.ip-list{list-style:none;margin:10px 0;padding:0}.ip-item{border-bottom:1px solid #eee;display:flex;padding:8px 0}.ip-item:last-child{border-bottom:none}.interface-name{color:#555;font-weight:700}.ip-address{background-color:#f8f9fa;border-radius:3px;flex:1 1;font-family:Courier New,monospace;padding:2px 6px}.toast{align-items:center;animation:toastSlideIn .3s ease-out;border-radius:4px;box-shadow:0 4px 12px #00000026;color:#fff;display:flex;font-weight:500;min-width:250px;padding:16px 20px;position:fixed;right:20px;top:20px;z-index:1000}@keyframes toastSlideIn{0%{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}.toast.success{background-color:#28a745;border-left:4px solid #1e7e34}.toast.error{background-color:#dc3545;border-left:4px solid #bd2130}.toast.info{background-color:#17a2b8;border-left:4px solid #117a8b}.toast-close{align-items:center;background:none;border:none;color:#fff;cursor:pointer;display:flex;font-size:20px;font-weight:700;height:20px;justify-content:center;margin-left:15px;padding:0;width:20px}.toast-close:hover{opacity:.7}.App{background-color:#f5f5f5;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;min-height:100vh;padding:20px;text-align:center}.config-container{background:#fff;border-radius:8px;box-shadow:0 2px 10px #0000001a;margin:0 auto;max-width:1220px;padding:30px;position:relative;text-align:left}.config-container h1{color:#333;margin-top:0;text-align:center}.config-section{background-color:#fafafa;border:1px solid #eee;border-radius:5px;margin-bottom:30px;padding:20px}.config-section h2{border-bottom:1px solid #eee;color:#555;margin-top:0;padding-bottom:10px}.host-input{display:flex;flex-direction:row;gap:10px;margin-bottom:15px}.host-input input[type=text]{border:1px solid #ddd;border-radius:4px;flex:1 1;font-size:14px;padding:10px}.host-input button{align-self:flex-start;background-color:#007bff;border:none;border-radius:4px;color:#fff;cursor:pointer;font-size:14px}.host-input button:hover{background-color:#0069d9}.time-inputs{align-items:center;display:flex;gap:10px}.time-inputs label{flex-direction:column;font-size:14px}hr.simple-line{background-color:#e3e3e3;border-width:0;height:1px}input[type=time]{background-color:#fff;border:1px solid #ddd;border-radius:3px;padding:4px}input[type=time]:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff40;outline:none}.host-list{list-style:none;margin:0;padding:0}.host-item{align-items:flex-start;border-bottom:1px solid #eee;display:flex;justify-content:space-between;padding:12px 0}.host-item:last-child{border-bottom:none}.host-info{align-items:center;display:flex;flex-grow:1;font-size:15px}span.host-text{align-self:center;flex-grow:1;font-size:14px}.time-controls{align-items:center;display:flex;gap:8px}.time-controls label{display:flex;flex-direction:column;font-size:12px}.remove-btn{align-self:center;background-color:#dc3545;border:none;border-radius:3px;color:#fff;cursor:pointer;font-size:12px;height:-webkit-fit-content;height:fit-content;margin-left:10px;min-width:23px;padding:5px 7px}.remove-btn:hover{background-color:#c82333}.setting-row{align-items:center;display:flex;gap:15px;margin-bottom:15px}.setting-row label{color:#555;font-weight:700}.setting-row input{flex:1 1}.setting-row input,.setting-row input[type=number]{border:1px solid #ddd;border-radius:4px;padding:8px}.setting-row input[type=number]{font-size:14px}.setting-row input[type=number]:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff40;outline:none}.actions{display:flex;justify-content:space-between}.restart-btn,.save-btn{border:none;border-radius:4px;cursor:pointer;flex:1 1;font-size:16px;font-weight:700;padding:12px 20px}.save-btn{background-color:#28a745;color:#fff}.save-btn:hover:not(:disabled){background-color:#218838}.restart-btn{background-color:#ffc107;color:#212529}.restart-btn:hover:not(:disabled){background-color:#e0a800}.restart-btn:disabled,.save-btn:disabled{background-color:#6c757d;cursor:not-allowed}button{border:none;border-radius:3px;cursor:pointer;padding:8px 12px;transition:background-color .2s}button:hover{opacity:.9}button:disabled{cursor:not-allowed;opacity:.6}.docker-info{color:#007bff;font-size:.9em}.host-ip-info{border-top:1px solid #eee;margin-top:15px;padding-top:10px}.host-ip-list{list-style:none;margin:10px 0;padding:0}.host-ip-item{display:flex;padding:5px 0}.method-name{color:#555;font-weight:700;width:150px}.host-ip-address{background-color:#e9ecef;border-radius:3px;flex:1 1;font-family:Courier New,monospace;padding:2px 6px}.weekday-btn,.weekday-controls{align-items:center;display:flex}.weekday-btn{background-color:#e5e5e5;border-radius:0;color:#515b63;cursor:pointer;font-size:12px;height:24px;justify-content:center;padding:0;width:24px}.weekday-btn:hover{background-color:#e9ecef;border-color:#adb5bd}.weekday-btn.active{background-color:#007bff;color:#fff}.weekday-btn:focus{box-shadow:0 0 0 2px #007bff40;outline:none}.mac-input{align-items:center;display:flex;gap:5px;margin:0 10px}.mac-input label{color:#555;font-size:12px}.mac-input input[type=text]{border:1px solid #ddd;border-radius:3px;font-size:12px;padding:4px;width:106px}.mac-input input[type=text]:focus{border-color:#007bff;box-shadow:0 0 0 2px #007bff40;outline:none}.table-right-blank{min-width:30px}.title-mac-input{font-size:15px;min-width:131px;text-align:center}.title-time-controls{font-size:15px;min-width:183px;text-align:center}.title-weedkey-controls{font-size:15px;min-width:106px}@media (max-width:500px){.config-container{margin:10px;padding:20px}.time-controls{align-items:flex-start;flex-direction:column;gap:5px}.host-item{gap:10px}.remove-btn{align-self:flex-start;margin-left:0;margin-top:10px}.mac-input{margin:5px 0}.mac-input input[type=text]{width:100px}}
|
|
2
|
+
/*# sourceMappingURL=main.098e0e65.css.map*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static/css/main.098e0e65.css","mappings":"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","sources":["index.css","App.css"],"sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n","/* 服务器信息样式 */\n.server-info {\n /*padding: 10px 0;*/\n}\n\n.server-info p {\n margin: 5px 0;\n}\n\n.ip-list {\n list-style: none;\n padding: 0;\n margin: 10px 0;\n}\n\n.ip-item {\n display: flex;\n padding: 8px 0;\n border-bottom: 1px solid #eee;\n}\n\n.ip-item:last-child {\n border-bottom: none;\n}\n\n.interface-name {\n font-weight: bold;\n color: #555;\n}\n\n.ip-address {\n flex: 1;\n font-family: 'Courier New', monospace;\n background-color: #f8f9fa;\n padding: 2px 6px;\n border-radius: 3px;\n}\n\n/* Toast 样式 */\n.toast {\n position: fixed;\n top: 20px;\n right: 20px;\n padding: 16px 20px;\n border-radius: 4px;\n color: white;\n font-weight: 500;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n align-items: center;\n animation: toastSlideIn 0.3s ease-out;\n min-width: 250px;\n}\n\n@keyframes toastSlideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n.toast.success {\n background-color: #28a745;\n border-left: 4px solid #1e7e34;\n}\n\n.toast.error {\n background-color: #dc3545;\n border-left: 4px solid #bd2130;\n}\n\n.toast.info {\n background-color: #17a2b8;\n border-left: 4px solid #117a8b;\n}\n\n.toast-close {\n background: none;\n border: none;\n color: white;\n font-size: 20px;\n font-weight: bold;\n margin-left: 15px;\n cursor: pointer;\n padding: 0;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.toast-close:hover {\n opacity: 0.7;\n}\n\n/* 其他原有样式保持不变 */\n.App {\n text-align: center;\n padding: 20px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n background-color: #f5f5f5;\n min-height: 100vh;\n}\n\n.config-container {\n max-width: 1220px;\n margin: 0 auto;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n padding: 30px;\n text-align: left;\n position: relative;\n}\n\n.config-container h1 {\n text-align: center;\n color: #333;\n margin-top: 0;\n}\n\n.config-section {\n margin-bottom: 30px;\n padding: 20px;\n border: 1px solid #eee;\n border-radius: 5px;\n background-color: #fafafa;\n}\n\n.config-section h2 {\n margin-top: 0;\n color: #555;\n border-bottom: 1px solid #eee;\n padding-bottom: 10px;\n}\n\n.host-input {\n display: flex;\n margin-bottom: 15px;\n gap: 10px;\n flex-direction: row;\n}\n\n.host-input input[type=\"text\"] {\n flex: 1;\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n}\n\n.host-input button {\n background-color: #007bff;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n align-self: flex-start;\n}\n\n.host-input button:hover {\n background-color: #0069d9;\n}\n\n.time-inputs {\n display: flex;\n gap: 10px;\n align-items: center;\n}\n\n.time-inputs label {\n flex-direction: column;\n font-size: 14px;\n}\n\nhr.simple-line {\n height:1px;\n border-width:0px;\n background-color:#e3e3e3\n}\n\n/* 时间控件样式 */\ninput[type=\"time\"] {\n padding: 4px;\n border: 1px solid #ddd;\n border-radius: 3px;\n background-color: white;\n}\n\ninput[type=\"time\"]:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n}\n\n.host-list {\n list-style: none;\n padding: 0;\n margin: 0;\n}\n\n.host-item {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 0px;\n border-bottom: 1px solid #eee;\n}\n\n.host-item:last-child {\n border-bottom: none;\n}\n\n.host-info {\n display: flex;\n flex-grow: 1;\n align-items:center;\n font-size:15px;\n}\n\nspan.host-text {\n font-size: 14px;\n flex-grow: 1;\n align-self: center; /* 垂直居中 */\n}\n\n.time-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.time-controls label {\n display: flex;\n flex-direction: column;\n font-size: 12px;\n}\n\n.remove-btn {\n background-color: #dc3545;\n color: white;\n border: none;\n padding: 5px 7px;\n min-width: 23px;\n cursor: pointer;\n border-radius: 3px;\n font-size: 12px;\n height: fit-content;\n align-self: center;\n margin-left: 10px;\n}\n\n.remove-btn:hover {\n background-color: #c82333;\n}\n\n.setting-row {\n display: flex;\n align-items: center;\n margin-bottom: 15px;\n gap: 15px;\n}\n\n.setting-row label {\n /*width: 120px;*/\n font-weight: bold;\n color: #555;\n}\n\n.setting-row input {\n flex: 1;\n padding: 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n}\n\n.setting-row input[type=\"number\"] {\n padding: 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n}\n\n.setting-row input[type=\"number\"]:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n}\n\n.actions {\n display: flex;\n justify-content: space-between;\n}\n\n.save-btn, .restart-btn {\n flex: 1;\n padding: 12px 20px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 16px;\n font-weight: bold;\n}\n\n.save-btn {\n background-color: #28a745;\n color: white;\n}\n\n.save-btn:hover:not(:disabled) {\n background-color: #218838;\n}\n\n.restart-btn {\n background-color: #ffc107;\n color: #212529;\n}\n\n.restart-btn:hover:not(:disabled) {\n background-color: #e0a800;\n}\n\n.save-btn:disabled, .restart-btn:disabled {\n background-color: #6c757d;\n cursor: not-allowed;\n}\n\nbutton {\n padding: 8px 12px;\n border: none;\n border-radius: 3px;\n cursor: pointer;\n transition: background-color 0.2s;\n}\n\nbutton:hover {\n opacity: 0.9;\n}\n\nbutton:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Docker信息样式 */\n.docker-info {\n color: #007bff;\n font-size: 0.9em;\n}\n\n.host-ip-info {\n margin-top: 15px;\n padding-top: 10px;\n border-top: 1px solid #eee;\n}\n\n.host-ip-list {\n list-style: none;\n padding: 0;\n margin: 10px 0;\n}\n\n.host-ip-item {\n display: flex;\n padding: 5px 0;\n}\n\n.method-name {\n font-weight: bold;\n width: 150px;\n color: #555;\n}\n\n.host-ip-address {\n flex: 1;\n font-family: 'Courier New', monospace;\n background-color: #e9ecef;\n padding: 2px 6px;\n border-radius: 3px;\n}\n\n/* 星期几控件样式 */\n.weekday-controls {\n display: flex;\n /*flex-wrap: wrap;*/\n align-items: center;\n}\n\n.weekday-btn {\n width: 24px;\n height: 24px;\n padding: 0;\n /*border: 1px solid #ddd;*/\n background-color: #e5e5e5;\n color: #515b63;\n font-size: 12px;\n border-radius: 0px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.weekday-btn:hover {\n background-color: #e9ecef;\n border-color: #adb5bd;\n}\n\n.weekday-btn.active {\n background-color: #007bff;\n color: white;\n}\n\n.weekday-btn:focus {\n outline: none;\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n}\n\n/* MAC地址输入框样式 */\n.mac-input {\n display: flex;\n align-items: center;\n margin: 0 10px;\n gap: 5px;\n}\n\n.mac-input label {\n font-size: 12px;\n color: #555;\n}\n\n.mac-input input[type=\"text\"] {\n width: 106px;\n padding: 4px;\n border: 1px solid #ddd;\n border-radius: 3px;\n font-size: 12px;\n}\n\n.mac-input input[type=\"text\"]:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n}\n\n.table-right-blank {\n min-width:30px;\n}\n\n.title-mac-input {\n font-size:15px;\n text-align:center;\n min-width:131px;\n}\n.title-time-controls {\n font-size:15px;\n text-align:center;\n min-width:183px;\n}\n.title-weedkey-controls {\n font-size:15px;\n min-width:106px;\n}\n\n/* 响应式设计 */\n@media (max-width: 500px) {\n .config-container {\n margin: 10px;\n padding: 20px;\n }\n \n .time-controls {\n flex-direction: column;\n align-items: flex-start;\n gap: 5px;\n }\n\n .host-item {\n gap: 10px;\n }\n \n .remove-btn {\n align-self: flex-start;\n margin-left: 0;\n margin-top: 10px;\n }\n\n .mac-input {\n margin: 5px 0;\n }\n \n .mac-input input[type=\"text\"] {\n width: 100px;\n }\n}\n\n"],"names":[],"sourceRoot":""}
|