Skip to content

Commit 99d15b9

Browse files
committed
feat: 非 Node 环境默认 cors 增加 substore.stash
1 parent 0f84a60 commit 99d15b9

10 files changed

Lines changed: 31 additions & 17 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ sub.store = 127.0.0.1
5151
Sub-Store also supports a configurable browser CORS allowlist for the backend API. This does not change the module rewrite domain, but it limits which browser origins can read API responses through CORS.
5252

5353
- Node/server deployments use `SUB_STORE_CORS_ALLOWED_ORIGINS`; the default is `*` for compatibility.
54-
- Proxy App modules use the `cors` module argument; the default is `https://sub-store.vercel.app`.
54+
- Proxy App modules use the `cors` module argument; the default is `https://sub-store.vercel.app,http://substore.stash,https://substore.stash`.
5555
- Multiple origins can be separated by commas. Origins are matched exactly by scheme, host, and port. Set the value to `*` only when you accept the risk of any website reading the local backend through browser CORS.
5656

5757
## Core functionalities:

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.24.13",
3+
"version": "2.24.14",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"packageManager": "pnpm@11.0.9",

backend/src/test/config/cors-module-config.spec.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import { describe, it } from 'mocha';
66

77
import { load } from '@/utils/yaml';
88

9-
const DEFAULT_ORIGIN = 'https://sub-store.vercel.app';
9+
const DEFAULT_ORIGINS =
10+
'https://sub-store.vercel.app,http://substore.stash,https://substore.stash';
1011

