@dsh-plus/access-gate 0.3.12 → 0.3.13
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/lib/client.js +3 -3
- package/lib/index.d.ts +19 -15
- package/lib/index.js +7 -17
- package/package.json +12 -12
- package/src/client/card.tsx +2 -2
- package/src/client/client.ts +1 -1
- package/src/config.ts +16 -5
- package/src/index.ts +8 -15
package/lib/client.js
CHANGED
|
@@ -42,7 +42,7 @@ window.__ModuleLoader__.load({
|
|
|
42
42
|
className: `${p}-pending`,
|
|
43
43
|
children: props.dirtyLabel
|
|
44
44
|
}) : null,
|
|
45
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
45
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}` })
|
|
46
46
|
]
|
|
47
47
|
}), props.open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48
48
|
className: `${p}-body`,
|
|
@@ -379,8 +379,8 @@ ${extra}
|
|
|
379
379
|
* 与 0.1.6-alpha.2 插件页 plugins.row.config / plugins.bundle.config,view 分发 summary/page)。
|
|
380
380
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
381
381
|
* 本文件保留业务字段(白名单 textarea/诊断面板)与保存逻辑。
|
|
382
|
-
*
|
|
383
|
-
*
|
|
382
|
+
* 配置读写经共享层 ctx.remote.settings 直连(0.1.7 起 settingsScope 已由
|
|
383
|
+
* configForms 取代):value 为 schema 解析后的视图,保存经 settings.update 深合并。
|
|
384
384
|
* 卡片顶部「当前页面诊断」读 /dsh-plus/gate/status(本页放行原因/客户端 IP/
|
|
385
385
|
* 官方 cookie 状态)。
|
|
386
386
|
*
|
package/lib/index.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
2
|
+
import { UnwrapVolatile } from "@dsh-plus/shared";
|
|
2
3
|
import z from "@deepseek-ai/schemastery";
|
|
3
4
|
//#region src/config.d.ts
|
|
4
|
-
declare const Config: z<Schemastery.ObjectS<{
|
|
5
|
-
enabled: z<boolean, boolean>;
|
|
6
|
-
allowedIps: z<string[]
|
|
7
|
-
trustForwardedFor: z<boolean, boolean>;
|
|
8
|
-
autoLoginTrustedIps: z<boolean, boolean>;
|
|
9
|
-
}
|
|
10
|
-
enabled: z<boolean, boolean>;
|
|
11
|
-
allowedIps: z<string[]
|
|
12
|
-
trustForwardedFor: z<boolean, boolean>;
|
|
13
|
-
autoLoginTrustedIps: z<boolean, boolean>;
|
|
14
|
-
}
|
|
15
|
-
|
|
5
|
+
declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
6
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
7
|
+
allowedIps: z<NoInfer<string[]>, NoInfer<string[]>, "volatile-defined">;
|
|
8
|
+
trustForwardedFor: z<boolean, boolean, "volatile-defined">;
|
|
9
|
+
autoLoginTrustedIps: z<boolean, boolean, "volatile-defined">;
|
|
10
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
11
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
12
|
+
allowedIps: z<NoInfer<string[]>, NoInfer<string[]>, "volatile-defined">;
|
|
13
|
+
trustForwardedFor: z<boolean, boolean, "volatile-defined">;
|
|
14
|
+
autoLoginTrustedIps: z<boolean, boolean, "volatile-defined">;
|
|
15
|
+
}>>, "plain">;
|
|
16
|
+
/** 活动字段形态(0.1.7 loader 解析产物:volatile 字段为活动引用)。 */
|
|
17
|
+
type AccessGateConfigFields = Schemastery.TypeT<typeof Config>;
|
|
18
|
+
/** 平面配置形态(服务与判定面的消费形态,由活动引用解包得到)。 */
|
|
19
|
+
type AccessGateConfig = UnwrapVolatile<AccessGateConfigFields>;
|
|
16
20
|
//#endregion
|
|
17
21
|
//#region src/index.d.ts
|
|
18
22
|
declare const name = "dsh-plus-access-gate";
|
|
@@ -22,12 +26,12 @@ declare module '@deepseek-ai/cordis' {
|
|
|
22
26
|
accessGate: AccessGateService;
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
|
-
/** 围栏服务:持有当前配置读取器(
|
|
29
|
+
/** 围栏服务:持有当前配置读取器(0.1.7 起为 volatile 活动引用的平面解包,读即最新)。 */
|
|
26
30
|
declare class AccessGateService extends Service {
|
|
27
31
|
private current;
|
|
28
32
|
/** 官方 browser-auth 签名密钥(惰性读取缓存;读取失败 = null,autoLogin fail-safe 降级)。 */
|
|
29
33
|
private signingSecret;
|
|
30
|
-
constructor(ctx: Context, config: AccessGateConfig);
|
|
34
|
+
constructor(ctx: Context, config: AccessGateConfig | AccessGateConfigFields);
|
|
31
35
|
/** 当前生效配置(诊断用)。 */
|
|
32
36
|
policy(): AccessGateConfig;
|
|
33
37
|
/** 官方签名密钥(惰性缓存;失败返回 null 并记录,autoLogin 降级 fail-safe)。 */
|
|
@@ -37,6 +41,6 @@ declare class AccessGateService extends Service {
|
|
|
37
41
|
warn(message: string): void;
|
|
38
42
|
}): boolean;
|
|
39
43
|
}
|
|
40
|
-
declare function apply(ctx: Context, config: AccessGateConfig): void;
|
|
44
|
+
declare function apply(ctx: Context, config: AccessGateConfig | AccessGateConfigFields): void;
|
|
41
45
|
//#endregion
|
|
42
46
|
export { AccessGateService, Config, apply, inject, name };
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Service } from "@deepseek-ai/cordis";
|
|
2
2
|
import { dshHomePath } from "@deepseek-ai/dsh-home-paths";
|
|
3
|
+
import { unwrapVolatile } from "@dsh-plus/shared";
|
|
3
4
|
import z from "@deepseek-ai/schemastery";
|
|
4
5
|
import { createHash, createHmac } from "node:crypto";
|
|
5
6
|
import { readFileSync } from "node:fs";
|
|
6
7
|
import { join } from "node:path";
|
|
7
|
-
//#endregion
|
|
8
8
|
//#region src/config.ts
|
|
9
9
|
/**
|
|
10
10
|
* 配置单一事实源:cordis 行级 Config(组合默认值,dev/prod patch 层可覆盖)
|
|
@@ -18,13 +18,11 @@ import { join } from "node:path";
|
|
|
18
18
|
* schemastery 透传忽略,不阻断加载(已实测验证)。
|
|
19
19
|
* @module access-gate/config
|
|
20
20
|
*/
|
|
21
|
-
/** settings 命名空间(字面量即合法命名空间,0.1.2-alpha.2 起编译期校验;webui 配置卡片与插件运行期读取同一份)。 */
|
|
22
|
-
const SETTINGS_NS = "dsh-plus-access-gate";
|
|
23
21
|
const Config = z.object({
|
|
24
|
-
enabled: z.boolean().description("访问围栏总开关(false = 一切放行,等价插件缺席)").default(false),
|
|
25
|
-
allowedIps: z.array(z.string()).description("附加 IP 围栏:非空时仅白名单条目(精确 IP 或 CIDR,IPv4/IPv6 皆可)可通行与登录;空 = 不限制来源 IP(仅官方登录保护)").default([]),
|
|
26
|
-
trustForwardedFor: z.boolean().description("是否信任 x-forwarded-for 还原真实客户端 IP(仅当入口代理强制覆盖该头时开启;tailscale serve 满足)").default(true),
|
|
27
|
-
autoLoginTrustedIps: z.boolean().description("IP 信任自动登录:来源命中 allowedIps 白名单且未认证时,服务端自动签发官方登录 cookie(免启动 token,仅对白名单来源生效);默认关闭,需显式开启").default(false)
|
|
22
|
+
enabled: z.boolean().description("访问围栏总开关(false = 一切放行,等价插件缺席)").default(false).volatile(),
|
|
23
|
+
allowedIps: z.array(z.string()).description("附加 IP 围栏:非空时仅白名单条目(精确 IP 或 CIDR,IPv4/IPv6 皆可)可通行与登录;空 = 不限制来源 IP(仅官方登录保护)").default([]).volatile(),
|
|
24
|
+
trustForwardedFor: z.boolean().description("是否信任 x-forwarded-for 还原真实客户端 IP(仅当入口代理强制覆盖该头时开启;tailscale serve 满足)").default(true).volatile(),
|
|
25
|
+
autoLoginTrustedIps: z.boolean().description("IP 信任自动登录:来源命中 allowedIps 白名单且未认证时,服务端自动签发官方登录 cookie(免启动 token,仅对白名单来源生效);默认关闭,需显式开启").default(false).volatile()
|
|
28
26
|
});
|
|
29
27
|
//#endregion
|
|
30
28
|
//#region src/cookie.ts
|
|
@@ -741,22 +739,14 @@ function assertGateStructure(server) {
|
|
|
741
739
|
//#region src/index.ts
|
|
742
740
|
const name = "dsh-plus-access-gate";
|
|
743
741
|
const inject = ["webServer", "connection"];
|
|
744
|
-
/** 围栏服务:持有当前配置读取器(
|
|
742
|
+
/** 围栏服务:持有当前配置读取器(0.1.7 起为 volatile 活动引用的平面解包,读即最新)。 */
|
|
745
743
|
var AccessGateService = class extends Service {
|
|
746
744
|
current;
|
|
747
745
|
/** 官方 browser-auth 签名密钥(惰性读取缓存;读取失败 = null,autoLogin fail-safe 降级)。 */
|
|
748
746
|
signingSecret;
|
|
749
747
|
constructor(ctx, config) {
|
|
750
748
|
super(ctx, "accessGate");
|
|
751
|
-
this.current = () => config;
|
|
752
|
-
ctx.inject(["settings"], (settingsCtx) => {
|
|
753
|
-
settingsCtx.settings.installSection(ctx, SETTINGS_NS, Config, config, {
|
|
754
|
-
setSource: (source) => {
|
|
755
|
-
this.current = source;
|
|
756
|
-
},
|
|
757
|
-
onChange: () => {}
|
|
758
|
-
});
|
|
759
|
-
});
|
|
749
|
+
this.current = () => unwrapVolatile(config);
|
|
760
750
|
const logger = ctx.logger("access-gate");
|
|
761
751
|
const officialAuth = (req) => ctx.connection.requestRejection({ headers: req.headers }) === void 0;
|
|
762
752
|
const secretOf = () => this.readSigningSecret(logger);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plus/access-gate",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.13",
|
|
4
4
|
"description": "dsh-plus service+ui plugin: dsh web 全量访问围栏——与官方 browser-auth 合并:官方 cookie 为唯一凭据,可选 IP 附加围栏,未认证导航渲染 token 输入页(PWA 可恢复),loopback 管理通道",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -31,21 +31,21 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@dsh-plus/shared": "0.1.
|
|
34
|
+
"@dsh-plus/shared": "0.1.22"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
38
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
39
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
40
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
37
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
38
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.7-alpha.2",
|
|
39
|
+
"@deepseek-ai/dsh-settings": "^0.1.7-alpha.2",
|
|
40
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@deepseek-ai/cordis": "4.0.
|
|
44
|
-
"@deepseek-ai/dsh-client-connection": "0.1.
|
|
45
|
-
"@deepseek-ai/dsh-home-paths": "0.1.
|
|
46
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.
|
|
47
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
48
|
-
"@deepseek-ai/schemastery": "3.18.
|
|
43
|
+
"@deepseek-ai/cordis": "4.0.4",
|
|
44
|
+
"@deepseek-ai/dsh-client-connection": "0.1.7-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-home-paths": "0.1.7-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.7-alpha.2",
|
|
47
|
+
"@deepseek-ai/dsh-settings": "0.1.7-alpha.2",
|
|
48
|
+
"@deepseek-ai/schemastery": "3.18.4",
|
|
49
49
|
"@types/react": "~18.3.31",
|
|
50
50
|
"react": "^18.2.0"
|
|
51
51
|
},
|
package/src/client/card.tsx
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* 与 0.1.6-alpha.2 插件页 plugins.row.config / plugins.bundle.config,view 分发 summary/page)。
|
|
4
4
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
5
5
|
* 本文件保留业务字段(白名单 textarea/诊断面板)与保存逻辑。
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* 配置读写经共享层 ctx.remote.settings 直连(0.1.7 起 settingsScope 已由
|
|
7
|
+
* configForms 取代):value 为 schema 解析后的视图,保存经 settings.update 深合并。
|
|
8
8
|
* 卡片顶部「当前页面诊断」读 /dsh-plus/gate/status(本页放行原因/客户端 IP/
|
|
9
9
|
* 官方 cookie 状态)。
|
|
10
10
|
*
|
package/src/client/client.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 类型说明:浏览器半只用到 slots/locale/remote 的很窄一面,
|
|
9
9
|
* scope 与基础控件走 @dsh-plus/shared/client 套件(收编自本插件原实现)。
|
|
10
10
|
* 配置读写经 ctx.remote.settings 直连(0.1.2-alpha.1 起 connection.api.settings
|
|
11
|
-
*
|
|
11
|
+
* 已移除;0.1.7 起 settingsScope 服务亦删除——configForms 取代,自始直连)。
|
|
12
12
|
* 卡片 key/rowId 约定见 @dsh-plus/shared/client/config-slots。
|
|
13
13
|
* @module @dsh-plus/access-gate/client
|
|
14
14
|
*/
|
package/src/config.ts
CHANGED
|
@@ -11,38 +11,49 @@
|
|
|
11
11
|
* @module access-gate/config
|
|
12
12
|
*/
|
|
13
13
|
import z from '@deepseek-ai/schemastery'
|
|
14
|
+
import type { UnwrapVolatile } from '@dsh-plus/shared'
|
|
14
15
|
|
|
15
16
|
import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
|
|
16
17
|
|
|
17
18
|
/** settings 命名空间(字面量即合法命名空间,0.1.2-alpha.2 起编译期校验;webui 配置卡片与插件运行期读取同一份)。 */
|
|
18
19
|
export const SETTINGS_NS = NS_LITERAL
|
|
19
20
|
|
|
21
|
+
// 0.1.7:全部字段 `.volatile()`——loader 解析为活动引用(用户层 override 并入
|
|
22
|
+
// 行级 config,GUI 写入原位提交热生效),同时使本条目进入 settings describe
|
|
23
|
+
// 视图(配置卡片可读写);缺 volatile 标记的条目会被 describe 跳过。
|
|
20
24
|
export const Config = z.object({
|
|
21
25
|
enabled: z
|
|
22
26
|
.boolean()
|
|
23
27
|
.description('访问围栏总开关(false = 一切放行,等价插件缺席)')
|
|
24
|
-
.default(false)
|
|
28
|
+
.default(false)
|
|
29
|
+
.volatile(),
|
|
25
30
|
allowedIps: z
|
|
26
31
|
.array(z.string())
|
|
27
32
|
.description(
|
|
28
33
|
'附加 IP 围栏:非空时仅白名单条目(精确 IP 或 CIDR,IPv4/IPv6 皆可)可通行与登录;空 = 不限制来源 IP(仅官方登录保护)',
|
|
29
34
|
)
|
|
30
|
-
.default([])
|
|
35
|
+
.default([])
|
|
36
|
+
.volatile(),
|
|
31
37
|
trustForwardedFor: z
|
|
32
38
|
.boolean()
|
|
33
39
|
.description(
|
|
34
40
|
'是否信任 x-forwarded-for 还原真实客户端 IP(仅当入口代理强制覆盖该头时开启;tailscale serve 满足)',
|
|
35
41
|
)
|
|
36
|
-
.default(true)
|
|
42
|
+
.default(true)
|
|
43
|
+
.volatile(),
|
|
37
44
|
autoLoginTrustedIps: z
|
|
38
45
|
.boolean()
|
|
39
46
|
.description(
|
|
40
47
|
'IP 信任自动登录:来源命中 allowedIps 白名单且未认证时,服务端自动签发官方登录 cookie(免启动 token,仅对白名单来源生效);默认关闭,需显式开启',
|
|
41
48
|
)
|
|
42
|
-
.default(false)
|
|
49
|
+
.default(false)
|
|
50
|
+
.volatile(),
|
|
43
51
|
})
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
/** 活动字段形态(0.1.7 loader 解析产物:volatile 字段为活动引用)。 */
|
|
54
|
+
export type AccessGateConfigFields = Schemastery.TypeT<typeof Config>
|
|
55
|
+
/** 平面配置形态(服务与判定面的消费形态,由活动引用解包得到)。 */
|
|
56
|
+
export type AccessGateConfig = UnwrapVolatile<AccessGateConfigFields>
|
|
46
57
|
|
|
47
58
|
/** 判定所需的最小配置视图(测试与决策函数共用窄面)。 */
|
|
48
59
|
export interface GatePolicy {
|
package/src/index.ts
CHANGED
|
@@ -32,8 +32,9 @@ import { type Context, Service } from '@deepseek-ai/cordis'
|
|
|
32
32
|
import type {} from '@deepseek-ai/dsh-client-connection'
|
|
33
33
|
import { dshHomePath } from '@deepseek-ai/dsh-home-paths'
|
|
34
34
|
import type {} from '@deepseek-ai/dsh-settings'
|
|
35
|
+
import { unwrapVolatile } from '@dsh-plus/shared'
|
|
35
36
|
|
|
36
|
-
import { type AccessGateConfig,
|
|
37
|
+
import { type AccessGateConfig, type AccessGateConfigFields, Config } from './config.ts'
|
|
37
38
|
import {
|
|
38
39
|
credentialsPath,
|
|
39
40
|
mintAutoLoginCookie,
|
|
@@ -55,25 +56,17 @@ declare module '@deepseek-ai/cordis' {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
/** 围栏服务:持有当前配置读取器(
|
|
59
|
+
/** 围栏服务:持有当前配置读取器(0.1.7 起为 volatile 活动引用的平面解包,读即最新)。 */
|
|
59
60
|
export class AccessGateService extends Service {
|
|
60
61
|
private current: () => AccessGateConfig
|
|
61
62
|
/** 官方 browser-auth 签名密钥(惰性读取缓存;读取失败 = null,autoLogin fail-safe 降级)。 */
|
|
62
63
|
private signingSecret: Buffer | null | undefined
|
|
63
64
|
|
|
64
|
-
constructor(ctx: Context, config: AccessGateConfig) {
|
|
65
|
+
constructor(ctx: Context, config: AccessGateConfig | AccessGateConfigFields) {
|
|
65
66
|
super(ctx, 'accessGate')
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
ctx.inject(['settings'], (settingsCtx) => {
|
|
70
|
-
settingsCtx.settings.installSection(ctx, SETTINGS_NS, Config, config, {
|
|
71
|
-
setSource: (source) => {
|
|
72
|
-
this.current = source
|
|
73
|
-
},
|
|
74
|
-
onChange: () => {},
|
|
75
|
-
})
|
|
76
|
-
})
|
|
67
|
+
// 0.1.7 替代 0.1.6 installSection/setSource:loader 解析层已把用户层
|
|
68
|
+
// override 并入行级 config 并以活动引用原位提交,current() 现取即热。
|
|
69
|
+
this.current = () => unwrapVolatile(config)
|
|
77
70
|
const logger = ctx.logger('access-gate')
|
|
78
71
|
|
|
79
72
|
// 官方凭据校验委托:undefined = 已通过(含官方 Host 信任围栏)。
|
|
@@ -142,6 +135,6 @@ export class AccessGateService extends Service {
|
|
|
142
135
|
}
|
|
143
136
|
}
|
|
144
137
|
|
|
145
|
-
export function apply(ctx: Context, config: AccessGateConfig): void {
|
|
138
|
+
export function apply(ctx: Context, config: AccessGateConfig | AccessGateConfigFields): void {
|
|
146
139
|
ctx.plugin(AccessGateService, config)
|
|
147
140
|
}
|