






















@@ -0,0 +1,123 @@
1+import { randomUUID } from "node:crypto";
2+import { normalizeOptionalString } from "../shared/string-coerce.js";
3+import type { ExecElevatedDefaults } from "./bash-tools.exec-types.js";
4+5+const EXEC_APPROVAL_FOLLOWUP_IDEMPOTENCY_PREFIX = "exec-approval-followup:";
6+const EXEC_APPROVAL_FOLLOWUP_ELEVATED_TOKEN_MARKER = ":elevated:";
7+const EXEC_APPROVAL_FOLLOWUP_ELEVATED_TTL_MS = 5 * 60 * 1000;
8+9+type ExecApprovalFollowupElevatedEntry = {
10+sessionKey: string;
11+bashElevated: ExecElevatedDefaults;
12+expiresAtMs: number;
13+};
14+15+const execApprovalFollowupElevatedDefaults = new Map<string, ExecApprovalFollowupElevatedEntry>();
16+17+function cloneExecElevatedDefaults(value: ExecElevatedDefaults): ExecElevatedDefaults {
18+return {
19+enabled: value.enabled,
20+allowed: value.allowed,
21+defaultLevel: value.defaultLevel,
22+ ...(value.fullAccessAvailable !== undefined
23+ ? { fullAccessAvailable: value.fullAccessAvailable }
24+ : {}),
25+ ...(value.fullAccessBlockedReason !== undefined
26+ ? { fullAccessBlockedReason: value.fullAccessBlockedReason }
27+ : {}),
28+};
29+}
30+31+function pruneExpiredExecApprovalFollowupElevatedDefaults(nowMs: number): void {
32+for (const [token, entry] of execApprovalFollowupElevatedDefaults) {
33+if (entry.expiresAtMs <= nowMs) {
34+execApprovalFollowupElevatedDefaults.delete(token);
35+}
36+}
37+}
38+39+export function buildExecApprovalFollowupIdempotencyKey(params: {
40+approvalId: string;
41+execApprovalFollowupToken?: string;
42+}): string {
43+const base = `${EXEC_APPROVAL_FOLLOWUP_IDEMPOTENCY_PREFIX}${params.approvalId}`;
44+return params.execApprovalFollowupToken
45+ ? `${base}${EXEC_APPROVAL_FOLLOWUP_ELEVATED_TOKEN_MARKER}${params.execApprovalFollowupToken}`
46+ : base;
47+}
48+49+function parseExecApprovalFollowupToken(idempotencyKey: string): string | undefined {
50+if (!idempotencyKey.startsWith(EXEC_APPROVAL_FOLLOWUP_IDEMPOTENCY_PREFIX)) {
51+return undefined;
52+}
53+const tokenMarker = idempotencyKey.lastIndexOf(EXEC_APPROVAL_FOLLOWUP_ELEVATED_TOKEN_MARKER);
54+if (tokenMarker < EXEC_APPROVAL_FOLLOWUP_IDEMPOTENCY_PREFIX.length) {
55+return undefined;
56+}
57+return normalizeOptionalString(
58+idempotencyKey.slice(tokenMarker + EXEC_APPROVAL_FOLLOWUP_ELEVATED_TOKEN_MARKER.length),
59+);
60+}
61+62+export function registerExecApprovalFollowupElevatedDefaults(params: {
63+sessionKey: string;
64+bashElevated?: ExecElevatedDefaults;
65+nowMs?: number;
66+}): string | undefined {
67+const sessionKey = normalizeOptionalString(params.sessionKey);
68+if (!params.bashElevated || !sessionKey) {
69+return undefined;
70+}
71+const nowMs = params.nowMs ?? Date.now();
72+pruneExpiredExecApprovalFollowupElevatedDefaults(nowMs);
73+const token = randomUUID();
74+execApprovalFollowupElevatedDefaults.set(token, {
75+ sessionKey,
76+bashElevated: cloneExecElevatedDefaults(params.bashElevated),
77+expiresAtMs: nowMs + EXEC_APPROVAL_FOLLOWUP_ELEVATED_TTL_MS,
78+});
79+return token;
80+}
81+82+export function consumeExecApprovalFollowupElevatedDefaults(params: {
83+token?: string;
84+sessionKey?: string;
85+nowMs?: number;
86+}): ExecElevatedDefaults | undefined {
87+const token = normalizeOptionalString(params.token);
88+if (!token) {
89+return undefined;
90+}
91+const nowMs = params.nowMs ?? Date.now();
92+pruneExpiredExecApprovalFollowupElevatedDefaults(nowMs);
93+const entry = execApprovalFollowupElevatedDefaults.get(token);
94+if (!entry) {
95+return undefined;
96+}
97+if (entry.expiresAtMs <= nowMs) {
98+execApprovalFollowupElevatedDefaults.delete(token);
99+return undefined;
100+}
101+const sessionKey = normalizeOptionalString(params.sessionKey);
102+if (entry.sessionKey !== sessionKey) {
103+return undefined;
104+}
105+execApprovalFollowupElevatedDefaults.delete(token);
106+return cloneExecElevatedDefaults(entry.bashElevated);
107+}
108+109+export function consumeExecApprovalFollowupElevatedDefaultsFromIdempotencyKey(params: {
110+idempotencyKey: string;
111+sessionKey?: string;
112+nowMs?: number;
113+}): ExecElevatedDefaults | undefined {
114+return consumeExecApprovalFollowupElevatedDefaults({
115+token: parseExecApprovalFollowupToken(params.idempotencyKey),
116+sessionKey: params.sessionKey,
117+nowMs: params.nowMs,
118+});
119+}
120+121+export function resetExecApprovalFollowupElevatedDefaultsForTests(): void {
122+execApprovalFollowupElevatedDefaults.clear();
123+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。