block-proxy 0.1.10 → 0.1.11

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.
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(git commit:*)",
5
4
  "Bash(git add:*)",
6
- "Bash(tshark:*)",
7
- "Bash(python3:*)",
8
- "Bash(gh issue create:*)"
5
+ "Bash(git commit:*)"
9
6
  ]
10
7
  }
11
8
  }
package/build/index.html CHANGED
@@ -1,2 +1 @@
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
-
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>
package/config.json CHANGED
@@ -135,8 +135,8 @@
135
135
  "web_interface_port": 8003,
136
136
  "your_domain": "yui.cool",
137
137
  "vpn_proxy": "",
138
- "auth_username": "lijing",
139
- "auth_password": "lijing",
138
+ "auth_username": "",
139
+ "auth_password": "",
140
140
  "enable_express": "1",
141
141
  "enable_socks5": "1",
142
142
  "socks5_port": 8002,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "block-proxy",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Small-scale network mitm proxy filter",
5
5
  "bin": {
6
6
  "block-proxy": "bin/start.js"
@@ -17,13 +17,14 @@
17
17
  },
18
18
  "scripts": {
19
19
  "cp": "echo '----- program start -----'",
20
+ "rm_bkconfig": "rm ./config_backup.json",
20
21
  "craco": "craco start",
21
22
  "dev": "BLOCK_PROXY_DEV=1 npm run express",
22
23
  "start": "npm run express",
23
24
  "socks5": "node ./socks5/start.js",
24
25
  "express": "npm run cp && node ./server/start.js",
25
26
  "proxy": "npm run cp && node ./proxy/start.js",
26
- "build": "react-scripts build",
27
+ "build": "npm run rm_bkconfig && react-scripts build",
27
28
  "docker:build": "npm run build && docker build -t block-proxy .",
28
29
  "docker:build_arm": "npm run build && docker buildx build --platform linux/arm64/v8 -t block-proxy .",
29
30
  "test": "react-scripts test",
package/proxy/fs.js CHANGED
@@ -4,6 +4,7 @@ const path = require('path');
4
4
 
5
5
  const configPath = path.join(__dirname, '../config.json');
6
6
  const CONFIG_FILE_PATH = configPath;
7
+ const BACKUP_FILE_PATH = path.join(__dirname, '../config_backup.json');
7
8
 
8
9
  // 传入的是对象
9
10
  async function writeConfig(newData) {
@@ -16,20 +17,45 @@ async function writeConfig(newData) {
16
17
  }
17
18
  }
18
19
 
20
+ async function backupConfig(newData) {
21
+ try {
22
+ await fs.writeFile(BACKUP_FILE_PATH, JSON.stringify(newData, null, 2), 'utf8');
23
+ } catch (error) {
24
+ console.error('Error writing backup config file:', error.message);
25
+ }
26
+ }
27
+
19
28
  // 示例:读取配置
20
29
  // 返回的是对象
21
30
  async function readConfig() {
22
31
  try {
23
32
  const data = await fs.readFile(CONFIG_FILE_PATH, 'utf8');
24
33
  const config = JSON.parse(data);
34
+
35
+ // 第一次运行:如果备份不存在,则生成一个
36
+ try {
37
+ await fs.access(BACKUP_FILE_PATH);
38
+ } catch (e) {
39
+ await backupConfig(config);
40
+ }
41
+
25
42
  return config;
26
43
  } catch (error) {
27
44
  if (error.code === 'ENOENT') {
28
45
  console.error('Config file does not exist.');
29
46
  return {}; // 或返回一个默认配置对象
30
47
  } else if (error instanceof SyntaxError) {
31
- console.error('Error parsing config file JSON:', error.message);
32
- throw error;
48
+ console.error('Error parsing config file JSON, attempting to restore from backup:', error.message);
49
+ try {
50
+ const backupData = await fs.readFile(BACKUP_FILE_PATH, 'utf8');
51
+ const config = JSON.parse(backupData);
52
+ // 自动恢复主配置文件
53
+ await writeConfig(config);
54
+ return config;
55
+ } catch (backupError) {
56
+ console.error('Backup file also failed:', backupError.message);
57
+ throw error;
58
+ }
33
59
  } else {
34
60
  console.error('Error reading config file:', error.message);
35
61
  throw error;
@@ -63,6 +89,7 @@ async function clearGlobalConfigFile() {
63
89
  module.exports = {
64
90
  writeConfig,
65
91
  readConfig,
92
+ backupConfig,
66
93
  setGlobalConfigFile,
67
94
  getGlobalConfigFile,
68
95
  clearGlobalConfigFile
package/server/express.js CHANGED
@@ -96,6 +96,7 @@ app.post('/api/config', async (req, res) => {
96
96
  const configPath = path.join(__dirname, '../config.json');
97
97
  // fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2));
98
98
  _fs.writeConfig(newConfig);
99
+ _fs.backupConfig(newConfig);
99
100
  res.status(200).json({ message: 'Config updated successfully' });
100
101
  } catch (err) {
101
102
  res.status(400).json({ error: 'Invalid JSON or write error: ' + err.message });
@@ -1,2 +0,0 @@
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*/
@@ -1 +0,0 @@
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":""}