Skip to content

Commit 6653f76

Browse files
authoredSep 27, 2024··
feature: windows的系统代理排除列表中,排除掉中国域名白名单,并提供自动更新中国域名白名单的功能 (#366)
·
v2.0.0.2v1.8.6
1 parent 1af4bfe commit 6653f76

File tree

6 files changed

+1387
-4
lines changed

6 files changed

+1387
-4
lines changed
 

‎packages/core/src/modules/proxy/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ module.exports = {
5656
other: [],
5757
proxyHttp: false, // false=只代理HTTPS请求 true=同时代理HTTP和HTTPS请求
5858
setEnv: false,
59+
60+
// 排除中国域名 所需配置
61+
excludeChinaDomainAllowList: true, // 是否排除中国域名,默认:需要排除
62+
autoUpdateChinaDomainAllowList: true, // 是否自动更新中国域名
63+
remoteChinaDomainAllowListFileUrl: 'https://raw.githubusercontent.com/pluwen/china-domain-allowlist/refs/heads/main/allow-list.sorl',
64+
chinaDomainAllowListFileAbsolutePath: null, // 自定义 china-domain-allowlist.txt 文件位置,可以是本地文件路径
65+
chinaDomainAllowListFilePath: './extra/proxy/china-domain-allowlist.txt', // 内置中国域名文件
66+
67+
// 自定义系统代理排除列表
5968
excludeIpList: {
6069
// region 常用国内可访问域名
6170

‎packages/core/src/shell/scripts/set-system-proxy/index.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const execute = Shell.execute
88
const execFile = Shell.execFile
99
const log = require('../../../utils/util.log')
1010
const extraPath = require('../extra-path/index')
11+
const fs = require('fs')
12+
const path = require('path')
13+
const request = require('request')
1114

1215
let config = null
1316
function loadConfig () {
@@ -47,6 +50,137 @@ async function _winUnsetProxy (exec, setEnv) {
4750
}
4851
}
4952

53+
function getChinaDomainAllowListTmpFilePath () {
54+
return path.join(config.get().server.setting.userBasePath, '/china-domain-allowlist.txt')
55+
}
56+
57+
async function downloadChinaDomainAllowListAsync () {
58+
loadConfig()
59+
60+
const remoteFileUrl = config.get().proxy.remoteChinaDomainAllowListFileUrl
61+
log.info('开始下载远程 china-domain-allowlist.txt 文件:', remoteFileUrl)
62+
request(remoteFileUrl, (error, response, body) => {
63+
if (error) {
64+
log.error('下载远程 china-domain-allowlist.txt 文件失败, error:', error, ', response:', response, ', body:', body)
65+
return
66+
}
67+
if (response && response.statusCode === 200) {
68+
if (body == null || body.length < 100) {
69+
log.warn('下载远程 china-domain-allowlist.txt 文件成功,但内容为空或内容太短,判断为无效的 china-domain-allowlist.txt 文件:', remoteFileUrl, ', body:', body)
70+
return
71+
} else {
72+
log.info('下载远程 china-domain-allowlist.txt 文件成功:', remoteFileUrl)
73+
}
74+
75+
let fileTxt = body
76+
try {
77+
if (fileTxt.indexOf('*.') < 0) {
78+
fileTxt = Buffer.from(fileTxt, 'base64').toString('utf8')
79+
// log.debug('解析 base64 后的 china-domain-allowlist:', fileTxt)
80+
}
81+
} catch (e) {
82+
if (fileTxt.indexOf('*.') < 0) {
83+
log.error(`远程 china-domain-allowlist.txt 文件内容即不是base64格式,也不是要求的格式,url: ${remoteFileUrl},body: ${body}`)
84+
return
85+
}
86+
}
87+
88+
// 保存到本地
89+
saveChinaDomainAllowListFile(fileTxt)
90+
} else {
91+
log.error('下载远程 china-domain-allowlist.txt 文件失败, response:', response, ', body:', body)
92+
}
93+
})
94+
}
95+
96+
function loadLastModifiedTimeFromTxt (fileTxt) {
97+
const matched = fileTxt.match(/(?<=; Update Date: )[^\r\n]+/g)
98+
if (matched && matched.length > 0) {
99+
try {
100+
return new Date(matched[0])
101+
} catch (ignore) {
102+
return null
103+
}
104+
}
105+
}
106+
107+
// 保存 中国域名白名单 内容到 `~/china-domain-allowlist.txt.txt` 文件中
108+
function saveChinaDomainAllowListFile (fileTxt) {
109+
const filePath = getChinaDomainAllowListTmpFilePath()
110+
fs.writeFileSync(filePath, fileTxt.replaceAll(/\r\n?/g, '\n'))
111+
log.info('保存 china-domain-allowlist.txt 文件成功:', filePath)
112+
113+
// 尝试解析和修改 china-domain-allowlist.txt 文件时间
114+
const lastModifiedTime = loadLastModifiedTimeFromTxt(fileTxt)
115+
if (lastModifiedTime) {
116+
fs.stat(filePath, (err, stats) => {
117+
if (err) {
118+
log.error('修改 china-domain-allowlist.txt 文件时间失败:', err)
119+
return
120+
}
121+
122+
// 修改文件的访问时间和修改时间为当前时间
123+
fs.utimes(filePath, lastModifiedTime, lastModifiedTime, (utimesErr) => {
124+
if (utimesErr) {
125+
log.error('修改 china-domain-allowlist.txt 文件时间失败:', utimesErr)
126+
} else {
127+
log.info(`'${filePath}' 文件的修改时间已更新为其最近更新时间 '${formatDate(lastModifiedTime)}'`)
128+
}
129+
})
130+
})
131+
}
132+
133+
return filePath
134+
}
135+
136+
function formatDate (date) {
137+
const year = date.getFullYear()
138+
const month = (date.getMonth() + 1).toString().padStart(2, '0')
139+
const day = date.getDate().toString().padStart(2, '0')
140+
const hours = date.getHours().toString().padStart(2, '0')
141+
const minutes = date.getMinutes().toString().padStart(2, '0')
142+
const seconds = date.getSeconds().toString().padStart(2, '0')
143+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
144+
}
145+
146+
function getChinaDomainAllowList () {
147+
loadConfig()
148+
149+
if (!config.get().proxy.excludeChinaDomainAllowList) {
150+
return null
151+
}
152+
153+
// 判断是否需要自动更新中国域名
154+
let fileAbsolutePath = config.get().proxy.chinaDomainAllowListFileAbsolutePath
155+
if (!fileAbsolutePath && config.get().proxy.autoUpdateChinaDomainAllowList) {
156+
// 异步下载,下载成功后,下次系统代理生效
157+
downloadChinaDomainAllowListAsync().then()
158+
}
159+
160+
// 加载本地文件
161+
if (!fileAbsolutePath) {
162+
const tmpFilePath = getChinaDomainAllowListTmpFilePath()
163+
if (fs.existsSync(tmpFilePath)) {
164+
// 如果临时文件已存在,则使用临时文件
165+
fileAbsolutePath = tmpFilePath
166+
log.info('读取已下载的 china-domain-allowlist.txt 文件:', fileAbsolutePath)
167+
} else {
168+
// 如果临时文件不存在,则使用内置文件
169+
fileAbsolutePath = path.join(__dirname, '../../gui/', config.get().proxy.chinaDomainAllowListFilePath)
170+
log.info('读取内置的 china-domain-allowlist.txt 文件:', fileAbsolutePath)
171+
}
172+
} else {
173+
log.info('读取自定义路径的 china-domain-allowlist.txt 文件:', fileAbsolutePath)
174+
}
175+
176+
try {
177+
return fs.readFileSync(fileAbsolutePath).toString()
178+
} catch (e) {
179+
log.error('读取 china-domain-allowlist.txt 文件失败:', fileAbsolutePath)
180+
return null
181+
}
182+
}
183+
50184
async function _winSetProxy (exec, ip, port, setEnv) {
51185
// 延迟加载config
52186
loadConfig()
@@ -58,6 +192,24 @@ async function _winSetProxy (exec, ip, port, setEnv) {
58192
}
59193
}
60194

195+
// 排除中国域名
196+
if (config.get().proxy.excludeChinaDomainAllowList) {
197+
try {
198+
let chinaDomainAllowList = getChinaDomainAllowList()
199+
if (chinaDomainAllowList) {
200+
chinaDomainAllowList = (chinaDomainAllowList + '\n').replaceAll(/[\r\n]+/g, '\n').replaceAll(/[^\n]*[^*.a-zA-Z\d-\n]+[^\n]*\r?\n/g, '').replaceAll(/\s*\n+\s*/g, ';')
201+
if (chinaDomainAllowList) {
202+
excludeIpStr += chinaDomainAllowList
203+
log.info('系统代理排除列表拼接中国域名')
204+
} else {
205+
log.info('中国域名为空,不进行系统代理排除列表拼接中国域名')
206+
}
207+
}
208+
} catch (e) {
209+
log.error('系统代理排除列表拼接中国域名失败:', e)
210+
}
211+
}
212+
61213
const proxyPath = extraPath.getProxyExePath()
62214
const execFun = 'global'
63215

0 commit comments

Comments
 (0)
Please sign in to comment.