@termix-ssh/plugin-sdk 1.0.4 → 1.0.6

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/PLUGIN-GUIDE.md +780 -0
  3. package/README.md +2 -1
  4. package/cli/commands/build.mjs +7 -7
  5. package/cli/commands/migrations.mjs +2 -2
  6. package/cli/commands/validate.mjs +5 -0
  7. package/cli/index.mjs +0 -0
  8. package/dist/changelog.d.ts +3 -1
  9. package/dist/changelog.js +12 -2
  10. package/dist/db.d.ts +1 -1
  11. package/dist/db.js +1 -1
  12. package/dist/ddl.js +4 -1
  13. package/dist/host/{chunk-RU4E5XLY.js → chunk-26DAYAKC.js} +323 -216
  14. package/dist/host/{chunk-O2OHNVFX.js → chunk-DIOJ3KW2.js} +1 -1
  15. package/dist/host/{chunk-F5RZH6HE.js → chunk-NZG6HNQH.js} +14 -13
  16. package/dist/host/core-classes.json +1 -1
  17. package/dist/host/{linked-server-4VWYYABP.js → linked-server-QAKKDBFM.js} +1 -1
  18. package/dist/host/{rbac-api-WIJVZH3M.js → rbac-api-5267EMX7.js} +1 -1
  19. package/dist/host/testing-host.js +3 -3
  20. package/dist/host/types/src/types/credential-sidebar-preferences.d.ts +1 -1
  21. package/dist/host/types/src/types/onboarding.d.ts +1 -0
  22. package/dist/host/types/src/ui/api/plugins-api.d.ts +51 -0
  23. package/dist/host/types/src/ui/components/panel-layout.d.ts +0 -4
  24. package/dist/host/types/src/ui/hooks/use-mobile.d.ts +1 -0
  25. package/dist/host/types/src/ui/i18n/i18n.d.ts +1 -36
  26. package/dist/host/types/src/ui/i18n/languages.d.ts +13 -0
  27. package/dist/host/types/src/ui/lib/error-message.d.ts +1 -1
  28. package/dist/host/types/src/ui/lib/host-key-fingerprint.d.ts +5 -0
  29. package/dist/host/types/src/ui/lib/server-time.d.ts +5 -0
  30. package/dist/host/types/src/ui/main-axios.d.ts +5 -2
  31. package/dist/host/types/src/ui/ssh/dialogs/HostKeyVerificationDialog.d.ts +1 -1
  32. package/dist/host/ui.js +439 -69
  33. package/dist/host/{use-permissions-KIQCJ35M.js → use-permissions-2P2TP6GY.js} +1 -1
  34. package/dist/host-commands.js +1 -1
  35. package/package.json +14 -1
package/dist/host/ui.js CHANGED
@@ -32,6 +32,7 @@ import {
32
32
  GroupHeading,
33
33
  InlineView,
34
34
  KeyRound,
35
+ LANGUAGES,
35
36
  List,
36
37
  LoaderCircle,
37
38
  Overlay2,
@@ -138,8 +139,8 @@ import {
138
139
  useSurfaceKind,
139
140
  useTheme,
140
141
  verifySecondFactor
141
- } from "./chunk-RU4E5XLY.js";
142
- import "./chunk-O2OHNVFX.js";
142
+ } from "./chunk-26DAYAKC.js";
143
+ import "./chunk-DIOJ3KW2.js";
143
144
  import {
144
145
  TabProvider,
145
146
  buildOriginWsUrl,
@@ -178,7 +179,7 @@ import {
178
179
  useTabs,
179
180
  useTabsSafe,
180
181
  verifyPasswordResetCode
181
- } from "./chunk-F5RZH6HE.js";
182
+ } from "./chunk-NZG6HNQH.js";
182
183
  import "./chunk-YC2MAKSP.js";
183
184
 
184
185
  // src/ui/components/alert.tsx
