diff --git a/backend/package.json b/backend/package.json index 7749351..45c5615 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.14.194", + "version": "2.14.195", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "main": "src/main.js", "scripts": { diff --git a/backend/src/core/proxy-utils/processors/index.js b/backend/src/core/proxy-utils/processors/index.js index 449b101..ed115b7 100644 --- a/backend/src/core/proxy-utils/processors/index.js +++ b/backend/src/core/proxy-utils/processors/index.js @@ -14,6 +14,7 @@ import { getFlowField, getFlowHeaders, parseFlowHeaders, + validCheck, flowTransfer, } from '@/utils/flow'; @@ -806,6 +807,7 @@ function createDynamicFunction(name, script, $arguments) { getFlowHeaders, parseFlowHeaders, flowTransfer, + validCheck, }; if ($.env.isLoon) { return new Function( diff --git a/backend/src/utils/download.js b/backend/src/utils/download.js index 9b59459..f1f7c80 100644 --- a/backend/src/utils/download.js +++ b/backend/src/utils/download.js @@ -4,7 +4,12 @@ import { HTTP, ENV } from '@/vendor/open-api'; import { hex_md5 } from '@/vendor/md5'; import resourceCache from '@/utils/resource-cache'; import headersResourceCache from '@/utils/headers-resource-cache'; -import { getFlowField } from '@/utils/flow'; +import { + getFlowField, + getFlowHeaders, + parseFlowHeaders, + validCheck, +} from '@/utils/flow'; import $ from '@/core/app'; const tasks = new Map(); @@ -64,36 +69,40 @@ export default async function download(rawUrl, ua, timeout) { timeout: requestTimeout, }); - const result = new Promise((resolve, reject) => { - // try to find in app cache - const cached = resourceCache.get(id); - if (!$arguments?.noCache && cached) { - resolve(cached); - } else { - $.info( - `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`, - ); - http.get(url) - .then((resp) => { - const { body, headers } = resp; - if (headers) { - const flowInfo = getFlowField(headers); - if (flowInfo) { - headersResourceCache.set(url, flowInfo); - } - } - if (body.replace(/\s/g, '').length === 0) - reject(new Error('远程资源内容为空!')); - else { - resourceCache.set(id, body); - resolve(body); - } - }) - .catch(() => { - reject(new Error(`无法下载 URL:${url}`)); - }); + let result; + + // try to find in app cache + const cached = resourceCache.get(id); + if (!$arguments?.noCache && cached) { + result = cached; + } else { + $.info( + `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`, + ); + try { + const { body, headers } = await http.get(url); + + if (headers) { + const flowInfo = getFlowField(headers); + if (flowInfo) { + headersResourceCache.set(url, flowInfo); + } + } + if (body.replace(/\s/g, '').length === 0) + throw new Error(new Error('远程资源内容为空')); + + resourceCache.set(id, body); + result = body; + } catch (e) { + throw new Error(`无法下载 URL ${url}: ${e.message ?? e}`); } - }); + } + + // 检查订阅有效性 + + if ($arguments?.validCheck) { + await validCheck(parseFlowHeaders(await getFlowHeaders(url))); + } if (!isNode) { tasks.set(id, result); diff --git a/backend/src/utils/flow.js b/backend/src/utils/flow.js index 6414a38..8c8116a 100644 --- a/backend/src/utils/flow.js +++ b/backend/src/utils/flow.js @@ -120,3 +120,26 @@ export function flowTransfer(flow, unit = 'B') { ? { value: flow.toFixed(1), unit: unit } : flowTransfer(flow / 1024, unitList[++unitIndex]); } + +export function validCheck(flow) { + if (!flow) { + throw new Error('没有流量信息'); + } + if (flow?.expires && flow.expires * 1000 < Date.now()) { + const date = new Date(flow.expires * 1000).toLocaleDateString(); + throw new Error(`订阅已过期: ${date}`); + } + if (flow?.total) { + const upload = flow.usage?.upload || 0; + const download = flow.usage?.download || 0; + if (flow.total - upload - download < 0) { + const current = upload + download; + const currT = flowTransfer(Math.abs(current)); + currT.value = current < 0 ? '-' + currT.value : currT.value; + const totalT = flowTransfer(flow.total); + throw new Error( + `流量已用完: ${currT.value} ${currT.unit} / ${totalT.value} ${totalT.unit}`, + ); + } + } +}