sliccy 6.154.1 → 6.154.2
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/dist/node-server/browser-shutdown.d.ts +6 -1
- package/dist/node-server/browser-shutdown.js +3 -3
- package/dist/node-server/chrome-launch.d.ts +3 -0
- package/dist/node-server/chrome-launch.js +2 -1
- package/dist/node-server/electron-controller.d.ts +63 -2
- package/dist/node-server/electron-controller.js +86 -48
- package/dist/node-server/electron-runtime.d.ts +15 -1
- package/dist/node-server/electron-runtime.js +10 -10
- package/dist/node-server/fetch-proxy-gzip.js +5 -7
- package/dist/node-server/hosted-bootstrap.d.ts +1 -0
- package/dist/node-server/hosted-bootstrap.js +12 -14
- package/dist/node-server/hostfs.d.ts +37 -1
- package/dist/node-server/hostfs.js +5 -5
- package/dist/node-server/install-cli.d.ts +1 -0
- package/dist/node-server/install-cli.js +1 -1
- package/dist/node-server/launch-url.js +2 -6
- package/dist/node-server/leader-restart.d.ts +9 -0
- package/dist/node-server/leader-restart.js +1 -1
- package/dist/node-server/publish-chrome-web-store-main.d.ts +1 -0
- package/dist/node-server/publish-chrome-web-store-main.js +13 -0
- package/dist/node-server/publish-chrome-web-store.d.ts +2 -0
- package/dist/node-server/publish-chrome-web-store.js +2 -15
- package/dist/node-server/release-package-main.d.ts +1 -0
- package/dist/node-server/release-package-main.js +17 -0
- package/dist/node-server/release-package.d.ts +38 -3
- package/dist/node-server/release-package.js +46 -50
- package/dist/node-server/routes/fetch-proxy.d.ts +40 -1
- package/dist/node-server/routes/fetch-proxy.js +20 -12
- package/dist/node-server/routes/secrets.d.ts +23 -1
- package/dist/node-server/routes/secrets.js +34 -30
- package/dist/node-server/secrets/proxy-manager.d.ts +2 -1
- package/dist/node-server/secrets/proxy-manager.js +27 -26
- package/dist/node-server/secrets/session-id-file.d.ts +5 -1
- package/dist/node-server/secrets/session-id-file.js +4 -4
- package/dist/node-server/secrets/sign-and-forward.d.ts +8 -0
- package/dist/node-server/secrets/sign-and-forward.js +1 -1
- package/dist/node-server/sudo/select.d.ts +2 -0
- package/dist/node-server/sudo/select.js +1 -1
- package/dist/node-server/sudo/tty-backend.d.ts +1 -0
- package/dist/node-server/sudo/tty-backend.js +1 -1
- package/dist/ui/.vite/manifest.json +171 -171
- package/dist/ui/assets/{account-store-BqdqUcgS.js → account-store-BSWxmlJm.js} +1 -1
- package/dist/ui/assets/{account-store-BgFuxoIt.js → account-store-BZdeVW0x.js} +1 -1
- package/dist/ui/assets/{adobe-BWEqvpfE.js → adobe-BKDJ9PXB.js} +1 -1
- package/dist/ui/assets/{adobe-De7VHe-t.js → adobe-Do7ppUu_.js} +1 -1
- package/dist/ui/assets/{agent-bridge-EXV0qNBB.js → agent-bridge-DKIVd0zM.js} +1 -1
- package/dist/ui/assets/{agent-panels-dcldnH3V.js → agent-panels-CERHjYbV.js} +1 -1
- package/dist/ui/assets/{apply-layout-DVgK-NlB.js → apply-layout-cMZU1oiO.js} +1 -1
- package/dist/ui/assets/{apps-BqrASr5C.js → apps-DBeGXxMQ.js} +1 -1
- package/dist/ui/assets/{azure-openai-vXGFZfPE.js → azure-openai-B7F3oYWt.js} +1 -1
- package/dist/ui/assets/{azure-openai-94kdulWT.js → azure-openai-CYw20Rb5.js} +1 -1
- package/dist/ui/assets/{budget-usage-source-BNEsxDHX.js → budget-usage-source-nJeiDJgA.js} +1 -1
- package/dist/ui/assets/{cdp-D0GOzfX9.js → cdp-C0EXef8t.js} +1 -1
- package/dist/ui/assets/{cerebras-v41u2mpJ.js → cerebras-B2Urbvva.js} +1 -1
- package/dist/ui/assets/{cerebras-eckgXNEU.js → cerebras-DmWJf3th.js} +1 -1
- package/dist/ui/assets/{composer-speech-ButVgF9_.js → composer-speech-BNHWaL3y.js} +1 -1
- package/dist/ui/assets/{connect-surface-C0WXwJHl.js → connect-surface-ig8ePsTv.js} +1 -1
- package/dist/ui/assets/{directed-approval-D1CLB6cG.js → directed-approval-B-TQlMYu.js} +1 -1
- package/dist/ui/assets/dist-BPPG9gF6.js +12 -0
- package/dist/ui/assets/dist-BnmWpUNI.js +18 -0
- package/dist/ui/assets/{dist-DCrgApJQ.js → dist-CFI3XeIO.js} +1 -1
- package/dist/ui/assets/{dist-UJah3hVh.js → dist-Ciikigd5.js} +1 -1
- package/dist/ui/assets/{fs-mC_RRTZZ.js → fs-CY5pwJnY.js} +1 -1
- package/dist/ui/assets/{fs-DK3k_wQh.js → fs-D5MhOzXY.js} +2 -2
- package/dist/ui/assets/{github-BLOM522m.js → github-B-Bd_nZ-.js} +2 -2
- package/dist/ui/assets/{github-CT-Oyj_0.js → github-C0Ge88be.js} +1 -1
- package/dist/ui/assets/{github-copilot-D2H-jvYu.js → github-copilot-CZaiYWHF.js} +1 -1
- package/dist/ui/assets/{github-copilot-CACLYChL.js → github-copilot-socdhqrE.js} +1 -1
- package/dist/ui/assets/{github-install-Bk-KTJD-.js → github-install-DuwYDOce.js} +1 -1
- package/dist/ui/assets/{github-zip-Dvb4zHOl.js → github-zip-CatJM_Hn.js} +1 -1
- package/dist/ui/assets/{hear-BXcOoxVl.js → hear-Ghdnf7n1.js} +1 -1
- package/dist/ui/assets/{help-BAqixBa0.js → help-hIoQhrvq.js} +1 -1
- package/dist/ui/assets/{js-realm-worker-CRY5Fv-C.js → js-realm-worker-DWUez8Bj.js} +1 -1
- package/dist/ui/assets/{kernel-worker-C1DLWYBM.js → kernel-worker-DOOSpFVG.js} +581 -581
- package/dist/ui/assets/{local-llm-Cv98D1SL.js → local-llm-Bi5_jnDv.js} +1 -1
- package/dist/ui/assets/{local-llm-D723hPLf.js → local-llm-DUeCZi0o.js} +1 -1
- package/dist/ui/assets/{main-C-pVQBFE.js → main-BBsnqT-n.js} +3 -3
- package/dist/ui/assets/{main-cherry-BdH-nz0p.js → main-cherry-Dx-6EGAA.js} +1 -1
- package/dist/ui/assets/{memory-curation-seam-eUVjWT6W.js → memory-curation-seam-6Ye5fb1z.js} +1 -1
- package/dist/ui/assets/{mount-3VFe3Pa7.js → mount-BJWo4gr-.js} +3 -3
- package/dist/ui/assets/{mount-Dh4tJ6XQ.js → mount-Dq_fD8nk.js} +1 -1
- package/dist/ui/assets/{mount-recovery-Cp7KYqTq.js → mount-recovery-2IXcFTPg.js} +1 -1
- package/dist/ui/assets/{new-session-hwwKqrO5.js → new-session-yJbhj5MZ.js} +2 -2
- package/dist/ui/assets/{oauth-bootstrap-BP7bAgwJ.js → oauth-bootstrap-B1nxEXuw.js} +2 -2
- package/dist/ui/assets/{onboarding-orchestrator-DOOTJ9OG.js → onboarding-orchestrator-Bzd3eyDB.js} +1 -1
- package/dist/ui/assets/{openai-codex--3foibzj.js → openai-codex-Blu70lOC.js} +1 -1
- package/dist/ui/assets/{openai-codex-vGpH6Ldz.js → openai-codex-CRux_5Io.js} +1 -1
- package/dist/ui/assets/{openrouter-B3v5OQPe.js → openrouter-BwyOovNP.js} +1 -1
- package/dist/ui/assets/{openrouter-D17vOiK5.js → openrouter-D5FrXcZn.js} +1 -1
- package/dist/ui/assets/{openrouter-free-Mha-ykI6.js → openrouter-free-73roMQJB.js} +1 -1
- package/dist/ui/assets/{openrouter-free-DndyeHH8.js → openrouter-free-C6PmJYd9.js} +1 -1
- package/dist/ui/assets/{openrouter-oauth-ov7dnUnh.js → openrouter-oauth-D6eTjtsZ.js} +1 -1
- package/dist/ui/assets/{openrouter-oauth-C4aGXNeF.js → openrouter-oauth-DWlKSVgT.js} +1 -1
- package/dist/ui/assets/{panel-rpc-handlers-CDsWA3s8.js → panel-rpc-handlers-3YsyA58r.js} +2 -2
- package/dist/ui/assets/{panelize-shell-CXpZWzgn.js → panelize-shell-DE_uUThR.js} +1 -1
- package/dist/ui/assets/{provider-BtT9_ZsY.js → provider-PKpn_LmL.js} +1 -1
- package/dist/ui/assets/{provider-2fDgJArv.js → provider-kiXfL_mq.js} +2 -2
- package/dist/ui/assets/provider-settings-DQML2w6d.js +1 -0
- package/dist/ui/assets/provider-store-access-BEmFKV-n.js +1 -0
- package/dist/ui/assets/provider-store-access-Cce46clP.js +1 -0
- package/dist/ui/assets/{providers-BWmPj6ob.js → providers-B7K9U_fm.js} +2 -2
- package/dist/ui/assets/{providers-D_mm-oKv.js → providers-e1sU7s6k.js} +1 -1
- package/dist/ui/assets/{quick-llm-Ch_X9AH9.js → quick-llm-fE1NE1pP.js} +1 -1
- package/dist/ui/assets/{recovery-screen-Ldb8xS5S.js → recovery-screen-yZ7MZWap.js} +1 -1
- package/dist/ui/assets/{run-DXUToOLa.js → run-CJHbh10K.js} +1 -1
- package/dist/ui/assets/{run-xG3-BOwR.js → run-Ce3yzmAj.js} +1 -1
- package/dist/ui/assets/{run-Bmb6g7U2.js → run-WYZqOFOH.js} +2 -2
- package/dist/ui/assets/{session-jsonl-DlNZajGM.js → session-jsonl-1Tumjx5q.js} +1 -1
- package/dist/ui/assets/{setup-feature-flags-remote-D-IPtvuE.js → setup-feature-flags-remote-Bjk9XIgB.js} +1 -1
- package/dist/ui/assets/sidecar-repair-D9Vw_sYj.js +1 -0
- package/dist/ui/assets/{silent-renew-backoff-BocHwLdw.js → silent-renew-backoff-Djz3wKFS.js} +1 -1
- package/dist/ui/assets/{skills-CTDnQTUW.js → skills-CyxZ_qdB.js} +1 -1
- package/dist/ui/assets/slicc-version-Be90TKG2.js +1 -0
- package/dist/ui/assets/{snapshot-BZ-_n6uU.js → snapshot-3Qf38DNo.js} +1 -1
- package/dist/ui/assets/{snapshot-features-BWzc1ERL.js → snapshot-features-BPOMdL3k.js} +1 -1
- package/dist/ui/assets/{soundscape-CowYlYSr.js → soundscape-B2mWrlHy.js} +1 -1
- package/dist/ui/assets/{speak-rCiisrK7.js → speak-CDJ0RzHm.js} +1 -1
- package/dist/ui/assets/{sprinkle-manager-DaVvW4Pl.js → sprinkle-manager-CpaUQQdp.js} +1 -1
- package/dist/ui/assets/{sprinkle-renderer-CDcbztf1.js → sprinkle-renderer-xqSZhBNo.js} +1 -1
- package/dist/ui/assets/{state-DHftNsPN.js → state-C-GUxpCw.js} +1 -1
- package/dist/ui/assets/{store-MZJeSOYF.js → store-BpCQUWkE.js} +1 -1
- package/dist/ui/assets/{store-CTM4679Z.js → store-DNbNsvQ5.js} +1 -1
- package/dist/ui/assets/{sudo-DLRz2gLx.js → sudo-HwABgE4V.js} +1 -1
- package/dist/ui/assets/{sync-dialog-BUFCYPxf.js → sync-dialog-BjaW5TBb.js} +1 -1
- package/dist/ui/assets/{transformers-env-BfjOXz9f.js → transformers-env-Xlg2tROb.js} +1 -1
- package/dist/ui/assets/{tray-sidecar-BP70hrzZ.js → tray-sidecar-KbAtqLcw.js} +1 -1
- package/dist/ui/assets/{upgrade-detection-Be8A7nY7.js → upgrade-detection-BWteE-0x.js} +1 -1
- package/dist/ui/assets/{voice-reply-BtqQr2DX.js → voice-reply-Bju5XMHK.js} +1 -1
- package/dist/ui/assets/{wc-attach-zW7DuRo7.js → wc-attach-Z0pwdH9M.js} +2 -2
- package/dist/ui/assets/{wc-extension-DGYx9jMG.js → wc-extension-_Hj1HhGf.js} +2 -2
- package/dist/ui/assets/{wc-follower-Bc6Mmmda.js → wc-follower-DVUdb9Um.js} +3 -3
- package/dist/ui/assets/{wc-follower-oauth-DOaUEVw8.js → wc-follower-oauth-BPx1gTgG.js} +1 -1
- package/dist/ui/assets/{wc-gelatiere-CdqOnO6V.js → wc-gelatiere-C0ySyH9N.js} +1 -1
- package/dist/ui/assets/{wc-live-BrKyGs-7.js → wc-live-DDos6Dzx.js} +5 -5
- package/dist/ui/assets/{wc-nav-dSAbBsA5.js → wc-nav-B2eDg6pO.js} +2 -2
- package/dist/ui/assets/{wc-onboarding-C1uyya9g.js → wc-onboarding-DboQnPWI.js} +2 -2
- package/dist/ui/assets/{wc-placeholder-Cw7uGVuJ.js → wc-placeholder-BjUEI-Mu.js} +3 -3
- package/dist/ui/assets/{wc-secret-request-CwA6DiWC.js → wc-secret-request-DceB-GYM.js} +1 -1
- package/dist/ui/assets/{wc-settings-DJEhDr23.js → wc-settings-DSED486Z.js} +3 -3
- package/dist/ui/assets/{wc-shell-C-DwVQCG.js → wc-shell-Dukh8kBp.js} +3 -3
- package/dist/ui/assets/{wc-shortcut-config-D9HBEfqv.js → wc-shortcut-config-BVLmA_4e.js} +1 -1
- package/dist/ui/assets/{wc-shortcuts-7i4KncH2.js → wc-shortcuts-DRoF52xJ.js} +1 -1
- package/dist/ui/assets/{wc-sprinkles-DsRJYYRI.js → wc-sprinkles-D-gTuKDK.js} +2 -2
- package/dist/ui/assets/{wc-transcript-export-Dq9HNkpA.js → wc-transcript-export-NX12cq80.js} +2 -2
- package/dist/ui/assets/{wc-tray-f6xi76Bq.js → wc-tray-CiypFS7u.js} +4 -4
- package/dist/ui/assets/welcome-detection-DS0NGHuw.js +1 -0
- package/dist/ui/assets/{whisper-session-B6knWfce.js → whisper-session-B2k89xAM.js} +2 -2
- package/dist/ui/assets/{xai-grok-BIfBT2BL.js → xai-grok-DMR1ZtnC.js} +1 -1
- package/dist/ui/assets/{xai-grok-B0KRInrx.js → xai-grok-cDPFunWd.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/ui/packages/webapp/index.html +3 -3
- package/package.json +3 -3
- package/dist/ui/assets/dist-B3W7EgGh.js +0 -12
- package/dist/ui/assets/dist-CmI2JIly.js +0 -18
- package/dist/ui/assets/provider-settings-D2AYwHOa.js +0 -1
- package/dist/ui/assets/provider-store-access-BdvWm9Kj.js +0 -1
- package/dist/ui/assets/provider-store-access-C5A5Se3D.js +0 -1
- package/dist/ui/assets/sidecar-repair-DRUvDMSe.js +0 -1
- package/dist/ui/assets/slicc-version-CWl4uhV3.js +0 -1
- package/dist/ui/assets/welcome-detection-DmqQ-hO4.js +0 -1
|
@@ -8,7 +8,7 @@ import { handleDaSignAndForward, handleS3SignAndForward } from '../secrets/sign-
|
|
|
8
8
|
* the 500 they got with the server log; the detail goes to the file logger
|
|
9
9
|
* (above DEBUG) only when devMode is on.
|
|
10
10
|
*/
|
|
11
|
-
function respondSignAndForwardError(res, err, devMode, label) {
|
|
11
|
+
export function respondSignAndForwardError(res, err, devMode, label) {
|
|
12
12
|
const traceId = (globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2, 10)).slice(0, 8);
|
|
13
13
|
console.error(`${label} sign-and-forward error [trace=${traceId}]`);
|
|
14
14
|
if (devMode) {
|
|
@@ -29,7 +29,7 @@ function isStringArray(value) {
|
|
|
29
29
|
* Scope edit handler — updates allowed domains of an existing secret without
|
|
30
30
|
* changing its value. Checks session store first, then falls back to persisted.
|
|
31
31
|
*/
|
|
32
|
-
async function handleScopeEdit(res, name, domains, secretStore, secretProxy) {
|
|
32
|
+
export async function handleScopeEdit(res, name, domains, secretStore, secretProxy) {
|
|
33
33
|
if (typeof name !== 'string' || !isStringArray(domains)) {
|
|
34
34
|
return res.status(400).json({ error: 'bad-request' });
|
|
35
35
|
}
|
|
@@ -81,7 +81,7 @@ function handleRedactExport(res, texts, secretProxy) {
|
|
|
81
81
|
* session shadow does not leak through after deletion, then falls back to the
|
|
82
82
|
* persisted store. Reloads the masking pipeline either way.
|
|
83
83
|
*/
|
|
84
|
-
async function handleDeleteSecret(name, res, secretStore, secretProxy) {
|
|
84
|
+
export async function handleDeleteSecret(name, res, secretStore, secretProxy) {
|
|
85
85
|
if (typeof name !== 'string' || name.length === 0) {
|
|
86
86
|
return res.status(400).json({ error: 'bad-request' });
|
|
87
87
|
}
|
|
@@ -104,6 +104,31 @@ async function handleDeleteSecret(name, res, secretStore, secretProxy) {
|
|
|
104
104
|
.json({ error: err instanceof Error ? err.message : 'Failed to delete secret' });
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
+
function registerOauthSecretRoutes(app, oauthStore, secretProxy) {
|
|
108
|
+
app.post('/api/secrets/oauth-update', express.json(), async (req, res) => {
|
|
109
|
+
const { providerId, accessToken, domains } = req.body ?? {};
|
|
110
|
+
if (typeof providerId !== 'string' ||
|
|
111
|
+
typeof accessToken !== 'string' ||
|
|
112
|
+
!isStringArray(domains) ||
|
|
113
|
+
domains.length === 0) {
|
|
114
|
+
return res.status(400).json({ error: 'bad-request' });
|
|
115
|
+
}
|
|
116
|
+
const name = `oauth.${providerId}.token`;
|
|
117
|
+
oauthStore.set(name, accessToken, domains);
|
|
118
|
+
await secretProxy.reload();
|
|
119
|
+
const masked = secretProxy.getMaskedEntries().find((e) => e.name === name)?.maskedValue;
|
|
120
|
+
res.json({ providerId, name, maskedValue: masked, domains });
|
|
121
|
+
});
|
|
122
|
+
app.delete('/api/secrets/oauth/:providerId', async (req, res) => {
|
|
123
|
+
const name = `oauth.${req.params.providerId}.token`;
|
|
124
|
+
if (!oauthStore.list().some((e) => e.name === name)) {
|
|
125
|
+
return res.status(404).json({ error: 'not-found' });
|
|
126
|
+
}
|
|
127
|
+
oauthStore.delete(name);
|
|
128
|
+
await secretProxy.reload();
|
|
129
|
+
res.status(204).end();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
107
132
|
/**
|
|
108
133
|
* Secret management API — direct .env file access (no browser needed). The
|
|
109
134
|
* `secretStore` is wired into `secretProxy` so the fetch-proxy and the
|
|
@@ -111,6 +136,8 @@ async function handleDeleteSecret(name, res, secretStore, secretProxy) {
|
|
|
111
136
|
*/
|
|
112
137
|
export function registerSecretRoutes(app, deps) {
|
|
113
138
|
const { secretStore, secretProxy, oauthStore, devMode } = deps;
|
|
139
|
+
const handleS3 = deps.handleS3 ?? handleS3SignAndForward;
|
|
140
|
+
const handleDa = deps.handleDa ?? handleDaSignAndForward;
|
|
114
141
|
app.get('/api/secrets', (_req, res) => {
|
|
115
142
|
try {
|
|
116
143
|
res.json(secretStore.list());
|
|
@@ -197,7 +224,7 @@ export function registerSecretRoutes(app, deps) {
|
|
|
197
224
|
// never sees access_key_id / secret_access_key.
|
|
198
225
|
app.post('/api/s3-sign-and-forward', async (req, res) => {
|
|
199
226
|
try {
|
|
200
|
-
await
|
|
227
|
+
await handleS3(req, res, secretStore);
|
|
201
228
|
}
|
|
202
229
|
catch (err) {
|
|
203
230
|
respondSignAndForwardError(res, err, devMode, 'S3');
|
|
@@ -209,7 +236,7 @@ export function registerSecretRoutes(app, deps) {
|
|
|
209
236
|
// to remove the browser exposure entirely.
|
|
210
237
|
app.post('/api/da-sign-and-forward', async (req, res) => {
|
|
211
238
|
try {
|
|
212
|
-
await
|
|
239
|
+
await handleDa(req, res);
|
|
213
240
|
}
|
|
214
241
|
catch (err) {
|
|
215
242
|
respondSignAndForwardError(res, err, devMode, 'DA');
|
|
@@ -252,29 +279,6 @@ export function registerSecretRoutes(app, deps) {
|
|
|
252
279
|
.json({ error: err instanceof Error ? err.message : 'Failed to get masked secrets' });
|
|
253
280
|
}
|
|
254
281
|
});
|
|
255
|
-
// OAuth
|
|
256
|
-
app
|
|
257
|
-
const { providerId, accessToken, domains } = req.body ?? {};
|
|
258
|
-
if (typeof providerId !== 'string' ||
|
|
259
|
-
typeof accessToken !== 'string' ||
|
|
260
|
-
!isStringArray(domains) ||
|
|
261
|
-
domains.length === 0) {
|
|
262
|
-
return res.status(400).json({ error: 'bad-request' });
|
|
263
|
-
}
|
|
264
|
-
const name = `oauth.${providerId}.token`;
|
|
265
|
-
oauthStore.set(name, accessToken, domains);
|
|
266
|
-
await secretProxy.reload();
|
|
267
|
-
const masked = secretProxy.getMaskedEntries().find((e) => e.name === name)?.maskedValue;
|
|
268
|
-
res.json({ providerId, name, maskedValue: masked, domains });
|
|
269
|
-
});
|
|
270
|
-
// OAuth secret deletion — removes access token on logout
|
|
271
|
-
app.delete('/api/secrets/oauth/:providerId', async (req, res) => {
|
|
272
|
-
const name = `oauth.${req.params.providerId}.token`;
|
|
273
|
-
if (!oauthStore.list().some((e) => e.name === name)) {
|
|
274
|
-
return res.status(404).json({ error: 'not-found' });
|
|
275
|
-
}
|
|
276
|
-
oauthStore.delete(name);
|
|
277
|
-
await secretProxy.reload();
|
|
278
|
-
res.status(204).end();
|
|
279
|
-
});
|
|
282
|
+
// OAuth update/deletion — stores access tokens after login and removes them on logout.
|
|
283
|
+
registerOauthSecretRoutes(app, oauthStore, secretProxy);
|
|
280
284
|
}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
*
|
|
8
8
|
* As of Task 1.4, this is a thin wrapper around SecretsPipeline from @slicc/shared-ts.
|
|
9
9
|
*/
|
|
10
|
-
import { SecretsPipeline, SessionSecretStore } from '../_shared/index.js';
|
|
10
|
+
import { type FetchProxySecretSource, SecretsPipeline, SessionSecretStore } from '../_shared/index.js';
|
|
11
11
|
import type { EnvSecretStore } from './env-secret-store.js';
|
|
12
12
|
import type { OauthSecretStore } from './oauth-secret-store.js';
|
|
13
|
+
export declare function buildFetchProxySecretSource(getEnvStore: () => EnvSecretStore | undefined, getOauthStore: () => OauthSecretStore | undefined): FetchProxySecretSource;
|
|
13
14
|
export declare class SecretProxyManager {
|
|
14
15
|
private readonly pipeline;
|
|
15
16
|
private readonly _sessionId;
|
|
@@ -9,6 +9,32 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { randomUUID } from 'node:crypto';
|
|
11
11
|
import { SecretsPipeline, SessionSecretStore } from '../_shared/index.js';
|
|
12
|
+
export function buildFetchProxySecretSource(getEnvStore, getOauthStore) {
|
|
13
|
+
return {
|
|
14
|
+
get: async (name) => {
|
|
15
|
+
const fromOauth = getOauthStore()?.get(name);
|
|
16
|
+
if (fromOauth !== undefined)
|
|
17
|
+
return fromOauth;
|
|
18
|
+
return getEnvStore()?.get(name)?.value ?? undefined;
|
|
19
|
+
},
|
|
20
|
+
listAll: async () => {
|
|
21
|
+
const list = [];
|
|
22
|
+
// OAuth wins on name collision (reserved namespace policy)
|
|
23
|
+
const oauthList = getOauthStore()?.list() ?? [];
|
|
24
|
+
const oauthNames = new Set(oauthList.map((e) => e.name));
|
|
25
|
+
for (const e of oauthList)
|
|
26
|
+
list.push({ name: e.name, value: e.value, domains: e.domains });
|
|
27
|
+
const envEntries = getEnvStore()?.list() ?? [];
|
|
28
|
+
for (const entry of envEntries) {
|
|
29
|
+
const secret = getEnvStore()?.get(entry.name);
|
|
30
|
+
if (!secret || oauthNames.has(entry.name))
|
|
31
|
+
continue;
|
|
32
|
+
list.push({ name: secret.name, value: secret.value, domains: secret.domains });
|
|
33
|
+
}
|
|
34
|
+
return list;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
12
38
|
export class SecretProxyManager {
|
|
13
39
|
pipeline;
|
|
14
40
|
_sessionId;
|
|
@@ -28,32 +54,7 @@ export class SecretProxyManager {
|
|
|
28
54
|
});
|
|
29
55
|
}
|
|
30
56
|
buildSource() {
|
|
31
|
-
|
|
32
|
-
const oauth = () => this._oauthStore;
|
|
33
|
-
return {
|
|
34
|
-
get: async (name) => {
|
|
35
|
-
const fromOauth = oauth()?.get(name);
|
|
36
|
-
if (fromOauth !== undefined)
|
|
37
|
-
return fromOauth;
|
|
38
|
-
return env()?.get(name)?.value ?? undefined;
|
|
39
|
-
},
|
|
40
|
-
listAll: async () => {
|
|
41
|
-
const list = [];
|
|
42
|
-
// OAuth wins on name collision (reserved namespace policy)
|
|
43
|
-
const oauthList = oauth()?.list() ?? [];
|
|
44
|
-
const oauthNames = new Set(oauthList.map((e) => e.name));
|
|
45
|
-
for (const e of oauthList)
|
|
46
|
-
list.push({ name: e.name, value: e.value, domains: e.domains });
|
|
47
|
-
const envEntries = env()?.list() ?? [];
|
|
48
|
-
for (const entry of envEntries) {
|
|
49
|
-
const secret = env()?.get(entry.name);
|
|
50
|
-
if (!secret || oauthNames.has(entry.name))
|
|
51
|
-
continue;
|
|
52
|
-
list.push({ name: secret.name, value: secret.value, domains: secret.domains });
|
|
53
|
-
}
|
|
54
|
-
return list;
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
+
return buildFetchProxySecretSource(() => this._envStore, () => this._oauthStore);
|
|
57
58
|
}
|
|
58
59
|
setOauthStore(store) {
|
|
59
60
|
this._oauthStore = store;
|
|
@@ -2,4 +2,8 @@
|
|
|
2
2
|
* Read the session-id from `<dir>/session-id`; if missing/empty/corrupt, generate
|
|
3
3
|
* a fresh UUID, write it (mode 0600), and return that. Idempotent on subsequent calls.
|
|
4
4
|
*/
|
|
5
|
-
export declare function readOrCreateSessionId(dir: string
|
|
5
|
+
export declare function readOrCreateSessionId(dir: string, options?: {
|
|
6
|
+
chmod?: (path: string, mode: number) => void;
|
|
7
|
+
platform?: NodeJS.Platform;
|
|
8
|
+
reportError?: (...args: unknown[]) => void;
|
|
9
|
+
}): string;
|
|
@@ -6,7 +6,7 @@ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
|
|
6
6
|
* Read the session-id from `<dir>/session-id`; if missing/empty/corrupt, generate
|
|
7
7
|
* a fresh UUID, write it (mode 0600), and return that. Idempotent on subsequent calls.
|
|
8
8
|
*/
|
|
9
|
-
export function readOrCreateSessionId(dir) {
|
|
9
|
+
export function readOrCreateSessionId(dir, options = {}) {
|
|
10
10
|
mkdirSync(dir, { recursive: true });
|
|
11
11
|
const path = join(dir, 'session-id');
|
|
12
12
|
if (existsSync(path)) {
|
|
@@ -17,7 +17,7 @@ export function readOrCreateSessionId(dir) {
|
|
|
17
17
|
const fresh = randomUUID();
|
|
18
18
|
writeFileSync(path, fresh + '\n', { encoding: 'utf-8' });
|
|
19
19
|
try {
|
|
20
|
-
chmodSync(path, 0o600);
|
|
20
|
+
(options.chmod ?? chmodSync)(path, 0o600);
|
|
21
21
|
}
|
|
22
22
|
catch (err) {
|
|
23
23
|
// Windows ignores POSIX modes — silent failure is fine.
|
|
@@ -25,8 +25,8 @@ export function readOrCreateSessionId(dir) {
|
|
|
25
25
|
// session-id is the HMAC key that prevents lookup-table attacks on
|
|
26
26
|
// leaked masks (see docs/architecture.md), so EPERM/EACCES here is
|
|
27
27
|
// a real degradation — surface it.
|
|
28
|
-
if (process.platform !== 'win32') {
|
|
29
|
-
console.error(`[session-id] chmod 0600 failed at ${path}; session-id may be world-readable`, err instanceof Error ? err.message : String(err));
|
|
28
|
+
if ((options.platform ?? process.platform) !== 'win32') {
|
|
29
|
+
(options.reportError ?? console.error)(`[session-id] chmod 0600 failed at ${path}; session-id may be world-readable`, err instanceof Error ? err.message : String(err));
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
return fresh;
|
|
@@ -19,9 +19,17 @@
|
|
|
19
19
|
* Logging contract: never log envelope contents — request bodies or the
|
|
20
20
|
* `imsToken` may contain credential material.
|
|
21
21
|
*/
|
|
22
|
+
import { type SignAndForwardErrorCode } from '../_shared/index.js';
|
|
22
23
|
import type { Request, Response } from 'express';
|
|
23
24
|
import type { SecretStore } from './types.js';
|
|
24
25
|
export type { DaSignAndForwardEnvelope, S3SignAndForwardEnvelope } from '../_shared/index.js';
|
|
26
|
+
/**
|
|
27
|
+
* Map a structured failure code onto the HTTP status the CLI float returns.
|
|
28
|
+
* Setup/validation errors are client errors (400); an upstream fetch failure
|
|
29
|
+
* is a bad gateway (502); an internal error is 500. The `never` default makes
|
|
30
|
+
* a future addition to `SignAndForwardErrorCode` fail the typecheck here.
|
|
31
|
+
*/
|
|
32
|
+
export declare function statusForErrorCode(code: SignAndForwardErrorCode): number;
|
|
25
33
|
/**
|
|
26
34
|
* Handle a `POST /api/s3-sign-and-forward` request. Validates the envelope,
|
|
27
35
|
* resolves credentials, signs, forwards, returns a JSON envelope.
|
|
@@ -26,7 +26,7 @@ import { executeDaSignAndForward, executeS3SignAndForward, } from '../_shared/in
|
|
|
26
26
|
* is a bad gateway (502); an internal error is 500. The `never` default makes
|
|
27
27
|
* a future addition to `SignAndForwardErrorCode` fail the typecheck here.
|
|
28
28
|
*/
|
|
29
|
-
function statusForErrorCode(code) {
|
|
29
|
+
export function statusForErrorCode(code) {
|
|
30
30
|
switch (code) {
|
|
31
31
|
case 'invalid_profile':
|
|
32
32
|
case 'invalid_request':
|
|
@@ -22,6 +22,8 @@ export interface SudoEnv {
|
|
|
22
22
|
}
|
|
23
23
|
/** Probe the live environment. */
|
|
24
24
|
export declare function detectSudoEnv(): SudoEnv;
|
|
25
|
+
/** Synchronous best-effort `which`; false when the binary is absent. */
|
|
26
|
+
export declare function defaultWhich(cmd: string): boolean;
|
|
25
27
|
/**
|
|
26
28
|
* Select the highest-priority available backend for the given environment.
|
|
27
29
|
* Always returns a backend — the deny backend is the fail-closed terminal.
|
|
@@ -26,7 +26,7 @@ export function detectSudoEnv() {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
/** Synchronous best-effort `which`; false when the binary is absent. */
|
|
29
|
-
function defaultWhich(cmd) {
|
|
29
|
+
export function defaultWhich(cmd) {
|
|
30
30
|
try {
|
|
31
31
|
const probe = process.platform === 'win32' ? 'where' : 'which';
|
|
32
32
|
execFileSync(probe, [cmd], { stdio: 'ignore' });
|
|
@@ -13,5 +13,6 @@ export interface TtyDeps {
|
|
|
13
13
|
output?: NodeJS.WritableStream;
|
|
14
14
|
createRl?: () => Pick<ReadlineInterface, 'question' | 'close'>;
|
|
15
15
|
}
|
|
16
|
+
export declare function defaultRl(): Pick<ReadlineInterface, 'question' | 'close'>;
|
|
16
17
|
/** Create the editable-TTY backend. */
|
|
17
18
|
export declare function createTtyBackend(deps?: TtyDeps): SudoBackend;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* suggested default). Fail closed: a closed stream, EOF, or any error denies.
|
|
8
8
|
*/
|
|
9
9
|
import { createInterface } from 'readline';
|
|
10
|
-
function defaultRl() {
|
|
10
|
+
export function defaultRl() {
|
|
11
11
|
return createInterface({ input: process.stdin, output: process.stdout });
|
|
12
12
|
}
|
|
13
13
|
function ask(rl, query) {
|