@dsh-plus/access-gate 0.1.4 → 0.2.1
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 +52 -165
- package/lib/index.d.ts +1 -9
- package/lib/index.js +192 -266
- package/package.json +12 -11
- package/src/client/card.tsx +21 -112
- package/src/client/client.ts +1 -1
- package/src/client/i18n.ts +23 -37
- package/src/config.ts +11 -26
- package/src/decision.ts +42 -50
- package/src/index.ts +36 -13
- package/src/interceptor.ts +33 -11
- package/src/ns.ts +3 -2
- package/src/routes.ts +47 -109
- package/src/token-page.ts +88 -0
- package/src/login-page.ts +0 -77
package/lib/client.js
CHANGED
|
@@ -91,41 +91,6 @@ window.__ModuleLoader__.load({
|
|
|
91
91
|
}
|
|
92
92
|
//#endregion
|
|
93
93
|
//#region ../shared/src/client/fields.tsx
|
|
94
|
-
function TextField(props) {
|
|
95
|
-
const p = props.prefix ?? "dshp";
|
|
96
|
-
const invalid = props.invalid === true;
|
|
97
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
98
|
-
className: `${p}-field`,
|
|
99
|
-
children: [
|
|
100
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
101
|
-
className: `${p}-head`,
|
|
102
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
103
|
-
className: `${p}-label`,
|
|
104
|
-
htmlFor: props.id,
|
|
105
|
-
children: props.label
|
|
106
|
-
}), props.badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
107
|
-
className: `${p}-badge ${props.badge.set ? `${p}-badgeSet` : `${p}-badgeUnset`}`,
|
|
108
|
-
children: props.badge.text
|
|
109
|
-
}) : null]
|
|
110
|
-
}),
|
|
111
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
112
|
-
id: props.id,
|
|
113
|
-
className: `${p}-input${invalid ? ` ${p}-inputInvalid` : ""}`,
|
|
114
|
-
type: props.password === true ? "password" : "text",
|
|
115
|
-
inputMode: props.numeric === true ? "numeric" : void 0,
|
|
116
|
-
autoComplete: props.password === true ? "off" : void 0,
|
|
117
|
-
"aria-invalid": invalid || void 0,
|
|
118
|
-
value: props.value,
|
|
119
|
-
disabled: props.disabled === true,
|
|
120
|
-
onChange: (event) => props.onEdit(event.target.value)
|
|
121
|
-
}),
|
|
122
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
123
|
-
className: invalid ? `${p}-invalid` : `${p}-hint`,
|
|
124
|
-
children: invalid ? props.invalidLabel ?? "" : props.hint ?? ""
|
|
125
|
-
})
|
|
126
|
-
]
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
94
|
/**
|
|
130
95
|
* 勾选行:自绘圆角扁平开关(switch),对齐官方 WebUI 无原生 checkbox 的
|
|
131
96
|
* 设计语言(官方选择类控件全走胶囊/菜单,见 cardCss 的 -switch 规则)。
|
|
@@ -385,8 +350,9 @@ ${extra}
|
|
|
385
350
|
//#region src/ns.ts
|
|
386
351
|
/**
|
|
387
352
|
* settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
|
|
388
|
-
*
|
|
389
|
-
* settings.plugin.item keyed 槽位的
|
|
353
|
+
* 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings 编译期校验命名空间
|
|
354
|
+
* 语法,见 config.ts),浏览器半将其作为 settings.plugin.item keyed 槽位的
|
|
355
|
+
* key —— 同一字面量两处共用,防止漂移。
|
|
390
356
|
* @module access-gate/ns
|
|
391
357
|
*/
|
|
392
358
|
const SETTINGS_NS = "dsh-plus-access-gate";
|
|
@@ -395,47 +361,39 @@ ${extra}
|
|
|
395
361
|
/**
|
|
396
362
|
* 「访问控制」配置卡片:注册进 settings.plugin.item 插槽(官方插件配置页)。
|
|
397
363
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
398
|
-
*
|
|
399
|
-
* 配置读写走官方 settingsScope 传输:value 为 schema
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
364
|
+
* 本文件保留业务字段(白名单 textarea/诊断面板)与保存逻辑。
|
|
365
|
+
* 配置读写走官方 settingsScope 传输:value 为 schema 解析后的视图,
|
|
366
|
+
* 保存经 settings.update 深合并。
|
|
367
|
+
* 卡片顶部「当前页面诊断」读 /dsh-plus/gate/status(本页放行原因/客户端 IP/
|
|
368
|
+
* 官方 cookie 状态)。
|
|
369
|
+
*
|
|
370
|
+
* 与官方认证合并后:访问凭据由官方 browser-auth 持有(30 天 cookie),
|
|
371
|
+
* 卡片不再管理令牌;allowedIps 仅为可选附加 IP 围栏。
|
|
403
372
|
* @module access-gate/client/card
|
|
404
373
|
*/
|
|
405
374
|
function draftFromValue(value) {
|
|
406
375
|
return {
|
|
407
376
|
enabled: value.enabled,
|
|
408
|
-
token: "",
|
|
409
377
|
allowedIpsText: value.allowedIps.join("\n"),
|
|
410
|
-
trustForwardedFor: value.trustForwardedFor
|
|
411
|
-
cookieMaxAgeHours: String(value.cookieMaxAgeHours),
|
|
412
|
-
loginFailLimit: String(value.loginFailLimit),
|
|
413
|
-
loginCooldownMs: String(value.loginCooldownMs)
|
|
378
|
+
trustForwardedFor: value.trustForwardedFor
|
|
414
379
|
};
|
|
415
380
|
}
|
|
416
|
-
function isPositiveInt(text) {
|
|
417
|
-
return /^[0-9]+$/.test(text) && Number(text) > 0;
|
|
418
|
-
}
|
|
419
381
|
function toPatch(draft) {
|
|
420
382
|
return {
|
|
421
383
|
enabled: draft.enabled,
|
|
422
384
|
allowedIps: draft.allowedIpsText.split("\n").map((s) => s.trim()).filter((s) => s.length > 0),
|
|
423
|
-
trustForwardedFor: draft.trustForwardedFor
|
|
424
|
-
cookieMaxAgeHours: Number(draft.cookieMaxAgeHours),
|
|
425
|
-
loginFailLimit: Number(draft.loginFailLimit),
|
|
426
|
-
loginCooldownMs: Number(draft.loginCooldownMs)
|
|
385
|
+
trustForwardedFor: draft.trustForwardedFor
|
|
427
386
|
};
|
|
428
387
|
}
|
|
429
388
|
/** reason 枚举 → 文案 key。 */
|
|
430
389
|
const REASON_KEYS = {
|
|
431
390
|
local: "diagLocal",
|
|
432
|
-
|
|
433
|
-
token: "diagToken"
|
|
391
|
+
cookie: "diagCookie"
|
|
434
392
|
};
|
|
435
393
|
function verdictLabel(t, diag) {
|
|
436
394
|
if (!diag.enabled) return t("diagOff");
|
|
437
395
|
if (diag.verdict === "pass") return t("diagPass");
|
|
438
|
-
if (diag.verdict === "
|
|
396
|
+
if (diag.verdict === "token-page") return t("diagTokenPage");
|
|
439
397
|
return t("diagBlock");
|
|
440
398
|
}
|
|
441
399
|
function AccessGateCard(props) {
|
|
@@ -444,7 +402,6 @@ ${extra}
|
|
|
444
402
|
const value = snapshot.value;
|
|
445
403
|
const [open, setOpen] = (0, react.useState)(false);
|
|
446
404
|
const [draft, setDraft] = (0, react.useState)(null);
|
|
447
|
-
const [tokenConfigured, setTokenConfigured] = (0, react.useState)(false);
|
|
448
405
|
const [diag, setDiag] = (0, react.useState)(null);
|
|
449
406
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
450
407
|
const [status, setStatus] = (0, react.useState)(IDLE_STATUS);
|
|
@@ -452,17 +409,6 @@ ${extra}
|
|
|
452
409
|
if (value === void 0 || draft !== null) return;
|
|
453
410
|
setDraft(draftFromValue(value));
|
|
454
411
|
}, [value, draft]);
|
|
455
|
-
(0, react.useEffect)(() => {
|
|
456
|
-
let alive = true;
|
|
457
|
-
api.describe().then((view) => {
|
|
458
|
-
if (!alive) return;
|
|
459
|
-
const ns = view.namespaces.find((candidate) => candidate.ns === SETTINGS_NS);
|
|
460
|
-
setTokenConfigured(ns?.secrets.some((secret) => secret.path.join(".") === "token" && secret.set) ?? false);
|
|
461
|
-
}).catch(() => {});
|
|
462
|
-
return () => {
|
|
463
|
-
alive = false;
|
|
464
|
-
};
|
|
465
|
-
}, [api, snapshot]);
|
|
466
412
|
(0, react.useEffect)(() => {
|
|
467
413
|
let alive = true;
|
|
468
414
|
fetch("/dsh-plus/gate/status").then((res) => res.ok ? res.json() : null).then((body) => {
|
|
@@ -472,9 +418,7 @@ ${extra}
|
|
|
472
418
|
alive = false;
|
|
473
419
|
};
|
|
474
420
|
}, [snapshot]);
|
|
475
|
-
const failClosed = (0, react.useMemo)(() => value?.enabled === true && value.allowedIps.length === 0 && !tokenConfigured, [value, tokenConfigured]);
|
|
476
421
|
const dirty = (0, react.useMemo)(() => value !== void 0 && draft !== null && JSON.stringify(toPatch(draft)) !== JSON.stringify(toPatch(draftFromValue(value))), [value, draft]);
|
|
477
|
-
const invalid = (0, react.useMemo)(() => draft !== null && (!isPositiveInt(draft.cookieMaxAgeHours) || !isPositiveInt(draft.loginFailLimit) || !isPositiveInt(draft.loginCooldownMs)), [draft]);
|
|
478
422
|
if (value === void 0 || draft === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
479
423
|
className: "dag-card",
|
|
480
424
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -492,7 +436,6 @@ ${extra}
|
|
|
492
436
|
const onSave = () => {
|
|
493
437
|
setSaving(true);
|
|
494
438
|
const patch = toPatch(draft);
|
|
495
|
-
if (draft.token !== "") patch.token = draft.token;
|
|
496
439
|
const revision = scope.getSnapshot().revision;
|
|
497
440
|
api.update(patch, revision).then(async () => {
|
|
498
441
|
await scope.load();
|
|
@@ -534,14 +477,14 @@ ${extra}
|
|
|
534
477
|
key: "save",
|
|
535
478
|
label: t(saving ? "saving" : "save"),
|
|
536
479
|
variant: "primary",
|
|
537
|
-
disabled: !dirty ||
|
|
480
|
+
disabled: !dirty || saving || disabled,
|
|
538
481
|
onClick: onSave
|
|
539
482
|
}],
|
|
540
483
|
children: [
|
|
541
|
-
|
|
542
|
-
className: "dag-
|
|
543
|
-
children: t("
|
|
544
|
-
})
|
|
484
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
485
|
+
className: "dag-hint",
|
|
486
|
+
children: t("mergedHint")
|
|
487
|
+
}),
|
|
545
488
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckRow, {
|
|
546
489
|
prefix: "dag",
|
|
547
490
|
id: "dag-enabled",
|
|
@@ -550,20 +493,6 @@ ${extra}
|
|
|
550
493
|
disabled,
|
|
551
494
|
onEdit: (v) => edit("enabled", v)
|
|
552
495
|
}),
|
|
553
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
554
|
-
prefix: "dag",
|
|
555
|
-
id: "dag-token",
|
|
556
|
-
label: t("token"),
|
|
557
|
-
hint: t("tokenHint"),
|
|
558
|
-
value: draft.token,
|
|
559
|
-
password: true,
|
|
560
|
-
disabled,
|
|
561
|
-
badge: {
|
|
562
|
-
text: t(tokenConfigured ? "tokenSet" : "tokenUnset"),
|
|
563
|
-
set: tokenConfigured
|
|
564
|
-
},
|
|
565
|
-
onEdit: (v) => edit("token", v)
|
|
566
|
-
}),
|
|
567
496
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
568
497
|
className: "dag-field",
|
|
569
498
|
children: [
|
|
@@ -597,42 +526,6 @@ ${extra}
|
|
|
597
526
|
disabled,
|
|
598
527
|
onEdit: (v) => edit("trustForwardedFor", v)
|
|
599
528
|
}),
|
|
600
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
601
|
-
prefix: "dag",
|
|
602
|
-
id: "dag-cookie",
|
|
603
|
-
label: t("cookieMaxAgeHours"),
|
|
604
|
-
hint: t("cookieMaxAgeHoursHint"),
|
|
605
|
-
value: draft.cookieMaxAgeHours,
|
|
606
|
-
numeric: true,
|
|
607
|
-
disabled,
|
|
608
|
-
invalid: !isPositiveInt(draft.cookieMaxAgeHours),
|
|
609
|
-
invalidLabel: t("invalidNumber"),
|
|
610
|
-
onEdit: (v) => edit("cookieMaxAgeHours", v)
|
|
611
|
-
}),
|
|
612
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
613
|
-
prefix: "dag",
|
|
614
|
-
id: "dag-faillimit",
|
|
615
|
-
label: t("loginFailLimit"),
|
|
616
|
-
hint: t("loginFailLimitHint"),
|
|
617
|
-
value: draft.loginFailLimit,
|
|
618
|
-
numeric: true,
|
|
619
|
-
disabled,
|
|
620
|
-
invalid: !isPositiveInt(draft.loginFailLimit),
|
|
621
|
-
invalidLabel: t("invalidNumber"),
|
|
622
|
-
onEdit: (v) => edit("loginFailLimit", v)
|
|
623
|
-
}),
|
|
624
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
625
|
-
prefix: "dag",
|
|
626
|
-
id: "dag-cooldown",
|
|
627
|
-
label: t("loginCooldownMs"),
|
|
628
|
-
hint: t("loginCooldownMsHint"),
|
|
629
|
-
value: draft.loginCooldownMs,
|
|
630
|
-
numeric: true,
|
|
631
|
-
disabled,
|
|
632
|
-
invalid: !isPositiveInt(draft.loginCooldownMs),
|
|
633
|
-
invalidLabel: t("invalidNumber"),
|
|
634
|
-
onEdit: (v) => edit("loginCooldownMs", v)
|
|
635
|
-
}),
|
|
636
529
|
diag !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
637
530
|
className: `dag-diag${diag.invalidEntries.length > 0 ? " dag-diagWarn" : ""}`,
|
|
638
531
|
children: [
|
|
@@ -670,6 +563,16 @@ ${extra}
|
|
|
670
563
|
children: diag.reason !== null ? t(REASON_KEYS[diag.reason] ?? diag.reason) : "—"
|
|
671
564
|
})]
|
|
672
565
|
}),
|
|
566
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
567
|
+
className: "dag-diagRow",
|
|
568
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
569
|
+
className: "dag-diagKey",
|
|
570
|
+
children: t("diagOfficial")
|
|
571
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
572
|
+
className: "dag-diagVal",
|
|
573
|
+
children: diag.officialAuthed ? t("diagOfficialYes") : t("diagOfficialNo")
|
|
574
|
+
})]
|
|
575
|
+
}),
|
|
673
576
|
diag.invalidEntries.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
674
577
|
className: "dag-diagRow",
|
|
675
578
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -695,69 +598,53 @@ ${extra}
|
|
|
695
598
|
const NS = "dsh-plus-access-gate";
|
|
696
599
|
const ownZh = {
|
|
697
600
|
title: "访问控制",
|
|
698
|
-
description: "Web
|
|
601
|
+
description: "Web 访问围栏:与官方登录合并——官方 cookie 为唯一凭据;未认证导航显示启动令牌输入页(PWA 内可用);可选 IP 附加围栏。",
|
|
699
602
|
enabled: "启用访问围栏",
|
|
700
|
-
enabledHint: "
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
tokenUnset: "未配置",
|
|
705
|
-
allowedIps: "放行 IP 白名单",
|
|
706
|
-
allowedIpsHint: "每行一个:精确 IP 或 CIDR(IPv4/IPv6 皆可),如 100.86.108.55 或 fd7a:115c:a1e0::/48。",
|
|
603
|
+
enabledHint: "关闭即完全旁路(等价插件缺席);启用后未认证流量被拦截到令牌输入页或拒绝。",
|
|
604
|
+
mergedHint: "登录凭据由官方认证持有(启动令牌换 30 天 cookie)。获取当前令牌:服务器执行 dshctl url,或本机访问 /dsh-plus/gate/launch-url。",
|
|
605
|
+
allowedIps: "附加 IP 围栏白名单",
|
|
606
|
+
allowedIpsHint: "每行一个:精确 IP 或 CIDR(IPv4/IPv6 皆可)。非空时仅白名单来源可通行与登录;留空 = 不限制来源 IP(仅官方登录保护)。",
|
|
707
607
|
trustForwardedFor: "信任 x-forwarded-for 还原客户端 IP",
|
|
708
608
|
trustForwardedForHint: "仅当入口代理强制覆盖该头时开启(tailscale serve 满足);直连暴露场景必须关闭。",
|
|
709
|
-
cookieMaxAgeHours: "登录有效期(小时)",
|
|
710
|
-
cookieMaxAgeHoursHint: "令牌登录后 cookie 的有效期。",
|
|
711
|
-
loginFailLimit: "登录失败阈值",
|
|
712
|
-
loginFailLimitHint: "每个 IP 在冷却窗口内允许的失败次数,超出进入冷却。",
|
|
713
|
-
loginCooldownMs: "登录冷却(毫秒)",
|
|
714
|
-
loginCooldownMsHint: "失败达到阈值后的冷却时长。",
|
|
715
609
|
diagTitle: "当前页面诊断",
|
|
716
610
|
diagVerdict: "本页判定",
|
|
717
611
|
diagClientIp: "客户端 IP",
|
|
718
612
|
diagReason: "放行原因",
|
|
719
613
|
diagLocal: "本机直连",
|
|
720
|
-
|
|
721
|
-
|
|
614
|
+
diagCookie: "官方 cookie",
|
|
615
|
+
diagOfficial: "官方登录状态",
|
|
616
|
+
diagOfficialYes: "已登录",
|
|
617
|
+
diagOfficialNo: "未登录",
|
|
722
618
|
diagPass: "放行",
|
|
723
619
|
diagBlock: "拦截",
|
|
724
|
-
|
|
620
|
+
diagTokenPage: "令牌输入页",
|
|
725
621
|
diagOff: "围栏未启用",
|
|
726
|
-
diagInvalid: "白名单存在无法解析的条目:"
|
|
727
|
-
warnFailClosed: "警告:已启用但令牌与白名单均为空——所有远程访问将被拒绝(含本页之外的设备)。"
|
|
622
|
+
diagInvalid: "白名单存在无法解析的条目:"
|
|
728
623
|
};
|
|
729
624
|
const ownEn = {
|
|
730
625
|
title: "Access Control",
|
|
731
|
-
description: "Web access gate:
|
|
626
|
+
description: "Web access gate merged with official auth: the official cookie is the sole credential; unauthenticated navigations get a launch-token page (works inside the PWA); optional IP fence.",
|
|
732
627
|
enabled: "Enable access gate",
|
|
733
|
-
enabledHint: "Off means full bypass (as if absent); on,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
tokenUnset: "Not set",
|
|
738
|
-
allowedIps: "Allowed IP allowlist",
|
|
739
|
-
allowedIpsHint: "One per line: exact IP or CIDR (IPv4/IPv6), e.g. 100.86.108.55 or fd7a:115c:a1e0::/48.",
|
|
628
|
+
enabledHint: "Off means full bypass (as if absent); on, unauthenticated traffic hits the token page or is refused.",
|
|
629
|
+
mergedHint: "Credentials are owned by official auth (launch token exchange, 30-day cookie). Get the current token: run dshctl url on the server, or visit /dsh-plus/gate/launch-url locally.",
|
|
630
|
+
allowedIps: "Additional IP fence allowlist",
|
|
631
|
+
allowedIpsHint: "One per line: exact IP or CIDR (IPv4/IPv6). When non-empty only listed sources may pass or log in; empty = no IP restriction (official login only).",
|
|
740
632
|
trustForwardedFor: "Trust x-forwarded-for for client IP",
|
|
741
633
|
trustForwardedForHint: "Enable only when the entry proxy overwrites that header (tailscale serve does); must be off for direct exposure.",
|
|
742
|
-
cookieMaxAgeHours: "Login validity (hours)",
|
|
743
|
-
cookieMaxAgeHoursHint: "Cookie lifetime after a token login.",
|
|
744
|
-
loginFailLimit: "Login failure limit",
|
|
745
|
-
loginFailLimitHint: "Failures per IP within the cooldown window before throttling.",
|
|
746
|
-
loginCooldownMs: "Login cooldown (ms)",
|
|
747
|
-
loginCooldownMsHint: "Cooldown duration after reaching the limit.",
|
|
748
634
|
diagTitle: "This page",
|
|
749
635
|
diagVerdict: "Verdict",
|
|
750
636
|
diagClientIp: "Client IP",
|
|
751
637
|
diagReason: "Reason",
|
|
752
638
|
diagLocal: "loopback",
|
|
753
|
-
|
|
754
|
-
|
|
639
|
+
diagCookie: "official cookie",
|
|
640
|
+
diagOfficial: "Official login",
|
|
641
|
+
diagOfficialYes: "authenticated",
|
|
642
|
+
diagOfficialNo: "not authenticated",
|
|
755
643
|
diagPass: "pass",
|
|
756
644
|
diagBlock: "blocked",
|
|
757
|
-
|
|
645
|
+
diagTokenPage: "token page",
|
|
758
646
|
diagOff: "gate disabled",
|
|
759
|
-
diagInvalid: "Allowlist entries that failed to parse:"
|
|
760
|
-
warnFailClosed: "Warning: enabled with no token and an empty allowlist — all remote access will be refused."
|
|
647
|
+
diagInvalid: "Allowlist entries that failed to parse:"
|
|
761
648
|
};
|
|
762
649
|
const zh = mergeDict(commonZh, ownZh);
|
|
763
650
|
const en = mergeDict(commonEn, ownEn);
|
package/lib/index.d.ts
CHANGED
|
@@ -3,26 +3,18 @@ import z from "@deepseek-ai/schemastery";
|
|
|
3
3
|
//#region src/config.d.ts
|
|
4
4
|
declare const Config: z<Schemastery.ObjectS<{
|
|
5
5
|
enabled: z<boolean, boolean>;
|
|
6
|
-
token: z<string, string>;
|
|
7
6
|
allowedIps: z<string[], string[]>;
|
|
8
7
|
trustForwardedFor: z<boolean, boolean>;
|
|
9
|
-
cookieMaxAgeHours: z<number, number>;
|
|
10
|
-
loginFailLimit: z<number, number>;
|
|
11
|
-
loginCooldownMs: z<number, number>;
|
|
12
8
|
}>, Schemastery.ObjectT<{
|
|
13
9
|
enabled: z<boolean, boolean>;
|
|
14
|
-
token: z<string, string>;
|
|
15
10
|
allowedIps: z<string[], string[]>;
|
|
16
11
|
trustForwardedFor: z<boolean, boolean>;
|
|
17
|
-
cookieMaxAgeHours: z<number, number>;
|
|
18
|
-
loginFailLimit: z<number, number>;
|
|
19
|
-
loginCooldownMs: z<number, number>;
|
|
20
12
|
}>>;
|
|
21
13
|
type AccessGateConfig = Schemastery.TypeT<typeof Config>;
|
|
22
14
|
//#endregion
|
|
23
15
|
//#region src/index.d.ts
|
|
24
16
|
declare const name = "dsh-plus-access-gate";
|
|
25
|
-
declare const inject: readonly ["webServer"];
|
|
17
|
+
declare const inject: readonly ["webServer", "connection"];
|
|
26
18
|
declare module '@deepseek-ai/cordis' {
|
|
27
19
|
interface Context {
|
|
28
20
|
accessGate: AccessGateService;
|