1112
describe('module CORS allowlist config', function () {
1213
it('adds the default CORS argument to Surge modules', function () {
1314
for (const filename of ['Surge.sgmodule', 'Surge-Beta.sgmodule']) {
1415
const content = readConfig(filename);
1516

16-
expect(content).to.include(`cors:"${DEFAULT_ORIGIN}"`);
17+
expect(content).to.include(`cors:"${DEFAULT_ORIGINS}"`);
1718
expect(content).to.include('argument="cors={{{cors}}}"');
1819
expect(
1920
content.match(/argument="cors=\{\{\{cors\}\}\}"/g),
@@ -27,7 +28,7 @@ describe('module CORS allowlist config', function () {
2728
.map((item) => item.http_request)
2829
.filter(Boolean);
2930

30-
expect(config.compat_arguments.cors).to.equal(DEFAULT_ORIGIN);
31+
expect(config.compat_arguments.cors).to.equal(DEFAULT_ORIGINS);
3132
expect(config.compat_arguments_desc).to.include('1️⃣1️⃣ cors');
3233
expect(httpRequests).to.have.length(2);
3334
for (const script of httpRequests) {

backend/src/test/utils/cors.spec.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,21 @@ describe('CORS allowlist policy', function () {
4747
);
4848
});
4949

50-
it('defaults non-Node environments to the official frontend origin', function () {
50+
it('defaults non-Node environments to bundled frontend origins', function () {
5151
const policy = resolveCorsPolicy({ isNode: false });
5252

5353
expect(policy).to.deep.include({
5454
wildcard: false,
5555
source: 'default:non-node',
5656
value: NON_NODE_CORS_DEFAULT,
5757
});
58-
expect(isOriginAllowed(policy, NON_NODE_CORS_DEFAULT)).to.equal(true);
58+
expect(
59+
isOriginAllowed(policy, 'https://sub-store.vercel.app'),
60+
).to.equal(true);
61+
expect(isOriginAllowed(policy, 'http://substore.stash')).to.equal(true);
62+
expect(isOriginAllowed(policy, 'https://substore.stash')).to.equal(
63+
true,
64+
);
5965
expect(isOriginAllowed(policy, 'https://evil.example')).to.equal(
6066
false,
6167
);
@@ -143,9 +149,15 @@ describe('CORS allowlist policy', function () {
143149
source: 'default:non-node',
144150
value: NON_NODE_CORS_DEFAULT,
145151
});
146-
expect(isOriginAllowed(nonNodePolicy, NON_NODE_CORS_DEFAULT)).to.equal(
152+
expect(
153+
isOriginAllowed(nonNodePolicy, 'https://sub-store.vercel.app'),
154+
).to.equal(true);
155+
expect(isOriginAllowed(nonNodePolicy, 'http://substore.stash')).to.equal(
147156
true,
148157
);
158+
expect(
159+
isOriginAllowed(nonNodePolicy, 'https://substore.stash'),
160+
).to.equal(true);
149161
});
150162

151163
it('returns concrete CORS headers for allowed non-wildcard origins', function () {

backend/src/utils/cors.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
export const NODE_CORS_ALLOWED_ORIGINS_ENV =
44
'SUB_STORE_CORS_ALLOWED_ORIGINS';
55
export const NODE_CORS_DEFAULT = '*';
6-
export const NON_NODE_CORS_DEFAULT = 'https://sub-store.vercel.app';
6+
export const NON_NODE_CORS_DEFAULT =
7+
'https://sub-store.vercel.app,http://substore.stash,https://substore.stash';
78
export const CORS_ARGUMENT_KEY = 'cors';
89

910
const WILDCARD_ORIGIN = '*';

config/Egern.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ compat_arguments:
1212
sync_success_notify: true
1313
produce_sub: "sub1,sub2"
1414
produce_col: "col1,col2"
15-
cors: "https://sub-store.vercel.app"
16-
compat_arguments_desc: '\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 ''同步'' 或 ''同步配置''\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n8️⃣ sync_success_notify\n\n同步配置全部成功时是否发送完成通知\n默认为 true, 填 false/0/no/off 可关闭\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n1️⃣1️⃣ cors\n\n允许浏览器跨域访问 Sub-Store 后端的 origin. 默认为 https://sub-store.vercel.app. 多个用 , 连接. 设为 * 可恢复旧的任意来源访问行为, 存在钓鱼网站读取配置的风险\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅'
15+
cors: "https://sub-store.vercel.app,http://substore.stash,https://substore.stash"
16+
compat_arguments_desc: '\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 ''同步'' 或 ''同步配置''\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n8️⃣ sync_success_notify\n\n同步配置全部成功时是否发送完成通知\n默认为 true, 填 false/0/no/off 可关闭\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n1️⃣1️⃣ cors\n\n允许浏览器跨域访问 Sub-Store 后端的 origin. 默认为 https://sub-store.vercel.app,http://substore.stash,https://substore.stash. 多个用 , 连接. 设为 * 可恢复旧的任意来源访问行为, 存在钓鱼网站读取配置的风险\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅'
1717
scriptings:
1818
- http_request:
1919
name: Sub-Store Core

config/Loon.plugin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
[Argument]
99
cron=input, "55 23 * * *", tag=定时参数, desc=这里需要输入符合CRON表达式的参数
1010
sync_success_notify=switch, true, tag=同步成功通知, desc=同步配置全部成功时是否发送完成通知
11-
cors=input, "https://sub-store.vercel.app", tag=CORS允许来源, desc=允许浏览器跨域访问 Sub-Store 后端的 origin. 多个用 , 连接. 设为 * 可恢复旧行为
11+
cors=input, "https://sub-store.vercel.app,http://substore.stash,https://substore.stash", tag=CORS允许来源, desc=允许浏览器跨域访问 Sub-Store 后端的 origin. 多个用 , 连接. 设为 * 可恢复旧行为
1212

1313
[Rule]
1414
DOMAIN,sub-store.vercel.app,PROXY

config/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Node/服务器/Docker/Android 版可以通过环境变量 `SUB_STORE_CORS_ALLOWE
2222
SUB_STORE_CORS_ALLOWED_ORIGINS=https://sub-store.vercel.app,http://127.0.0.1:8888
2323
```
2424

25-
支持参数配置的 App 模块使用 `cors` 参数设置, 默认值为 `https://sub-store.vercel.app`。如果需要使用本地前端 `http://127.0.0.1:8888?api=http://127.0.0.1:3001/123` 测试代理 App 后端, 需要把模块里的 `cors` 改成 `https://sub-store.vercel.app,http://127.0.0.1:8888`。设为 `*` 可恢复旧的任意来源访问行为, 但任意网站都可能通过浏览器 CORS 读取本机 Sub-Store 后端响应, 不建议长期使用。
25+
支持参数配置的 App 模块使用 `cors` 参数设置, 默认值为 `https://sub-store.vercel.app,http://substore.stash,https://substore.stash`。如果需要使用本地前端 `http://127.0.0.1:8888?api=http://127.0.0.1:3001/123` 测试代理 App 后端, 需要把模块里的 `cors` 改成 `https://sub-store.vercel.app,http://substore.stash,https://substore.stash,http://127.0.0.1:8888`。设为 `*` 可恢复旧的任意来源访问行为, 但任意网站都可能通过浏览器 CORS 读取本机 Sub-Store 后端响应, 不建议长期使用。
2626

2727
### 1. Loon
2828

config/Surge-Beta.sgmodule

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#!name=Sub-Store(β)
22
#!desc=支持 Surge 正式版的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 55 23 * * *
33
#!category=订阅管理
4-
#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync",timeout:120,engine:auto,produce:"# Sub-Store Produce",produce_cronexp:50 */6 * * *,sync_success_notify:true,produce_sub:"sub1,sub2",produce_col:"col1,col2",max_size:-1,cors:"https://sub-store.vercel.app"
5-
#!arguments-desc=\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n8️⃣ sync_success_notify\n\n同步配置全部成功时是否发送完成通知\n默认为 true, 填 false/0/no/off 可关闭\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n1️⃣1️⃣ cors\n\n允许浏览器跨域访问 Sub-Store 后端的 origin. 默认为 https://sub-store.vercel.app. 多个用 , 连接. 设为 * 可恢复旧的任意来源访问行为, 存在钓鱼网站读取配置的风险\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅
4+
#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync",timeout:120,engine:auto,produce:"# Sub-Store Produce",produce_cronexp:50 */6 * * *,sync_success_notify:true,produce_sub:"sub1,sub2",produce_col:"col1,col2",max_size:-1,cors:"https://sub-store.vercel.app,http://substore.stash,https://substore.stash"
5+
#!arguments-desc=\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n8️⃣ sync_success_notify\n\n同步配置全部成功时是否发送完成通知\n默认为 true, 填 false/0/no/off 可关闭\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n1️⃣1️⃣ cors\n\n允许浏览器跨域访问 Sub-Store 后端的 origin. 默认为 https://sub-store.vercel.app,http://substore.stash,https://substore.stash. 多个用 , 连接. 设为 * 可恢复旧的任意来源访问行为, 存在钓鱼网站读取配置的风险\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅
66

77
[MITM]
88
hostname = %APPEND% sub.store

config/Surge.sgmodule

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#!name=Sub-Store
22
#!desc=支持 Surge 正式版的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 55 23 * * *
33
#!category=订阅管理
4-
#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync",timeout:120,engine:auto,produce:"# Sub-Store Produce",produce_cronexp:50 */6 * * *,sync_success_notify:true,produce_sub:"sub1,sub2",produce_col:"col1,col2",max_size:-1,cors:"https://sub-store.vercel.app"
5-
#!arguments-desc=\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n8️⃣ sync_success_notify\n\n同步配置全部成功时是否发送完成通知\n默认为 true, 填 false/0/no/off 可关闭\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n1️⃣1️⃣ cors\n\n允许浏览器跨域访问 Sub-Store 后端的 origin. 默认为 https://sub-store.vercel.app. 多个用 , 连接. 设为 * 可恢复旧的任意来源访问行为, 存在钓鱼网站读取配置的风险\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅
4+
#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync",timeout:120,engine:auto,produce:"# Sub-Store Produce",produce_cronexp:50 */6 * * *,sync_success_notify:true,produce_sub:"sub1,sub2",produce_col:"col1,col2",max_size:-1,cors:"https://sub-store.vercel.app,http://substore.stash,https://substore.stash"
5+
#!arguments-desc=\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n8️⃣ sync_success_notify\n\n同步配置全部成功时是否发送完成通知\n默认为 true, 填 false/0/no/off 可关闭\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n1️⃣1️⃣ cors\n\n允许浏览器跨域访问 Sub-Store 后端的 origin. 默认为 https://sub-store.vercel.app,http://substore.stash,https://substore.stash. 多个用 , 连接. 设为 * 可恢复旧的任意来源访问行为, 存在钓鱼网站读取配置的风险\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅
66

77
[MITM]
88
hostname = %APPEND% sub.store

0 commit comments

Comments
 (0)