@@ -1501,7 +1502,7 @@ function Switch2({
1501
1502
  {
1502
1503
  "data-slot": "switch",
1503
1504
  className: cn(
1504
- "peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-[background-color,border-color,box-shadow,opacity] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
1505
+ "peer relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center border-2 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-accent-brand data-[state=checked]:border-accent-brand data-[state=unchecked]:bg-muted data-[state=unchecked]:border-border",
1505
1506
  className
1506
1507
  ),
1507
1508
  ...props,
@@ -1509,9 +1510,7 @@ function Switch2({
1509
1510
  SwitchThumb,
1510
1511
  {
1511
1512
  "data-slot": "switch-thumb",
1512
- className: cn(
1513
- "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
1514
- )
1513
+ className: "pointer-events-none block h-3 w-3 bg-background shadow-sm transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0.5"
1515
1514
  }
1516
1515
  )
1517
1516
  }
@@ -2050,16 +2049,21 @@ function MiniStat({
2050
2049
 
2051
2050
  // src/ui/components/charts/LineChart.tsx
2052
2051
  import { useRef, useState as useState4, useEffect as useEffect2, useCallback } from "react";
2052
+
2053
+ // src/ui/lib/server-time.ts
2054
+ function parseServerTime(ts) {
2055
+ const bare = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(ts);
2056
+ return new Date(bare ? `${ts.replace(" ", "T")}Z` : ts);
2057
+ }
2058
+
2059
+ // src/ui/components/charts/LineChart.tsx
2053
2060
  import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
2054
2061
  var Y_LABEL_W = 44;
2055
2062
  var X_LABEL_H = 20;
2056
2063
  var TOP_PAD = 6;
2057
2064
  var TICK_COUNT = 5;
2058
- function parseTs(ts) {
2059
- return new Date(ts.includes("T") ? ts : ts.replace(" ", "T") + "Z");
2060
- }
2061
2065
  function formatTimestamp(ts, rangeMs) {
2062
- const d = parseTs(ts);
2066
+ const d = parseServerTime(ts);
2063
2067
  if (rangeMs <= 25 * 60 * 60 * 1e3) {
2064
2068
  return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
2065
2069
  }
@@ -2114,7 +2118,7 @@ function LineChart({
2114
2118
  const chartW = Math.max(0, width - Y_LABEL_W);
2115
2119
  const drawH = height - TOP_PAD;
2116
2120
  const svgH = height + X_LABEL_H;
2117
- const rangeMs = timestamps.length >= 2 ? parseTs(timestamps[timestamps.length - 1]).getTime() - parseTs(timestamps[0]).getTime() : 0;
2121
+ const rangeMs = timestamps.length >= 2 ? parseServerTime(timestamps[timestamps.length - 1]).getTime() - parseServerTime(timestamps[0]).getTime() : 0;
2118
2122
  const yTicks = (() => {
2119
2123
  const [lo, hi] = domain;
2120
2124
  const step = (hi - lo) / (TICK_COUNT - 1);
@@ -2323,6 +2327,10 @@ function useIsMobile() {
2323
2327
  void 0
2324
2328
  );
2325
2329
  React5.useEffect(() => {
2330
+ if (isElectron()) {
2331
+ setIsMobile(false);
2332
+ return;
2333
+ }
2326
2334
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
2327
2335
  const onChange = () => {
2328
2336
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -4348,12 +4356,15 @@ async function loadNamespaces(summaries) {
4348
4356
  loadedNamespaceVersions.set(summary.id, namespaceVersion(summary));
4349
4357
  }
4350
4358
  }
4359
+ function serverServesAssets(summary) {
4360
+ return summary.enabled && (!summary.state || summary.state === "active");
4361
+ }
4351
4362
  function namespaceVersion(summary) {
4352
4363
  return `${summary.version}|${summary.assetVersion ?? ""}`;
4353
4364
  }
4354
4365
  async function reconcile(summaries) {
4355
4366
  setPluginSummaries(summaries);
4356
- await loadNamespaces(summaries);
4367
+ await loadNamespaces(summaries.filter(serverServesAssets));
4357
4368
  const { order, blocked } = orderForActivation(summaries);
4358
4369
  const wanted = new Map(order.map((summary) => [summary.id, summary]));
4359
4370
  for (const id of [...active.keys()].reverse()) {
@@ -4428,6 +4439,13 @@ function syncPlugins(summaries) {
4428
4439
  import.meta.hot?.on("termix:plugins-reloaded", () => {
4429
4440
  if (started) void syncPlugins();
4430
4441
  });
4442
+ function installLocaleResolver() {
4443
+ setPluginLocaleResolver((namespace, _language, file) => {
4444
+ const summary = getPluginRecord(namespace)?.summary;
4445
+ if (!summary) return Promise.resolve(null);
4446
+ return currentDeps().loadLocale(summary, file);
4447
+ });
4448
+ }
4431
4449
  async function fetchPreLoginPlugins() {
4432
4450
  const response = await fetch(getBackendUrl("/plugins/public-manifest"));
4433
4451
  if (!response.ok) return [];
@@ -4443,11 +4461,7 @@ async function startPreLoginPlugins(options = {}) {
4443
4461
  return;
4444
4462
  }
4445
4463
  if (list.length === 0 || started) return;
4446
- setPluginLocaleResolver((namespace, _language, file) => {
4447
- const summary = getPluginRecord(namespace)?.summary;
4448
- if (!summary) return Promise.resolve(null);
4449
- return currentDeps().loadLocale(summary, file);
4450
- });
4464
+ installLocaleResolver();
4451
4465
  await enqueue(async () => {
4452
4466
  if (started) return;
4453
4467
  if (options.retryFailed) {
@@ -4542,43 +4556,6 @@ function removeSilentSigninFromSearch(search) {
4542
4556
 
4543
4557
  // src/ui/auth/Auth.tsx
4544
4558
  import { Fragment as Fragment5, jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
4545
- var LANGUAGES = [
4546
- { code: "en", label: "English" },
4547
- { code: "af", label: "Afrikaans" },
4548
- { code: "ar", label: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629" },
4549
- { code: "bn", label: "\u09AC\u09BE\u0982\u09B2\u09BE" },
4550
- { code: "bg", label: "\u0411\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438" },
4551
- { code: "ca", label: "Catal\xE0" },
4552
- { code: "zh-CN", label: "\u4E2D\u6587 (\u7B80\u4F53)" },
4553
- { code: "zh-TW", label: "\u4E2D\u6587 (\u7E41\u9AD4)" },
4554
- { code: "cs", label: "\u010Ce\u0161tina" },
4555
- { code: "da", label: "Dansk" },
4556
- { code: "nl", label: "Nederlands" },
4557
- { code: "fi", label: "Suomi" },
4558
- { code: "fr", label: "Fran\xE7ais" },
4559
- { code: "de", label: "Deutsch" },
4560
- { code: "el", label: "\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC" },
4561
- { code: "he", label: "\u05E2\u05D1\u05E8\u05D9\u05EA" },
4562
- { code: "hi", label: "\u0939\u093F\u0928\u094D\u0926\u0940" },
4563
- { code: "hu", label: "Magyar" },
4564
- { code: "id", label: "Indonesia" },
4565
- { code: "it", label: "Italiano" },
4566
- { code: "ja", label: "\u65E5\u672C\u8A9E" },
4567
- { code: "ko", label: "\uD55C\uAD6D\uC5B4" },
4568
- { code: "no", label: "Norsk" },
4569
- { code: "pl", label: "Polski" },
4570
- { code: "pt-PT", label: "Portugu\xEAs (PT)" },
4571
- { code: "pt-BR", label: "Portugu\xEAs (BR)" },
4572
- { code: "ro", label: "Rom\xE2n\u0103" },
4573
- { code: "ru", label: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439" },
4574
- { code: "sr", label: "\u0421\u0440\u043F\u0441\u043A\u0438" },
4575
- { code: "es-ES", label: "Espa\xF1ol" },
4576
- { code: "sv-SE", label: "Svenska" },
4577
- { code: "th", label: "\u0E44\u0E17\u0E22" },
4578
- { code: "tr", label: "T\xFCrk\xE7e" },
4579
- { code: "uk", label: "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430" },
4580
- { code: "vi", label: "Ti\u1EBFng Vi\u1EC7t" }
4581
- ];
4582
4559
  function LanguageRow({
4583
4560
  label,
4584
4561
  value,
@@ -5028,6 +5005,10 @@ function Auth({ onLogin }) {
5028
5005
  toast2.error(t2("auth.secondFactorUnavailable"));
5029
5006
  return;
5030
5007
  }
5008
+ if (error?.response?.data?.code === "external_login_required") {
5009
+ toast2.error(t2("auth.externalLoginRequired"));
5010
+ return;
5011
+ }
5031
5012
  toast2.error(
5032
5013
  error?.response?.data?.error || error?.message || t2(fallbackKey)
5033
5014
  );
@@ -30167,8 +30148,396 @@ function PassphraseDialog({
30167
30148
  // src/ui/ssh/dialogs/HostKeyVerificationDialog.tsx
30168
30149
  import { useState as useState18 } from "react";
30169
30150
  import { useTranslation as useTranslation18 } from "react-i18next";
30151
+
30152
+ // node_modules/@noble/hashes/_u64.js
30153
+ var fromNumH = (n) => n / 2 ** 32 | 0;
30154
+ var fromNumL = (n) => n >>> 0;
30155
+ function setU64FromNum(view, byteOffset, n, isLE) {
30156
+ const h = fromNumH(n);
30157
+ const l = fromNumL(n);
30158
+ view.setUint32(byteOffset, isLE ? l : h, isLE);
30159
+ view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
30160
+ }
30161
+
30162
+ // node_modules/@noble/hashes/utils.js
30163
+ function isBytes(a) {
30164
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
30165
+ }
30166
+ var atitle = (title) => title ? `"${title}" ` : "";
30167
+ function anumber(n, title = "") {
30168
+ if (typeof n !== "number")
30169
+ throw new TypeError(atitle(title) + "expected number, got " + typeof n);
30170
+ if (!Number.isSafeInteger(n) || n < 0)
30171
+ throw new RangeError(atitle(title) + "expected integer >= 0, got " + n);
30172
+ return n;
30173
+ }
30174
+ function abytes(value, length, title = "") {
30175
+ if (isBytes(value) && (length === void 0 || value.length === length))
30176
+ return value;
30177
+ if (length !== void 0)
30178
+ anumber(length, "length");
30179
+ const bytes = isBytes(value);
30180
+ const ofLen = length !== void 0 ? ` of length ${length}` : "";
30181
+ const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
30182
+ const message = atitle(title) + "expected Uint8Array" + ofLen + ", got " + got;
30183
+ if (!bytes)
30184
+ throw new TypeError(message);
30185
+ throw new RangeError(message);
30186
+ }
30187
+ var aobject = (value, label) => {
30188
+ if (value === null || typeof value !== "object" || Array.isArray(value))
30189
+ throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value);
30190
+ };
30191
+ var aopts = (value, label) => {
30192
+ aobject(value, label);
30193
+ const proto = Object.getPrototypeOf(value);
30194
+ if (proto !== Object.prototype && proto !== null)
30195
+ throw new TypeError(`"${label}" expected plain object`);
30196
+ if (Object.hasOwn(value, "__proto__"))
30197
+ throw new TypeError(`"${label}.__proto__" is not allowed`);
30198
+ };
30199
+ function aexists(instance, checkFinished = true) {
30200
+ if (instance.destroyed)
30201
+ throw new Error("hash was destroyed");
30202
+ if (checkFinished && instance.finished)
30203
+ throw new Error("digest() was already called");
30204
+ }
30205
+ function aoutput(out, instance) {
30206
+ abytes(out, void 0, "output");
30207
+ const min = instance.outputLen;
30208
+ if (!(out.length >= min)) {
30209
+ throw new RangeError('"output" expected length >= ' + min);
30210
+ }
30211
+ }
30212
+ function clean(...arrays) {
30213
+ for (let i2 = 0; i2 < arrays.length; i2++) {
30214
+ arrays[i2].fill(0);
30215
+ }
30216
+ }
30217
+ function createView(arr) {
30218
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
30219
+ }
30220
+ function rotr(word, shift2) {
30221
+ return word << 32 - shift2 | word >>> shift2;
30222
+ }
30223
+ function checkOpts(defaults3, opts, title = "opts") {
30224
+ aopts(defaults3, "defaults");
30225
+ if (opts !== void 0)
30226
+ aopts(opts, title);
30227
+ const merged = Object.assign(/* @__PURE__ */ Object.create(null), defaults3, opts);
30228
+ return merged;
30229
+ }
30230
+ function createHasher(hashCons, info = {}) {
30231
+ if (typeof hashCons !== "function")
30232
+ throw new TypeError('"hashCons" expected function, got type=' + typeof hashCons);
30233
+ info = checkOpts({}, info, "info");
30234
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
30235
+ const tmp = hashCons(void 0);
30236
+ hashC.outputLen = tmp.outputLen;
30237
+ hashC.blockLen = tmp.blockLen;
30238
+ hashC.canXOF = tmp.canXOF;
30239
+ hashC.create = (opts) => hashCons(opts);
30240
+ Object.assign(hashC, info);
30241
+ return Object.freeze(hashC);
30242
+ }
30243
+ var oidNist = (suffix) => ({
30244
+ // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
30245
+ // Larger suffix values would need base-128 OID encoding and a different length byte.
30246
+ oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
30247
+ });
30248
+
30249
+ // node_modules/@noble/hashes/_md.js
30250
+ function Chi(a, b, c) {
30251
+ return a & b ^ ~a & c;
30252
+ }
30253
+ function Maj(a, b, c) {
30254
+ return a & b ^ a & c ^ b & c;
30255
+ }
30256
+ var HashMD = class {
30257
+ blockLen;
30258
+ outputLen;
30259
+ canXOF = false;
30260
+ padOffset;
30261
+ isLE;
30262
+ // For partial updates less than block size
30263
+ buffer;
30264
+ view;
30265
+ finished = false;
30266
+ length = 0;
30267
+ pos = 0;
30268
+ destroyed = false;
30269
+ constructor(blockLen, outputLen, padOffset, isLE) {
30270
+ this.blockLen = blockLen;
30271
+ this.outputLen = outputLen;
30272
+ this.padOffset = padOffset;
30273
+ this.isLE = isLE;
30274
+ this.buffer = new Uint8Array(blockLen);
30275
+ this.view = createView(this.buffer);
30276
+ }
30277
+ update(data) {
30278
+ aexists(this);
30279
+ abytes(data);
30280
+ const { view, buffer, blockLen } = this;
30281
+ const len = data.length;
30282
+ let processed = false;
30283
+ for (let pos = 0; pos < len; ) {
30284
+ const take = Math.min(blockLen - this.pos, len - pos);
30285
+ if (take === blockLen) {
30286
+ const dataView = createView(data);
30287
+ for (; blockLen <= len - pos; pos += blockLen)
30288
+ this.process(dataView, pos);
30289
+ processed = true;
30290
+ continue;
30291
+ }
30292
+ buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
30293
+ this.pos += take;
30294
+ pos += take;
30295
+ if (this.pos === blockLen) {
30296
+ this.process(view, 0);
30297
+ this.pos = 0;
30298
+ processed = true;
30299
+ }
30300
+ }
30301
+ this.length += data.length;
30302
+ if (processed)
30303
+ this.roundClean();
30304
+ return this;
30305
+ }
30306
+ digestInto(out) {
30307
+ aexists(this);
30308
+ aoutput(out, this);
30309
+ this.finished = true;
30310
+ const { buffer, view, blockLen, isLE } = this;
30311
+ let { pos } = this;
30312
+ buffer[pos++] = 128;
30313
+ buffer.fill(0, pos);
30314
+ if (this.padOffset > blockLen - pos) {
30315
+ this.process(view, 0);
30316
+ buffer.fill(0);
30317
+ }
30318
+ setU64FromNum(view, blockLen - 8, this.length * 8, isLE);
30319
+ this.process(view, 0);
30320
+ this.roundClean();
30321
+ const oview = out === buffer ? view : createView(out);
30322
+ const len = this.outputLen;
30323
+ const outLen = len / 4;
30324
+ const state = this.get();
30325
+ if (len % 4 || outLen > state.length)
30326
+ throw new Error("invalid outputLen");
30327
+ for (let i2 = 0; i2 < outLen; i2++)
30328
+ oview.setUint32(4 * i2, state[i2], isLE);
30329
+ }
30330
+ digest() {
30331
+ const { buffer, outputLen } = this;
30332
+ this.digestInto(buffer);
30333
+ const res = buffer.slice(0, outputLen);
30334
+ this.destroy();
30335
+ return res;
30336
+ }
30337
+ _cloneIntoMeta(to) {
30338
+ const { buffer, length, finished, destroyed, pos } = this;
30339
+ to.destroyed = destroyed;
30340
+ to.finished = finished;
30341
+ to.length = length;
30342
+ to.pos = pos;
30343
+ if (pos)
30344
+ to.buffer.set(buffer);
30345
+ return to;
30346
+ }
30347
+ clone() {
30348
+ return this._cloneInto();
30349
+ }
30350
+ };
30351
+ var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
30352
+ 1779033703,
30353
+ 3144134277,
30354
+ 1013904242,
30355
+ 2773480762,
30356
+ 1359893119,
30357
+ 2600822924,
30358
+ 528734635,
30359
+ 1541459225
30360
+ ]);
30361
+
30362
+ // node_modules/@noble/hashes/sha2.js
30363
+ var SHA256_K = /* @__PURE__ */ Uint32Array.from([
30364
+ 1116352408,
30365
+ 1899447441,
30366
+ 3049323471,
30367
+ 3921009573,
30368
+ 961987163,
30369
+ 1508970993,
30370
+ 2453635748,
30371
+ 2870763221,
30372
+ 3624381080,
30373
+ 310598401,
30374
+ 607225278,
30375
+ 1426881987,
30376
+ 1925078388,
30377
+ 2162078206,
30378
+ 2614888103,
30379
+ 3248222580,
30380
+ 3835390401,
30381
+ 4022224774,
30382
+ 264347078,
30383
+ 604807628,
30384
+ 770255983,
30385
+ 1249150122,
30386
+ 1555081692,
30387
+ 1996064986,
30388
+ 2554220882,
30389
+ 2821834349,
30390
+ 2952996808,
30391
+ 3210313671,
30392
+ 3336571891,
30393
+ 3584528711,
30394
+ 113926993,
30395
+ 338241895,
30396
+ 666307205,
30397
+ 773529912,
30398
+ 1294757372,
30399
+ 1396182291,
30400
+ 1695183700,
30401
+ 1986661051,
30402
+ 2177026350,
30403
+ 2456956037,
30404
+ 2730485921,
30405
+ 2820302411,
30406
+ 3259730800,
30407
+ 3345764771,
30408
+ 3516065817,
30409
+ 3600352804,
30410
+ 4094571909,
30411
+ 275423344,
30412
+ 430227734,
30413
+ 506948616,
30414
+ 659060556,
30415
+ 883997877,
30416
+ 958139571,
30417
+ 1322822218,
30418
+ 1537002063,
30419
+ 1747873779,
30420
+ 1955562222,
30421
+ 2024104815,
30422
+ 2227730452,
30423
+ 2361852424,
30424
+ 2428436474,
30425
+ 2756734187,
30426
+ 3204031479,
30427
+ 3329325298
30428
+ ]);
30429
+ var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
30430
+ var SHA2_32B = class extends HashMD {
30431
+ // We cannot use array here since array allows indexing by variable
30432
+ // which means optimizer/compiler cannot use registers.
30433
+ // Numeric initializers matter: starting the fields as `undefined` changes
30434
+ // V8's field representation and makes sha256 3x slower (measured).
30435
+ A = 0;
30436
+ B = 0;
30437
+ C = 0;
30438
+ D = 0;
30439
+ E = 0;
30440
+ F = 0;
30441
+ G = 0;
30442
+ H = 0;
30443
+ constructor(outputLen, IV) {
30444
+ super(64, outputLen, 8, false);
30445
+ this.A = IV[0] | 0;
30446
+ this.B = IV[1] | 0;
30447
+ this.C = IV[2] | 0;
30448
+ this.D = IV[3] | 0;
30449
+ this.E = IV[4] | 0;
30450
+ this.F = IV[5] | 0;
30451
+ this.G = IV[6] | 0;
30452
+ this.H = IV[7] | 0;
30453
+ }
30454
+ get() {
30455
+ const { A, B, C: C2, D, E, F, G, H } = this;
30456
+ return [A, B, C2, D, E, F, G, H];
30457
+ }
30458
+ // prettier-ignore
30459
+ set(A, B, C2, D, E, F, G, H) {
30460
+ this.A = A | 0;
30461
+ this.B = B | 0;
30462
+ this.C = C2 | 0;
30463
+ this.D = D | 0;
30464
+ this.E = E | 0;
30465
+ this.F = F | 0;
30466
+ this.G = G | 0;
30467
+ this.H = H | 0;
30468
+ }
30469
+ _cloneInto(to) {
30470
+ (to ||= new this.constructor()).set(...this.get());
30471
+ return this._cloneIntoMeta(to);
30472
+ }
30473
+ process(view, offset) {
30474
+ for (let i2 = 0; i2 < 16; i2++, offset += 4)
30475
+ SHA256_W[i2] = view.getUint32(offset, false);
30476
+ for (let i2 = 16; i2 < 64; i2++) {
30477
+ const W15 = SHA256_W[i2 - 15];
30478
+ const W2 = SHA256_W[i2 - 2];
30479
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
30480
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
30481
+ SHA256_W[i2] = s1 + SHA256_W[i2 - 7] + s0 + SHA256_W[i2 - 16] | 0;
30482
+ }
30483
+ let { A, B, C: C2, D, E, F, G, H } = this;
30484
+ for (let i2 = 0; i2 < 64; i2++) {
30485
+ const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
30486
+ const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i2] + SHA256_W[i2] | 0;
30487
+ const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
30488
+ const T2 = sigma0 + Maj(A, B, C2) | 0;
30489
+ H = G;
30490
+ G = F;
30491
+ F = E;
30492
+ E = D + T1 | 0;
30493
+ D = C2;
30494
+ C2 = B;
30495
+ B = A;
30496
+ A = T1 + T2 | 0;
30497
+ }
30498
+ A = A + this.A | 0;
30499
+ B = B + this.B | 0;
30500
+ C2 = C2 + this.C | 0;
30501
+ D = D + this.D | 0;
30502
+ E = E + this.E | 0;
30503
+ F = F + this.F | 0;
30504
+ G = G + this.G | 0;
30505
+ H = H + this.H | 0;
30506
+ this.set(A, B, C2, D, E, F, G, H);
30507
+ }
30508
+ roundClean() {
30509
+ clean(SHA256_W);
30510
+ }
30511
+ destroy() {
30512
+ this.destroyed = true;
30513
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
30514
+ clean(this.buffer);
30515
+ }
30516
+ };
30517
+ var _SHA256 = class extends SHA2_32B {
30518
+ constructor() {
30519
+ super(32, SHA256_IV);
30520
+ }
30521
+ };
30522
+ var sha256 = /* @__PURE__ */ createHasher(
30523
+ () => new _SHA256(),
30524
+ /* @__PURE__ */ oidNist(1)
30525
+ );
30526
+
30527
+ // src/ui/lib/host-key-fingerprint.ts
30528
+ function hostKeyFingerprint(hex) {
30529
+ if (!hex || hex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(hex)) return hex;
30530
+ const bytes = new Uint8Array(hex.length / 2);
30531
+ for (let i2 = 0; i2 < bytes.length; i2++) {
30532
+ bytes[i2] = parseInt(hex.slice(i2 * 2, i2 * 2 + 2), 16);
30533
+ }
30534
+ let binary = "";
30535
+ for (const byte of sha256(bytes)) binary += String.fromCharCode(byte);
30536
+ return `SHA256:${btoa(binary).replace(/=+$/, "")}`;
30537
+ }
30538
+
30539
+ // src/ui/ssh/dialogs/HostKeyVerificationDialog.tsx
30170
30540
  import { Fragment as Fragment7, jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
30171
- var formatFingerprint = (fp) => fp.match(/.{1,2}/g)?.join(":") || fp;
30172
30541
  function FingerprintRow({
30173
30542
  label,
30174
30543
  value,
@@ -30178,8 +30547,8 @@ function FingerprintRow({
30178
30547
  const { t: t2 } = useTranslation18();
30179
30548
  return /* @__PURE__ */ jsxs35("div", { className: "flex flex-col gap-1.5", children: [
30180
30549
  /* @__PURE__ */ jsx51("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: label }),
30181
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
30182
- /* @__PURE__ */ jsx51("div", { className: "flex-1 bg-muted/50 border border-border p-3 font-mono text-xs break-all", children: formatFingerprint(value) }),
30550
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-stretch gap-2", children: [
30551
+ /* @__PURE__ */ jsx51("div", { className: "flex-1 bg-muted/50 border border-border p-3 font-mono text-xs break-all", children: value }),
30183
30552
  /* @__PURE__ */ jsx51(
30184
30553
  "button",
30185
30554
  {
@@ -30187,7 +30556,7 @@ function FingerprintRow({
30187
30556
  onClick: onCopy,
30188
30557
  title: t2("common.copy"),
30189
30558
  "aria-label": t2("common.copy"),
30190
- className: `${PROMPT_BUTTON} size-8 shrink-0 px-0`,
30559
+ className: "flex w-11 shrink-0 items-center justify-center border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring",
30191
30560
  children: copied ? /* @__PURE__ */ jsx51(Check, { className: "size-4 text-accent-brand" }) : /* @__PURE__ */ jsx51(Copy, { className: "size-4" })
30192
30561
  }
30193
30562
  )
@@ -30202,7 +30571,6 @@ function HostKeyVerificationDialog({
30202
30571
  hostname,
30203
30572
  fingerprint,
30204
30573
  oldFingerprint,
30205
- algorithm,
30206
30574
  onAccept,
30207
30575
  onReject,
30208
30576
  backgroundColor
@@ -30222,6 +30590,8 @@ function HostKeyVerificationDialog({
30222
30590
  }
30223
30591
  };
30224
30592
  const changed = scenario === "changed";
30593
+ const newPrint = hostKeyFingerprint(fingerprint);
30594
+ const oldPrint = hostKeyFingerprint(oldFingerprint || "");
30225
30595
  return /* @__PURE__ */ jsx51(
30226
30596
  PanePrompt,
30227
30597
  {
@@ -30261,18 +30631,18 @@ function HostKeyVerificationDialog({
30261
30631
  FingerprintRow,
30262
30632
  {
30263
30633
  label: t2("hostKey.previousKey"),
30264
- value: oldFingerprint || "",
30634
+ value: oldPrint,
30265
30635
  copied: copiedOldFingerprint,
30266
- onCopy: () => copyFingerprint(oldFingerprint || "", true)
30636
+ onCopy: () => copyFingerprint(oldPrint, true)
30267
30637
  }
30268
30638
  ),
30269
30639
  /* @__PURE__ */ jsx51(
30270
30640
  FingerprintRow,
30271
30641
  {
30272
30642
  label: t2("hostKey.newFingerprint"),
30273
- value: fingerprint,
30643
+ value: newPrint,
30274
30644
  copied: copiedFingerprint,
30275
- onCopy: () => copyFingerprint(fingerprint)
30645
+ onCopy: () => copyFingerprint(newPrint)
30276
30646
  }
30277
30647
  )
30278
30648
  ] }) : /* @__PURE__ */ jsxs35(Fragment7, { children: [
@@ -30286,10 +30656,10 @@ function HostKeyVerificationDialog({
30286
30656
  /* @__PURE__ */ jsx51(
30287
30657
  FingerprintRow,
30288
30658
  {
30289
- label: `${t2("hostKey.fingerprint")} (${algorithm.toUpperCase()})`,
30290
- value: fingerprint,
30659
+ label: t2("hostKey.fingerprint"),
30660
+ value: newPrint,
30291
30661
  copied: copiedFingerprint,
30292
- onCopy: () => copyFingerprint(fingerprint)
30662
+ onCopy: () => copyFingerprint(newPrint)
30293
30663
  }
30294
30664
  ),
30295
30665
  /* @__PURE__ */ jsx51("p", { className: "text-[10px] text-muted-foreground", children: t2("hostKey.verifyInstructions") })
@@ -31140,7 +31510,7 @@ function gridClass(columns) {
31140
31510
  columns.xl && XL_COLS[columns.xl]
31141
31511
  );
31142
31512
  }
31143
- function DataView({
31513
+ function DataView2({
31144
31514
  items,
31145
31515
  view,
31146
31516
  density,
@@ -31899,7 +32269,7 @@ export {
31899
32269
  ConnectionLogPanel,
31900
32270
  ConnectionLogProvider,
31901
32271
  ConnectionScreen,
31902
- DataView,
32272
+ DataView2 as DataView,
31903
32273
  Dialog,
31904
32274
  DialogClose,
31905
32275
  DialogContent,
@@ -7,7 +7,7 @@ import {
7
7
  resetPermissionsCache,
8
8
  setPermissionsForTesting,
9
9
  usePermissions
10
- } from "./chunk-O2OHNVFX.js";
10
+ } from "./chunk-DIOJ3KW2.js";
11
11
  import "./chunk-YC2MAKSP.js";
12
12
  export {
13
13
  hasPermission,
@@ -17,7 +17,7 @@ export function execCommand(client, command, timeoutMs = 30000) {
17
17
  if (!settled) {
18
18
  settled = true;
19
19
  cleanup();
20
- reject(new Error(`Command timeout after ${timeoutMs}ms: ${command}`));
20
+ reject(new Error(`Command timeout after ${timeoutMs}ms`));
21
21
  }
22
22
  }, timeoutMs);
23
23
  const cleanup = () => {