@solongate/proxy 0.81.55 → 0.81.56
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/api-client/client.d.ts +2 -0
- package/dist/api-client/settings.d.ts +15 -0
- package/dist/commands/index.js +8 -0
- package/dist/index.js +254 -66
- package/dist/tui/index.js +253 -65
- package/package.json +1 -1
|
@@ -15,6 +15,8 @@ export interface SavedAccount {
|
|
|
15
15
|
export declare function listAccounts(): SavedAccount[];
|
|
16
16
|
/** Upsert an account (dedupe by apiKey). Called from `login`. */
|
|
17
17
|
export declare function saveAccount(acc: SavedAccount): void;
|
|
18
|
+
/** Remove a saved account from this device (does NOT revoke the cloud key). */
|
|
19
|
+
export declare function removeAccount(apiKey: string): void;
|
|
18
20
|
export declare function setViewCredentials(creds: Credentials | null): void;
|
|
19
21
|
/** True when the given key is the ACTIVE one the guard hooks use. */
|
|
20
22
|
export declare function isActiveAccount(apiKey: string): boolean;
|
|
@@ -61,6 +61,21 @@ export declare function deleteAlert(id: string): Promise<{
|
|
|
61
61
|
export declare function setAlertEnabled(id: string, enabled: boolean): Promise<{
|
|
62
62
|
ok: true;
|
|
63
63
|
}>;
|
|
64
|
+
export declare function updateAlert(id: string, patch: {
|
|
65
|
+
signal?: AlertRule['signal'];
|
|
66
|
+
threshold?: number;
|
|
67
|
+
windowSeconds?: number;
|
|
68
|
+
emails?: string[];
|
|
69
|
+
telegram?: string[];
|
|
70
|
+
}): Promise<{
|
|
71
|
+
rule: AlertRule;
|
|
72
|
+
}>;
|
|
73
|
+
export declare function sendTestAlert(id: string): Promise<{
|
|
74
|
+
delivered: {
|
|
75
|
+
telegram: boolean;
|
|
76
|
+
email: boolean;
|
|
77
|
+
};
|
|
78
|
+
}>;
|
|
64
79
|
export interface DenialWebhook {
|
|
65
80
|
id: string;
|
|
66
81
|
url: string;
|
package/dist/commands/index.js
CHANGED
|
@@ -221,11 +221,13 @@ __export(settings_exports, {
|
|
|
221
221
|
getSecurityLayers: () => getSecurityLayers,
|
|
222
222
|
getSelfProtection: () => getSelfProtection,
|
|
223
223
|
getWebhooks: () => getWebhooks,
|
|
224
|
+
sendTestAlert: () => sendTestAlert,
|
|
224
225
|
sendTestWebhook: () => sendTestWebhook,
|
|
225
226
|
setAlertEnabled: () => setAlertEnabled,
|
|
226
227
|
setLocalLogs: () => setLocalLogs,
|
|
227
228
|
setSecurityLayers: () => setSecurityLayers,
|
|
228
229
|
setSelfProtection: () => setSelfProtection,
|
|
230
|
+
updateAlert: () => updateAlert,
|
|
229
231
|
updateWebhook: () => updateWebhook
|
|
230
232
|
});
|
|
231
233
|
function getSecurityLayers() {
|
|
@@ -267,6 +269,12 @@ function deleteAlert(id) {
|
|
|
267
269
|
function setAlertEnabled(id, enabled) {
|
|
268
270
|
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: { enabled } });
|
|
269
271
|
}
|
|
272
|
+
function updateAlert(id, patch) {
|
|
273
|
+
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: patch });
|
|
274
|
+
}
|
|
275
|
+
function sendTestAlert(id) {
|
|
276
|
+
return request("POST", "/settings/denial-alerts/send-test", { body: { id } });
|
|
277
|
+
}
|
|
270
278
|
function getWebhooks() {
|
|
271
279
|
return request("GET", "/settings/denial-webhook");
|
|
272
280
|
}
|
package/dist/index.js
CHANGED
|
@@ -7086,6 +7086,20 @@ function saveAccount(acc) {
|
|
|
7086
7086
|
} catch {
|
|
7087
7087
|
}
|
|
7088
7088
|
}
|
|
7089
|
+
function removeAccount(apiKey) {
|
|
7090
|
+
try {
|
|
7091
|
+
const list6 = (() => {
|
|
7092
|
+
try {
|
|
7093
|
+
const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
|
|
7094
|
+
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
7095
|
+
} catch {
|
|
7096
|
+
return [];
|
|
7097
|
+
}
|
|
7098
|
+
})();
|
|
7099
|
+
writeFileSync6(accountsFile(), JSON.stringify(list6.filter((a) => a.apiKey !== apiKey), null, 2));
|
|
7100
|
+
} catch {
|
|
7101
|
+
}
|
|
7102
|
+
}
|
|
7089
7103
|
function setViewCredentials(creds) {
|
|
7090
7104
|
viewOverride = creds;
|
|
7091
7105
|
cached2 = null;
|
|
@@ -7394,11 +7408,13 @@ __export(settings_exports, {
|
|
|
7394
7408
|
getSecurityLayers: () => getSecurityLayers,
|
|
7395
7409
|
getSelfProtection: () => getSelfProtection,
|
|
7396
7410
|
getWebhooks: () => getWebhooks,
|
|
7411
|
+
sendTestAlert: () => sendTestAlert,
|
|
7397
7412
|
sendTestWebhook: () => sendTestWebhook,
|
|
7398
7413
|
setAlertEnabled: () => setAlertEnabled,
|
|
7399
7414
|
setLocalLogs: () => setLocalLogs,
|
|
7400
7415
|
setSecurityLayers: () => setSecurityLayers,
|
|
7401
7416
|
setSelfProtection: () => setSelfProtection,
|
|
7417
|
+
updateAlert: () => updateAlert,
|
|
7402
7418
|
updateWebhook: () => updateWebhook
|
|
7403
7419
|
});
|
|
7404
7420
|
function getSecurityLayers() {
|
|
@@ -7440,6 +7456,12 @@ function deleteAlert(id) {
|
|
|
7440
7456
|
function setAlertEnabled(id, enabled) {
|
|
7441
7457
|
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: { enabled } });
|
|
7442
7458
|
}
|
|
7459
|
+
function updateAlert(id, patch) {
|
|
7460
|
+
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: patch });
|
|
7461
|
+
}
|
|
7462
|
+
function sendTestAlert(id) {
|
|
7463
|
+
return request("POST", "/settings/denial-alerts/send-test", { body: { id } });
|
|
7464
|
+
}
|
|
7443
7465
|
function getWebhooks() {
|
|
7444
7466
|
return request("GET", "/settings/denial-webhook");
|
|
7445
7467
|
}
|
|
@@ -10076,6 +10098,7 @@ function SettingsPanel({
|
|
|
10076
10098
|
const [confirmDel, setConfirmDel] = useState7(null);
|
|
10077
10099
|
const [msg, setMsg] = useState7(null);
|
|
10078
10100
|
const [busy, setBusy] = useState7(false);
|
|
10101
|
+
const [editor, setEditor] = useState7(null);
|
|
10079
10102
|
const [accounts, setAccounts] = useState7(() => listAccounts());
|
|
10080
10103
|
const [login, setLogin] = useState7(null);
|
|
10081
10104
|
const [tick, setTick] = useState7(0);
|
|
@@ -10095,22 +10118,30 @@ function SettingsPanel({
|
|
|
10095
10118
|
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
10096
10119
|
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
10097
10120
|
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
10121
|
+
const guardQ = useLoader(() => listAccounts().length ? api.settings.getGuardStatus() : Promise.resolve(null));
|
|
10122
|
+
const selfQ = useLoader(() => listAccounts().length ? api.settings.getSelfProtection() : Promise.resolve(null));
|
|
10098
10123
|
const local = localQ.data;
|
|
10124
|
+
const guard = guardQ.data;
|
|
10125
|
+
const selfProt = selfQ.data;
|
|
10099
10126
|
const [hidden, setHidden] = useState7(/* @__PURE__ */ new Set());
|
|
10100
10127
|
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
10101
10128
|
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
10129
|
+
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
10130
|
+
const hasTgAlert = alerts.some((r) => alertChannel(r) === "telegram");
|
|
10102
10131
|
const rowsAll = [
|
|
10103
10132
|
...accounts.map((acc) => ({ kind: "acct", acc })),
|
|
10104
10133
|
{ kind: "acct-add" },
|
|
10105
10134
|
...locked ? [] : [
|
|
10135
|
+
{ kind: "guard" },
|
|
10136
|
+
{ kind: "self" },
|
|
10106
10137
|
{ kind: "ll-enabled" },
|
|
10107
10138
|
{ kind: "ll-path" },
|
|
10108
10139
|
{ kind: "ll-server" },
|
|
10109
10140
|
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
10110
10141
|
{ kind: "wh-add" },
|
|
10111
10142
|
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
10112
|
-
{ kind: "alert-add-email" },
|
|
10113
|
-
{ kind: "alert-add-tg" }
|
|
10143
|
+
...hasEmailAlert ? [] : [{ kind: "alert-add-email" }],
|
|
10144
|
+
...hasTgAlert ? [] : [{ kind: "alert-add-tg" }]
|
|
10114
10145
|
]
|
|
10115
10146
|
];
|
|
10116
10147
|
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
@@ -10121,6 +10152,8 @@ function SettingsPanel({
|
|
|
10121
10152
|
localQ.reload();
|
|
10122
10153
|
whQ.reload();
|
|
10123
10154
|
alertQ.reload();
|
|
10155
|
+
guardQ.reload();
|
|
10156
|
+
selfQ.reload();
|
|
10124
10157
|
};
|
|
10125
10158
|
const run12 = (label, fn, reload) => {
|
|
10126
10159
|
if (busy) return;
|
|
@@ -10165,6 +10198,57 @@ function SettingsPanel({
|
|
|
10165
10198
|
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
10166
10199
|
})();
|
|
10167
10200
|
};
|
|
10201
|
+
const openAlertEditor = (channel, rule) => {
|
|
10202
|
+
setEditor({
|
|
10203
|
+
id: rule?.id,
|
|
10204
|
+
channel,
|
|
10205
|
+
target: (channel === "email" ? rule?.emails?.[0] : rule?.telegram?.[0]) ?? "",
|
|
10206
|
+
signal: rule?.signal ?? "any",
|
|
10207
|
+
threshold: rule?.threshold ?? THRESH_MIN,
|
|
10208
|
+
windowSeconds: rule?.windowSeconds ?? 300,
|
|
10209
|
+
field: rule ? 1 : 0
|
|
10210
|
+
// new rule starts on the target; existing on signal
|
|
10211
|
+
});
|
|
10212
|
+
if (!rule) {
|
|
10213
|
+
setInput("");
|
|
10214
|
+
setEditing("alert-target");
|
|
10215
|
+
}
|
|
10216
|
+
};
|
|
10217
|
+
const normTarget = (channel, raw) => {
|
|
10218
|
+
const v = raw.trim();
|
|
10219
|
+
if (channel === "email") {
|
|
10220
|
+
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "");
|
|
10221
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return { value: email, error: "that does not look like an e-mail address" };
|
|
10222
|
+
return { value: email };
|
|
10223
|
+
}
|
|
10224
|
+
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "");
|
|
10225
|
+
if (!/^-?\d{5,}$/.test(tg)) return { value: tg, error: "a telegram chat id is a number \u2014 get yours from @userinfobot" };
|
|
10226
|
+
return { value: tg };
|
|
10227
|
+
};
|
|
10228
|
+
const saveEditor = () => {
|
|
10229
|
+
if (!editor) return;
|
|
10230
|
+
const t = normTarget(editor.channel, editor.target);
|
|
10231
|
+
if (t.error) {
|
|
10232
|
+
setMsg({ text: "\u2717 " + t.error, level: "bad" });
|
|
10233
|
+
return;
|
|
10234
|
+
}
|
|
10235
|
+
const channels = editor.channel === "email" ? { emails: [t.value], telegram: [] } : { telegram: [t.value], emails: [] };
|
|
10236
|
+
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, ...channels };
|
|
10237
|
+
const id = editor.id;
|
|
10238
|
+
setEditor(null);
|
|
10239
|
+
if (id) run12("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
10240
|
+
else run12(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "dataroom alert", ...body }), alertQ.reload);
|
|
10241
|
+
};
|
|
10242
|
+
const testAlert = (rule) => {
|
|
10243
|
+
run12(
|
|
10244
|
+
"alert test sent \u2014 check your " + (alertChannel(rule) ?? "channel"),
|
|
10245
|
+
() => api.settings.sendTestAlert(rule.id).then((r) => {
|
|
10246
|
+
if (!r.delivered.telegram && !r.delivered.email) throw new Error("no channel on this rule");
|
|
10247
|
+
}),
|
|
10248
|
+
() => {
|
|
10249
|
+
}
|
|
10250
|
+
);
|
|
10251
|
+
};
|
|
10168
10252
|
const activate = (r) => {
|
|
10169
10253
|
if (r.kind === "acct") {
|
|
10170
10254
|
setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
|
|
@@ -10172,6 +10256,9 @@ function SettingsPanel({
|
|
|
10172
10256
|
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
10173
10257
|
} else if (r.kind === "acct-add") {
|
|
10174
10258
|
beginLogin();
|
|
10259
|
+
} else if (r.kind === "self") {
|
|
10260
|
+
if (!selfProt) return;
|
|
10261
|
+
run12(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
10175
10262
|
} else if (r.kind === "ll-enabled") {
|
|
10176
10263
|
if (!local) return;
|
|
10177
10264
|
if (!local.enabled && !local.path.trim()) {
|
|
@@ -10194,13 +10281,12 @@ function SettingsPanel({
|
|
|
10194
10281
|
setInput("");
|
|
10195
10282
|
setEditing("wh-url");
|
|
10196
10283
|
} else if (r.kind === "alert") {
|
|
10197
|
-
|
|
10284
|
+
const ch = alertChannel(r.rule);
|
|
10285
|
+
if (ch) openAlertEditor(ch, r.rule);
|
|
10198
10286
|
} else if (r.kind === "alert-add-email") {
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
setInput("");
|
|
10203
|
-
setEditing("alert-tg");
|
|
10287
|
+
openAlertEditor("email");
|
|
10288
|
+
} else if (r.kind === "alert-add-tg") {
|
|
10289
|
+
openAlertEditor("telegram");
|
|
10204
10290
|
}
|
|
10205
10291
|
};
|
|
10206
10292
|
const submitInput = () => {
|
|
@@ -10218,22 +10304,8 @@ function SettingsPanel({
|
|
|
10218
10304
|
return;
|
|
10219
10305
|
}
|
|
10220
10306
|
run12("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
10221
|
-
} else if (which === "alert-
|
|
10222
|
-
|
|
10223
|
-
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "").trim();
|
|
10224
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
10225
|
-
setMsg({ text: "\u2717 that does not look like an e-mail address", level: "bad" });
|
|
10226
|
-
return;
|
|
10227
|
-
}
|
|
10228
|
-
run12("email alert added", () => api.settings.createAlert({ ...ALERT_BASE, emails: [email] }), alertQ.reload);
|
|
10229
|
-
} else if (which === "alert-tg") {
|
|
10230
|
-
if (!v) return;
|
|
10231
|
-
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "").trim();
|
|
10232
|
-
if (!/^-?\d{5,}$/.test(tg)) {
|
|
10233
|
-
setMsg({ text: "\u2717 a telegram chat id is a number \u2014 get yours from @userinfobot", level: "bad" });
|
|
10234
|
-
return;
|
|
10235
|
-
}
|
|
10236
|
-
run12("telegram alert added", () => api.settings.createAlert({ ...ALERT_BASE, telegram: [tg] }), alertQ.reload);
|
|
10307
|
+
} else if (which === "alert-target" && editor) {
|
|
10308
|
+
setEditor({ ...editor, target: v, field: 1 });
|
|
10237
10309
|
}
|
|
10238
10310
|
};
|
|
10239
10311
|
useInput6(
|
|
@@ -10245,6 +10317,35 @@ function SettingsPanel({
|
|
|
10245
10317
|
}
|
|
10246
10318
|
return;
|
|
10247
10319
|
}
|
|
10320
|
+
if (editor) {
|
|
10321
|
+
if (key.escape) {
|
|
10322
|
+
setEditor(null);
|
|
10323
|
+
return;
|
|
10324
|
+
}
|
|
10325
|
+
if (inp === "e" || key.return && editor.field === 0) {
|
|
10326
|
+
setInput(editor.target);
|
|
10327
|
+
setEditing("alert-target");
|
|
10328
|
+
return;
|
|
10329
|
+
}
|
|
10330
|
+
if (inp === "t" && editor.id) {
|
|
10331
|
+
const rule = alerts.find((a) => a.id === editor.id);
|
|
10332
|
+
if (rule) testAlert(rule);
|
|
10333
|
+
return;
|
|
10334
|
+
}
|
|
10335
|
+
if (key.return) {
|
|
10336
|
+
saveEditor();
|
|
10337
|
+
return;
|
|
10338
|
+
}
|
|
10339
|
+
if (key.upArrow) setEditor({ ...editor, field: (editor.field + EDITOR_FIELDS - 1) % EDITOR_FIELDS });
|
|
10340
|
+
else if (key.downArrow) setEditor({ ...editor, field: (editor.field + 1) % EDITOR_FIELDS });
|
|
10341
|
+
else if (key.leftArrow || key.rightArrow) {
|
|
10342
|
+
const d = key.rightArrow ? 1 : -1;
|
|
10343
|
+
if (editor.field === 1) setEditor({ ...editor, signal: SIGNALS2[(SIGNALS2.indexOf(editor.signal) + d + SIGNALS2.length) % SIGNALS2.length] });
|
|
10344
|
+
else if (editor.field === 2) setEditor({ ...editor, threshold: Math.max(THRESH_MIN, Math.min(THRESH_MAX, editor.threshold + d * 5)) });
|
|
10345
|
+
else if (editor.field === 3) setEditor({ ...editor, windowSeconds: WINDOWS[Math.max(0, Math.min(WINDOWS.length - 1, nearestWindowIdx(editor.windowSeconds) + d))] });
|
|
10346
|
+
}
|
|
10347
|
+
return;
|
|
10348
|
+
}
|
|
10248
10349
|
setMsg(null);
|
|
10249
10350
|
if (key.upArrow) {
|
|
10250
10351
|
setSel((n) => Math.max(0, n - 1));
|
|
@@ -10258,28 +10359,41 @@ function SettingsPanel({
|
|
|
10258
10359
|
const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
|
|
10259
10360
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
10260
10361
|
refreshAccounts();
|
|
10261
|
-
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "ll-enabled" || cur.kind === "ll-server")
|
|
10362
|
+
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
10363
|
+
if (cur.kind === "alert") run12(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
10364
|
+
else activate(cur);
|
|
10365
|
+
}
|
|
10366
|
+
} else if (inp === "x" && cur.kind === "acct") {
|
|
10367
|
+
const k = "acct:" + cur.acc.apiKey;
|
|
10368
|
+
if (confirmDel !== k) {
|
|
10369
|
+
setConfirmDel(k);
|
|
10370
|
+
setMsg({ text: `press x again to remove ${acctLabel(cur.acc)} from this device (the cloud account is untouched)`, level: "bad" });
|
|
10371
|
+
return;
|
|
10372
|
+
}
|
|
10373
|
+
setConfirmDel(null);
|
|
10374
|
+
removeAccount(cur.acc.apiKey);
|
|
10375
|
+
setMsg({ text: `\u2713 removed ${acctLabel(cur.acc)} from this device`, level: "ok" });
|
|
10376
|
+
refreshAccounts();
|
|
10262
10377
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
10263
|
-
run12(
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
);
|
|
10270
|
-
} else if (inp === "n") beginLogin();
|
|
10378
|
+
run12("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
10379
|
+
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
10380
|
+
}), whQ.reload);
|
|
10381
|
+
} else if (inp === "t" && cur.kind === "alert") {
|
|
10382
|
+
testAlert(cur.rule);
|
|
10383
|
+
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
10271
10384
|
else if (inp === "e" && cur.kind === "wh") {
|
|
10272
10385
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
10273
10386
|
run12(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
10274
|
-
} else if (inp === "e" && cur.kind === "
|
|
10387
|
+
} else if (inp === "e" && cur.kind === "alert") {
|
|
10388
|
+
const ch = alertChannel(cur.rule);
|
|
10389
|
+
if (ch) openAlertEditor(ch, cur.rule);
|
|
10390
|
+
} else if (inp === "n") beginLogin();
|
|
10275
10391
|
else if (inp === "a") {
|
|
10276
10392
|
if (cur.kind === "wh" || cur.kind === "wh-add") {
|
|
10277
10393
|
setInput("");
|
|
10278
10394
|
setEditing("wh-url");
|
|
10279
|
-
} else if (cur.kind === "alert
|
|
10280
|
-
|
|
10281
|
-
setEditing("alert-email");
|
|
10282
|
-
}
|
|
10395
|
+
} else if (cur.kind === "alert-add-email") openAlertEditor("email");
|
|
10396
|
+
else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
|
|
10283
10397
|
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
10284
10398
|
const k = keyOf(cur);
|
|
10285
10399
|
if (confirmDel !== k) {
|
|
@@ -10319,30 +10433,70 @@ function SettingsPanel({
|
|
|
10319
10433
|
] })
|
|
10320
10434
|
] });
|
|
10321
10435
|
}
|
|
10322
|
-
|
|
10323
|
-
|
|
10436
|
+
if (editor) {
|
|
10437
|
+
const fieldRow = (idx, label, value, hint) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10438
|
+
/* @__PURE__ */ jsx7(Text7, { color: editor.field === idx ? theme.accentBright : theme.dim, children: editor.field === idx ? "\u25B8 " : " " }),
|
|
10439
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(11) }),
|
|
10440
|
+
value,
|
|
10441
|
+
editor.field === idx && hint ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " + hint }) : null
|
|
10442
|
+
] });
|
|
10443
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
10444
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
10445
|
+
editor.id ? "Edit" : "New",
|
|
10446
|
+
" ",
|
|
10447
|
+
editor.channel,
|
|
10448
|
+
" alert"
|
|
10449
|
+
] }),
|
|
10450
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10451
|
+
"\u2191\u2193 field \xB7 \u2190\u2192 change \xB7 e edit target \xB7 enter save",
|
|
10452
|
+
editor.id ? " \xB7 t test" : "",
|
|
10453
|
+
" \xB7 esc cancel"
|
|
10454
|
+
] }),
|
|
10455
|
+
editing === "alert-target" ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
10456
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
10457
|
+
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
10458
|
+
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
10459
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
10460
|
+
fieldRow(0, "target", editor.target ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(editor.target, cols - 16) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "empty \u2014 press e" }), "press e to edit"),
|
|
10461
|
+
fieldRow(1, "signal", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }), "\u2190\u2192 change"),
|
|
10462
|
+
fieldRow(2, "threshold", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: `\u2265 ${editor.threshold}` }), "\u2190\u2192 \xB15"),
|
|
10463
|
+
fieldRow(3, "window", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) }), "\u2190\u2192 change")
|
|
10464
|
+
] }),
|
|
10465
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10466
|
+
"fires when ",
|
|
10467
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
|
|
10468
|
+
" reach ",
|
|
10469
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: editor.threshold }),
|
|
10470
|
+
" within",
|
|
10471
|
+
" ",
|
|
10472
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) })
|
|
10473
|
+
] }) })
|
|
10474
|
+
] });
|
|
10475
|
+
}
|
|
10476
|
+
const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
|
|
10477
|
+
const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
|
|
10324
10478
|
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
10325
10479
|
const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
|
|
10326
10480
|
const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
10327
|
-
const listBudget = Math.max(4, rows -
|
|
10481
|
+
const listBudget = Math.max(4, rows - 12);
|
|
10328
10482
|
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
10329
10483
|
const inWindow = (r) => {
|
|
10330
10484
|
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
10331
10485
|
return i >= start && i < start + listBudget;
|
|
10332
10486
|
};
|
|
10333
10487
|
return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
10334
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter
|
|
10488
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter act \xB7 m toggle \xB7 t test \xB7 e edit \xB7 x remove acct \xB7 d delete \xB7 n add acct \xB7 r refresh" : "press \u2192 to configure" }),
|
|
10335
10489
|
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10336
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " :
|
|
10490
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
10337
10491
|
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
10338
10492
|
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
10339
10493
|
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
10340
10494
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
10341
10495
|
"ACCOUNTS ",
|
|
10342
10496
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10343
|
-
"\u2014
|
|
10497
|
+
"\u2014 on this device (",
|
|
10344
10498
|
accounts.length,
|
|
10345
|
-
") \xB7 \u25CF viewing
|
|
10499
|
+
") \xB7 \u25CF viewing \xB7 ACTIVE = key the guard uses \xB7 x removes"
|
|
10346
10500
|
] })
|
|
10347
10501
|
] }),
|
|
10348
10502
|
accounts.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
@@ -10358,7 +10512,7 @@ function SettingsPanel({
|
|
|
10358
10512
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(acctLabel(a), 30).padEnd(31) }),
|
|
10359
10513
|
isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
10360
10514
|
isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
10361
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate2(a.project,
|
|
10515
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate2(a.project, 20) : "" })
|
|
10362
10516
|
] }, a.apiKey);
|
|
10363
10517
|
}),
|
|
10364
10518
|
inWindow({ kind: "acct-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
@@ -10367,28 +10521,49 @@ function SettingsPanel({
|
|
|
10367
10521
|
] }) : null
|
|
10368
10522
|
] }),
|
|
10369
10523
|
locked ? null : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
10524
|
+
inWindow({ kind: "guard" }) || inWindow({ kind: "self" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
10525
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
10526
|
+
"PROTECTION ",
|
|
10527
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 the guard hook enforcing every layer on this project" })
|
|
10528
|
+
] }),
|
|
10529
|
+
inWindow({ kind: "guard" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10530
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "guard" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "guard" }) }),
|
|
10531
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
10532
|
+
guard ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
10533
|
+
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
10534
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available` }),
|
|
10535
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""}` })
|
|
10536
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
10537
|
+
] }) : null,
|
|
10538
|
+
inWindow({ kind: "self" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10539
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "self" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "self" }) }),
|
|
10540
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "self-prot".padEnd(11) }),
|
|
10541
|
+
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2026" }),
|
|
10542
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " blocks agents from editing SolonGate\u2019s own hooks/config \xB7 enter toggles" })
|
|
10543
|
+
] }) : null
|
|
10544
|
+
] }) : null,
|
|
10370
10545
|
inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) || inWindow({ kind: "ll-server" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
10371
10546
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
10372
10547
|
"LOCAL LOGS ",
|
|
10373
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on
|
|
10548
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on this machine" })
|
|
10374
10549
|
] }),
|
|
10375
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10550
|
+
inWindow({ kind: "ll-enabled" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10376
10551
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-enabled" }) }),
|
|
10377
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(
|
|
10552
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(11) }),
|
|
10378
10553
|
onOff(!!local?.enabled),
|
|
10379
10554
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
|
|
10380
|
-
] }),
|
|
10381
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10555
|
+
] }) : null,
|
|
10556
|
+
inWindow({ kind: "ll-path" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10382
10557
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-path" }) }),
|
|
10383
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(
|
|
10558
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(11) }),
|
|
10384
10559
|
local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
10385
|
-
] }),
|
|
10386
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10560
|
+
] }) : null,
|
|
10561
|
+
inWindow({ kind: "ll-server" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10387
10562
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-server" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-server" }) }),
|
|
10388
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(
|
|
10563
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(11) }),
|
|
10389
10564
|
srv.running ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: `running 127.0.0.1:${srv.port}` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "stopped" }),
|
|
10390
10565
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: srv.running ? " serves local logs to the dashboard \xB7 survives closing the dataroom \xB7 enter stops" : " enter starts the local-logs link for the dashboard" })
|
|
10391
|
-
] })
|
|
10566
|
+
] }) : null
|
|
10392
10567
|
] }) : null,
|
|
10393
10568
|
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
10394
10569
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
@@ -10396,7 +10571,7 @@ function SettingsPanel({
|
|
|
10396
10571
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10397
10572
|
"\u2014 POST every matching event to your endpoint (",
|
|
10398
10573
|
webhooks.length,
|
|
10399
|
-
")"
|
|
10574
|
+
") \xB7 t tests"
|
|
10400
10575
|
] })
|
|
10401
10576
|
] }),
|
|
10402
10577
|
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
@@ -10414,17 +10589,17 @@ function SettingsPanel({
|
|
|
10414
10589
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
10415
10590
|
"ALERTS ",
|
|
10416
10591
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10417
|
-
"\u2014
|
|
10592
|
+
"\u2014 spike alerts to one email + one telegram (",
|
|
10418
10593
|
alerts.length,
|
|
10419
|
-
")"
|
|
10594
|
+
") \xB7 enter edits \xB7 t tests"
|
|
10420
10595
|
] })
|
|
10421
10596
|
] }),
|
|
10422
10597
|
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10423
10598
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
10424
10599
|
onOff(rule.enabled),
|
|
10425
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(
|
|
10426
|
-
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}
|
|
10427
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols -
|
|
10600
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + SIGNAL_LABEL[rule.signal]).padEnd(13) }),
|
|
10601
|
+
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${winLabel(rule.windowSeconds)} `.padEnd(11) }),
|
|
10602
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols - 34) })
|
|
10428
10603
|
] }, rule.id)),
|
|
10429
10604
|
inWindow({ kind: "alert-add-email" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
10430
10605
|
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add-email" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add-email" }) }),
|
|
@@ -10432,13 +10607,14 @@ function SettingsPanel({
|
|
|
10432
10607
|
] }) : null,
|
|
10433
10608
|
inWindow({ kind: "alert-add-tg" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
10434
10609
|
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add-tg" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add-tg" }) }),
|
|
10435
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id
|
|
10436
|
-
] }) : null
|
|
10610
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id from @userinfobot)" })
|
|
10611
|
+
] }) : null,
|
|
10612
|
+
hasEmailAlert && hasTgAlert ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " both channels in use \u2014 remove one (d) to change it" }) : null
|
|
10437
10613
|
] })
|
|
10438
10614
|
] })
|
|
10439
10615
|
] }) });
|
|
10440
10616
|
}
|
|
10441
|
-
var EVENTS, SPIN2,
|
|
10617
|
+
var EVENTS, SPIN2, SIGNALS2, SIGNAL_LABEL, WINDOWS, winLabel, THRESH_MIN, THRESH_MAX, nearestWindowIdx, EDITOR_FIELDS, acctLabel, alertChannel;
|
|
10442
10618
|
var init_Settings = __esm({
|
|
10443
10619
|
"src/tui/panels/Settings.tsx"() {
|
|
10444
10620
|
"use strict";
|
|
@@ -10451,8 +10627,20 @@ var init_Settings = __esm({
|
|
|
10451
10627
|
init_theme();
|
|
10452
10628
|
EVENTS = ["denials", "allowed", "all"];
|
|
10453
10629
|
SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
10454
|
-
|
|
10630
|
+
SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
10631
|
+
SIGNAL_LABEL = { any: "any signal", deny: "denials", dlp: "dlp secrets", ratelimit: "rate-limit" };
|
|
10632
|
+
WINDOWS = [30, 60, 300, 3600, 86400];
|
|
10633
|
+
winLabel = (s) => s < 60 ? `${s}s` : s < 3600 ? `${s / 60}m` : s < 86400 ? `${s / 3600}h` : `${s / 86400}d`;
|
|
10634
|
+
THRESH_MIN = 5;
|
|
10635
|
+
THRESH_MAX = 100;
|
|
10636
|
+
nearestWindowIdx = (s) => {
|
|
10637
|
+
let best = 0;
|
|
10638
|
+
for (let i = 1; i < WINDOWS.length; i++) if (Math.abs(WINDOWS[i] - s) < Math.abs(WINDOWS[best] - s)) best = i;
|
|
10639
|
+
return best;
|
|
10640
|
+
};
|
|
10641
|
+
EDITOR_FIELDS = 4;
|
|
10455
10642
|
acctLabel = (a) => a.email || a.user || "account \u2026" + a.apiKey.slice(-4);
|
|
10643
|
+
alertChannel = (r) => r.emails && r.emails.length ? "email" : r.telegram && r.telegram.length ? "telegram" : null;
|
|
10456
10644
|
}
|
|
10457
10645
|
});
|
|
10458
10646
|
|
package/dist/tui/index.js
CHANGED
|
@@ -283,6 +283,20 @@ function saveAccount(acc) {
|
|
|
283
283
|
} catch {
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
+
function removeAccount(apiKey) {
|
|
287
|
+
try {
|
|
288
|
+
const list5 = (() => {
|
|
289
|
+
try {
|
|
290
|
+
const raw = JSON.parse(readFileSync3(accountsFile(), "utf-8"));
|
|
291
|
+
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
292
|
+
} catch {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
})();
|
|
296
|
+
writeFileSync2(accountsFile(), JSON.stringify(list5.filter((a) => a.apiKey !== apiKey), null, 2));
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
}
|
|
286
300
|
var viewOverride = null;
|
|
287
301
|
function setViewCredentials(creds) {
|
|
288
302
|
viewOverride = creds;
|
|
@@ -550,11 +564,13 @@ __export(settings_exports, {
|
|
|
550
564
|
getSecurityLayers: () => getSecurityLayers,
|
|
551
565
|
getSelfProtection: () => getSelfProtection,
|
|
552
566
|
getWebhooks: () => getWebhooks,
|
|
567
|
+
sendTestAlert: () => sendTestAlert,
|
|
553
568
|
sendTestWebhook: () => sendTestWebhook,
|
|
554
569
|
setAlertEnabled: () => setAlertEnabled,
|
|
555
570
|
setLocalLogs: () => setLocalLogs,
|
|
556
571
|
setSecurityLayers: () => setSecurityLayers,
|
|
557
572
|
setSelfProtection: () => setSelfProtection,
|
|
573
|
+
updateAlert: () => updateAlert,
|
|
558
574
|
updateWebhook: () => updateWebhook
|
|
559
575
|
});
|
|
560
576
|
function getSecurityLayers() {
|
|
@@ -596,6 +612,12 @@ function deleteAlert(id) {
|
|
|
596
612
|
function setAlertEnabled(id, enabled) {
|
|
597
613
|
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: { enabled } });
|
|
598
614
|
}
|
|
615
|
+
function updateAlert(id, patch) {
|
|
616
|
+
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: patch });
|
|
617
|
+
}
|
|
618
|
+
function sendTestAlert(id) {
|
|
619
|
+
return request("POST", "/settings/denial-alerts/send-test", { body: { id } });
|
|
620
|
+
}
|
|
599
621
|
function getWebhooks() {
|
|
600
622
|
return request("GET", "/settings/denial-webhook");
|
|
601
623
|
}
|
|
@@ -3175,8 +3197,20 @@ function stopLogsServerDaemon() {
|
|
|
3175
3197
|
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3176
3198
|
var EVENTS = ["denials", "allowed", "all"];
|
|
3177
3199
|
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3178
|
-
var
|
|
3200
|
+
var SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
3201
|
+
var SIGNAL_LABEL = { any: "any signal", deny: "denials", dlp: "dlp secrets", ratelimit: "rate-limit" };
|
|
3202
|
+
var WINDOWS = [30, 60, 300, 3600, 86400];
|
|
3203
|
+
var winLabel = (s) => s < 60 ? `${s}s` : s < 3600 ? `${s / 60}m` : s < 86400 ? `${s / 3600}h` : `${s / 86400}d`;
|
|
3204
|
+
var THRESH_MIN = 5;
|
|
3205
|
+
var THRESH_MAX = 100;
|
|
3206
|
+
var nearestWindowIdx = (s) => {
|
|
3207
|
+
let best = 0;
|
|
3208
|
+
for (let i = 1; i < WINDOWS.length; i++) if (Math.abs(WINDOWS[i] - s) < Math.abs(WINDOWS[best] - s)) best = i;
|
|
3209
|
+
return best;
|
|
3210
|
+
};
|
|
3211
|
+
var EDITOR_FIELDS = 4;
|
|
3179
3212
|
var acctLabel = (a) => a.email || a.user || "account \u2026" + a.apiKey.slice(-4);
|
|
3213
|
+
var alertChannel = (r) => r.emails && r.emails.length ? "email" : r.telegram && r.telegram.length ? "telegram" : null;
|
|
3180
3214
|
function SettingsPanel({
|
|
3181
3215
|
active: active2,
|
|
3182
3216
|
focused,
|
|
@@ -3191,6 +3225,7 @@ function SettingsPanel({
|
|
|
3191
3225
|
const [confirmDel, setConfirmDel] = useState7(null);
|
|
3192
3226
|
const [msg, setMsg] = useState7(null);
|
|
3193
3227
|
const [busy, setBusy] = useState7(false);
|
|
3228
|
+
const [editor, setEditor] = useState7(null);
|
|
3194
3229
|
const [accounts, setAccounts] = useState7(() => listAccounts());
|
|
3195
3230
|
const [login, setLogin] = useState7(null);
|
|
3196
3231
|
const [tick, setTick] = useState7(0);
|
|
@@ -3210,22 +3245,30 @@ function SettingsPanel({
|
|
|
3210
3245
|
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
3211
3246
|
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
3212
3247
|
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
3248
|
+
const guardQ = useLoader(() => listAccounts().length ? api.settings.getGuardStatus() : Promise.resolve(null));
|
|
3249
|
+
const selfQ = useLoader(() => listAccounts().length ? api.settings.getSelfProtection() : Promise.resolve(null));
|
|
3213
3250
|
const local = localQ.data;
|
|
3251
|
+
const guard = guardQ.data;
|
|
3252
|
+
const selfProt = selfQ.data;
|
|
3214
3253
|
const [hidden, setHidden] = useState7(/* @__PURE__ */ new Set());
|
|
3215
3254
|
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
3216
3255
|
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
3256
|
+
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
3257
|
+
const hasTgAlert = alerts.some((r) => alertChannel(r) === "telegram");
|
|
3217
3258
|
const rowsAll = [
|
|
3218
3259
|
...accounts.map((acc) => ({ kind: "acct", acc })),
|
|
3219
3260
|
{ kind: "acct-add" },
|
|
3220
3261
|
...locked ? [] : [
|
|
3262
|
+
{ kind: "guard" },
|
|
3263
|
+
{ kind: "self" },
|
|
3221
3264
|
{ kind: "ll-enabled" },
|
|
3222
3265
|
{ kind: "ll-path" },
|
|
3223
3266
|
{ kind: "ll-server" },
|
|
3224
3267
|
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
3225
3268
|
{ kind: "wh-add" },
|
|
3226
3269
|
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
3227
|
-
{ kind: "alert-add-email" },
|
|
3228
|
-
{ kind: "alert-add-tg" }
|
|
3270
|
+
...hasEmailAlert ? [] : [{ kind: "alert-add-email" }],
|
|
3271
|
+
...hasTgAlert ? [] : [{ kind: "alert-add-tg" }]
|
|
3229
3272
|
]
|
|
3230
3273
|
];
|
|
3231
3274
|
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
@@ -3236,6 +3279,8 @@ function SettingsPanel({
|
|
|
3236
3279
|
localQ.reload();
|
|
3237
3280
|
whQ.reload();
|
|
3238
3281
|
alertQ.reload();
|
|
3282
|
+
guardQ.reload();
|
|
3283
|
+
selfQ.reload();
|
|
3239
3284
|
};
|
|
3240
3285
|
const run = (label, fn, reload) => {
|
|
3241
3286
|
if (busy) return;
|
|
@@ -3280,6 +3325,57 @@ function SettingsPanel({
|
|
|
3280
3325
|
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
3281
3326
|
})();
|
|
3282
3327
|
};
|
|
3328
|
+
const openAlertEditor = (channel, rule) => {
|
|
3329
|
+
setEditor({
|
|
3330
|
+
id: rule?.id,
|
|
3331
|
+
channel,
|
|
3332
|
+
target: (channel === "email" ? rule?.emails?.[0] : rule?.telegram?.[0]) ?? "",
|
|
3333
|
+
signal: rule?.signal ?? "any",
|
|
3334
|
+
threshold: rule?.threshold ?? THRESH_MIN,
|
|
3335
|
+
windowSeconds: rule?.windowSeconds ?? 300,
|
|
3336
|
+
field: rule ? 1 : 0
|
|
3337
|
+
// new rule starts on the target; existing on signal
|
|
3338
|
+
});
|
|
3339
|
+
if (!rule) {
|
|
3340
|
+
setInput("");
|
|
3341
|
+
setEditing("alert-target");
|
|
3342
|
+
}
|
|
3343
|
+
};
|
|
3344
|
+
const normTarget = (channel, raw) => {
|
|
3345
|
+
const v = raw.trim();
|
|
3346
|
+
if (channel === "email") {
|
|
3347
|
+
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "");
|
|
3348
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return { value: email, error: "that does not look like an e-mail address" };
|
|
3349
|
+
return { value: email };
|
|
3350
|
+
}
|
|
3351
|
+
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "");
|
|
3352
|
+
if (!/^-?\d{5,}$/.test(tg)) return { value: tg, error: "a telegram chat id is a number \u2014 get yours from @userinfobot" };
|
|
3353
|
+
return { value: tg };
|
|
3354
|
+
};
|
|
3355
|
+
const saveEditor = () => {
|
|
3356
|
+
if (!editor) return;
|
|
3357
|
+
const t = normTarget(editor.channel, editor.target);
|
|
3358
|
+
if (t.error) {
|
|
3359
|
+
setMsg({ text: "\u2717 " + t.error, level: "bad" });
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
const channels = editor.channel === "email" ? { emails: [t.value], telegram: [] } : { telegram: [t.value], emails: [] };
|
|
3363
|
+
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, ...channels };
|
|
3364
|
+
const id = editor.id;
|
|
3365
|
+
setEditor(null);
|
|
3366
|
+
if (id) run("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
3367
|
+
else run(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "dataroom alert", ...body }), alertQ.reload);
|
|
3368
|
+
};
|
|
3369
|
+
const testAlert = (rule) => {
|
|
3370
|
+
run(
|
|
3371
|
+
"alert test sent \u2014 check your " + (alertChannel(rule) ?? "channel"),
|
|
3372
|
+
() => api.settings.sendTestAlert(rule.id).then((r) => {
|
|
3373
|
+
if (!r.delivered.telegram && !r.delivered.email) throw new Error("no channel on this rule");
|
|
3374
|
+
}),
|
|
3375
|
+
() => {
|
|
3376
|
+
}
|
|
3377
|
+
);
|
|
3378
|
+
};
|
|
3283
3379
|
const activate = (r) => {
|
|
3284
3380
|
if (r.kind === "acct") {
|
|
3285
3381
|
setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
|
|
@@ -3287,6 +3383,9 @@ function SettingsPanel({
|
|
|
3287
3383
|
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
3288
3384
|
} else if (r.kind === "acct-add") {
|
|
3289
3385
|
beginLogin();
|
|
3386
|
+
} else if (r.kind === "self") {
|
|
3387
|
+
if (!selfProt) return;
|
|
3388
|
+
run(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
3290
3389
|
} else if (r.kind === "ll-enabled") {
|
|
3291
3390
|
if (!local) return;
|
|
3292
3391
|
if (!local.enabled && !local.path.trim()) {
|
|
@@ -3309,13 +3408,12 @@ function SettingsPanel({
|
|
|
3309
3408
|
setInput("");
|
|
3310
3409
|
setEditing("wh-url");
|
|
3311
3410
|
} else if (r.kind === "alert") {
|
|
3312
|
-
|
|
3411
|
+
const ch = alertChannel(r.rule);
|
|
3412
|
+
if (ch) openAlertEditor(ch, r.rule);
|
|
3313
3413
|
} else if (r.kind === "alert-add-email") {
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
setInput("");
|
|
3318
|
-
setEditing("alert-tg");
|
|
3414
|
+
openAlertEditor("email");
|
|
3415
|
+
} else if (r.kind === "alert-add-tg") {
|
|
3416
|
+
openAlertEditor("telegram");
|
|
3319
3417
|
}
|
|
3320
3418
|
};
|
|
3321
3419
|
const submitInput = () => {
|
|
@@ -3333,22 +3431,8 @@ function SettingsPanel({
|
|
|
3333
3431
|
return;
|
|
3334
3432
|
}
|
|
3335
3433
|
run("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
3336
|
-
} else if (which === "alert-
|
|
3337
|
-
|
|
3338
|
-
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "").trim();
|
|
3339
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
3340
|
-
setMsg({ text: "\u2717 that does not look like an e-mail address", level: "bad" });
|
|
3341
|
-
return;
|
|
3342
|
-
}
|
|
3343
|
-
run("email alert added", () => api.settings.createAlert({ ...ALERT_BASE, emails: [email] }), alertQ.reload);
|
|
3344
|
-
} else if (which === "alert-tg") {
|
|
3345
|
-
if (!v) return;
|
|
3346
|
-
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "").trim();
|
|
3347
|
-
if (!/^-?\d{5,}$/.test(tg)) {
|
|
3348
|
-
setMsg({ text: "\u2717 a telegram chat id is a number \u2014 get yours from @userinfobot", level: "bad" });
|
|
3349
|
-
return;
|
|
3350
|
-
}
|
|
3351
|
-
run("telegram alert added", () => api.settings.createAlert({ ...ALERT_BASE, telegram: [tg] }), alertQ.reload);
|
|
3434
|
+
} else if (which === "alert-target" && editor) {
|
|
3435
|
+
setEditor({ ...editor, target: v, field: 1 });
|
|
3352
3436
|
}
|
|
3353
3437
|
};
|
|
3354
3438
|
useInput6(
|
|
@@ -3360,6 +3444,35 @@ function SettingsPanel({
|
|
|
3360
3444
|
}
|
|
3361
3445
|
return;
|
|
3362
3446
|
}
|
|
3447
|
+
if (editor) {
|
|
3448
|
+
if (key.escape) {
|
|
3449
|
+
setEditor(null);
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
if (inp === "e" || key.return && editor.field === 0) {
|
|
3453
|
+
setInput(editor.target);
|
|
3454
|
+
setEditing("alert-target");
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3457
|
+
if (inp === "t" && editor.id) {
|
|
3458
|
+
const rule = alerts.find((a) => a.id === editor.id);
|
|
3459
|
+
if (rule) testAlert(rule);
|
|
3460
|
+
return;
|
|
3461
|
+
}
|
|
3462
|
+
if (key.return) {
|
|
3463
|
+
saveEditor();
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
if (key.upArrow) setEditor({ ...editor, field: (editor.field + EDITOR_FIELDS - 1) % EDITOR_FIELDS });
|
|
3467
|
+
else if (key.downArrow) setEditor({ ...editor, field: (editor.field + 1) % EDITOR_FIELDS });
|
|
3468
|
+
else if (key.leftArrow || key.rightArrow) {
|
|
3469
|
+
const d = key.rightArrow ? 1 : -1;
|
|
3470
|
+
if (editor.field === 1) setEditor({ ...editor, signal: SIGNALS2[(SIGNALS2.indexOf(editor.signal) + d + SIGNALS2.length) % SIGNALS2.length] });
|
|
3471
|
+
else if (editor.field === 2) setEditor({ ...editor, threshold: Math.max(THRESH_MIN, Math.min(THRESH_MAX, editor.threshold + d * 5)) });
|
|
3472
|
+
else if (editor.field === 3) setEditor({ ...editor, windowSeconds: WINDOWS[Math.max(0, Math.min(WINDOWS.length - 1, nearestWindowIdx(editor.windowSeconds) + d))] });
|
|
3473
|
+
}
|
|
3474
|
+
return;
|
|
3475
|
+
}
|
|
3363
3476
|
setMsg(null);
|
|
3364
3477
|
if (key.upArrow) {
|
|
3365
3478
|
setSel((n) => Math.max(0, n - 1));
|
|
@@ -3373,28 +3486,41 @@ function SettingsPanel({
|
|
|
3373
3486
|
const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
|
|
3374
3487
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
3375
3488
|
refreshAccounts();
|
|
3376
|
-
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "ll-enabled" || cur.kind === "ll-server")
|
|
3489
|
+
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
3490
|
+
if (cur.kind === "alert") run(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
3491
|
+
else activate(cur);
|
|
3492
|
+
}
|
|
3493
|
+
} else if (inp === "x" && cur.kind === "acct") {
|
|
3494
|
+
const k = "acct:" + cur.acc.apiKey;
|
|
3495
|
+
if (confirmDel !== k) {
|
|
3496
|
+
setConfirmDel(k);
|
|
3497
|
+
setMsg({ text: `press x again to remove ${acctLabel(cur.acc)} from this device (the cloud account is untouched)`, level: "bad" });
|
|
3498
|
+
return;
|
|
3499
|
+
}
|
|
3500
|
+
setConfirmDel(null);
|
|
3501
|
+
removeAccount(cur.acc.apiKey);
|
|
3502
|
+
setMsg({ text: `\u2713 removed ${acctLabel(cur.acc)} from this device`, level: "ok" });
|
|
3503
|
+
refreshAccounts();
|
|
3377
3504
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
3378
|
-
run(
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
);
|
|
3385
|
-
} else if (inp === "n") beginLogin();
|
|
3505
|
+
run("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
3506
|
+
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
3507
|
+
}), whQ.reload);
|
|
3508
|
+
} else if (inp === "t" && cur.kind === "alert") {
|
|
3509
|
+
testAlert(cur.rule);
|
|
3510
|
+
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
3386
3511
|
else if (inp === "e" && cur.kind === "wh") {
|
|
3387
3512
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
3388
3513
|
run(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
3389
|
-
} else if (inp === "e" && cur.kind === "
|
|
3514
|
+
} else if (inp === "e" && cur.kind === "alert") {
|
|
3515
|
+
const ch = alertChannel(cur.rule);
|
|
3516
|
+
if (ch) openAlertEditor(ch, cur.rule);
|
|
3517
|
+
} else if (inp === "n") beginLogin();
|
|
3390
3518
|
else if (inp === "a") {
|
|
3391
3519
|
if (cur.kind === "wh" || cur.kind === "wh-add") {
|
|
3392
3520
|
setInput("");
|
|
3393
3521
|
setEditing("wh-url");
|
|
3394
|
-
} else if (cur.kind === "alert
|
|
3395
|
-
|
|
3396
|
-
setEditing("alert-email");
|
|
3397
|
-
}
|
|
3522
|
+
} else if (cur.kind === "alert-add-email") openAlertEditor("email");
|
|
3523
|
+
else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
|
|
3398
3524
|
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
3399
3525
|
const k = keyOf(cur);
|
|
3400
3526
|
if (confirmDel !== k) {
|
|
@@ -3434,30 +3560,70 @@ function SettingsPanel({
|
|
|
3434
3560
|
] })
|
|
3435
3561
|
] });
|
|
3436
3562
|
}
|
|
3437
|
-
|
|
3438
|
-
|
|
3563
|
+
if (editor) {
|
|
3564
|
+
const fieldRow = (idx, label, value, hint) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3565
|
+
/* @__PURE__ */ jsx7(Text7, { color: editor.field === idx ? theme.accentBright : theme.dim, children: editor.field === idx ? "\u25B8 " : " " }),
|
|
3566
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(11) }),
|
|
3567
|
+
value,
|
|
3568
|
+
editor.field === idx && hint ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " + hint }) : null
|
|
3569
|
+
] });
|
|
3570
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3571
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3572
|
+
editor.id ? "Edit" : "New",
|
|
3573
|
+
" ",
|
|
3574
|
+
editor.channel,
|
|
3575
|
+
" alert"
|
|
3576
|
+
] }),
|
|
3577
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3578
|
+
"\u2191\u2193 field \xB7 \u2190\u2192 change \xB7 e edit target \xB7 enter save",
|
|
3579
|
+
editor.id ? " \xB7 t test" : "",
|
|
3580
|
+
" \xB7 esc cancel"
|
|
3581
|
+
] }),
|
|
3582
|
+
editing === "alert-target" ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
3583
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
3584
|
+
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
3585
|
+
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
3586
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3587
|
+
fieldRow(0, "target", editor.target ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(editor.target, cols - 16) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "empty \u2014 press e" }), "press e to edit"),
|
|
3588
|
+
fieldRow(1, "signal", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }), "\u2190\u2192 change"),
|
|
3589
|
+
fieldRow(2, "threshold", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: `\u2265 ${editor.threshold}` }), "\u2190\u2192 \xB15"),
|
|
3590
|
+
fieldRow(3, "window", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) }), "\u2190\u2192 change")
|
|
3591
|
+
] }),
|
|
3592
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3593
|
+
"fires when ",
|
|
3594
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
|
|
3595
|
+
" reach ",
|
|
3596
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: editor.threshold }),
|
|
3597
|
+
" within",
|
|
3598
|
+
" ",
|
|
3599
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) })
|
|
3600
|
+
] }) })
|
|
3601
|
+
] });
|
|
3602
|
+
}
|
|
3603
|
+
const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
|
|
3604
|
+
const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
|
|
3439
3605
|
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
3440
3606
|
const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
|
|
3441
3607
|
const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
3442
|
-
const listBudget = Math.max(4, rows -
|
|
3608
|
+
const listBudget = Math.max(4, rows - 12);
|
|
3443
3609
|
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
3444
3610
|
const inWindow = (r) => {
|
|
3445
3611
|
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
3446
3612
|
return i >= start && i < start + listBudget;
|
|
3447
3613
|
};
|
|
3448
3614
|
return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3449
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter
|
|
3615
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter act \xB7 m toggle \xB7 t test \xB7 e edit \xB7 x remove acct \xB7 d delete \xB7 n add acct \xB7 r refresh" : "press \u2192 to configure" }),
|
|
3450
3616
|
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3451
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " :
|
|
3617
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
3452
3618
|
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
3453
3619
|
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
3454
3620
|
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3455
3621
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3456
3622
|
"ACCOUNTS ",
|
|
3457
3623
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3458
|
-
"\u2014
|
|
3624
|
+
"\u2014 on this device (",
|
|
3459
3625
|
accounts.length,
|
|
3460
|
-
") \xB7 \u25CF viewing
|
|
3626
|
+
") \xB7 \u25CF viewing \xB7 ACTIVE = key the guard uses \xB7 x removes"
|
|
3461
3627
|
] })
|
|
3462
3628
|
] }),
|
|
3463
3629
|
accounts.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
@@ -3473,7 +3639,7 @@ function SettingsPanel({
|
|
|
3473
3639
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(acctLabel(a), 30).padEnd(31) }),
|
|
3474
3640
|
isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
3475
3641
|
isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
3476
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate(a.project,
|
|
3642
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate(a.project, 20) : "" })
|
|
3477
3643
|
] }, a.apiKey);
|
|
3478
3644
|
}),
|
|
3479
3645
|
inWindow({ kind: "acct-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
@@ -3482,28 +3648,49 @@ function SettingsPanel({
|
|
|
3482
3648
|
] }) : null
|
|
3483
3649
|
] }),
|
|
3484
3650
|
locked ? null : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3651
|
+
inWindow({ kind: "guard" }) || inWindow({ kind: "self" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3652
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3653
|
+
"PROTECTION ",
|
|
3654
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 the guard hook enforcing every layer on this project" })
|
|
3655
|
+
] }),
|
|
3656
|
+
inWindow({ kind: "guard" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3657
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "guard" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "guard" }) }),
|
|
3658
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
3659
|
+
guard ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3660
|
+
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
3661
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available` }),
|
|
3662
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""}` })
|
|
3663
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
3664
|
+
] }) : null,
|
|
3665
|
+
inWindow({ kind: "self" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3666
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "self" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "self" }) }),
|
|
3667
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "self-prot".padEnd(11) }),
|
|
3668
|
+
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2026" }),
|
|
3669
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " blocks agents from editing SolonGate\u2019s own hooks/config \xB7 enter toggles" })
|
|
3670
|
+
] }) : null
|
|
3671
|
+
] }) : null,
|
|
3485
3672
|
inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) || inWindow({ kind: "ll-server" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3486
3673
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3487
3674
|
"LOCAL LOGS ",
|
|
3488
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on
|
|
3675
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on this machine" })
|
|
3489
3676
|
] }),
|
|
3490
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3677
|
+
inWindow({ kind: "ll-enabled" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3491
3678
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-enabled" }) }),
|
|
3492
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(
|
|
3679
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(11) }),
|
|
3493
3680
|
onOff(!!local?.enabled),
|
|
3494
3681
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
|
|
3495
|
-
] }),
|
|
3496
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3682
|
+
] }) : null,
|
|
3683
|
+
inWindow({ kind: "ll-path" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3497
3684
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-path" }) }),
|
|
3498
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(
|
|
3685
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(11) }),
|
|
3499
3686
|
local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
3500
|
-
] }),
|
|
3501
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3687
|
+
] }) : null,
|
|
3688
|
+
inWindow({ kind: "ll-server" }) ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3502
3689
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-server" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-server" }) }),
|
|
3503
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(
|
|
3690
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(11) }),
|
|
3504
3691
|
srv.running ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: `running 127.0.0.1:${srv.port}` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "stopped" }),
|
|
3505
3692
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: srv.running ? " serves local logs to the dashboard \xB7 survives closing the dataroom \xB7 enter stops" : " enter starts the local-logs link for the dashboard" })
|
|
3506
|
-
] })
|
|
3693
|
+
] }) : null
|
|
3507
3694
|
] }) : null,
|
|
3508
3695
|
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3509
3696
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
@@ -3511,7 +3698,7 @@ function SettingsPanel({
|
|
|
3511
3698
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3512
3699
|
"\u2014 POST every matching event to your endpoint (",
|
|
3513
3700
|
webhooks.length,
|
|
3514
|
-
")"
|
|
3701
|
+
") \xB7 t tests"
|
|
3515
3702
|
] })
|
|
3516
3703
|
] }),
|
|
3517
3704
|
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
@@ -3529,17 +3716,17 @@ function SettingsPanel({
|
|
|
3529
3716
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3530
3717
|
"ALERTS ",
|
|
3531
3718
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3532
|
-
"\u2014
|
|
3719
|
+
"\u2014 spike alerts to one email + one telegram (",
|
|
3533
3720
|
alerts.length,
|
|
3534
|
-
")"
|
|
3721
|
+
") \xB7 enter edits \xB7 t tests"
|
|
3535
3722
|
] })
|
|
3536
3723
|
] }),
|
|
3537
3724
|
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3538
3725
|
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
3539
3726
|
onOff(rule.enabled),
|
|
3540
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(
|
|
3541
|
-
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}
|
|
3542
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(chanOf(rule), cols -
|
|
3727
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + SIGNAL_LABEL[rule.signal]).padEnd(13) }),
|
|
3728
|
+
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${winLabel(rule.windowSeconds)} `.padEnd(11) }),
|
|
3729
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(chanOf(rule), cols - 34) })
|
|
3543
3730
|
] }, rule.id)),
|
|
3544
3731
|
inWindow({ kind: "alert-add-email" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3545
3732
|
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add-email" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add-email" }) }),
|
|
@@ -3547,8 +3734,9 @@ function SettingsPanel({
|
|
|
3547
3734
|
] }) : null,
|
|
3548
3735
|
inWindow({ kind: "alert-add-tg" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3549
3736
|
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add-tg" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add-tg" }) }),
|
|
3550
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id
|
|
3551
|
-
] }) : null
|
|
3737
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id from @userinfobot)" })
|
|
3738
|
+
] }) : null,
|
|
3739
|
+
hasEmailAlert && hasTgAlert ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " both channels in use \u2014 remove one (d) to change it" }) : null
|
|
3552
3740
|
] })
|
|
3553
3741
|
] })
|
|
3554
3742
|
] }) });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.56",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|