release-2.6.0 (#1085)

* fix: general bug fixes

* fix: general qol additions

* ci(deps): bump actions/setup-node in the github-actions group (#1068)

Bumps the github-actions group with 1 update: [actions/setup-node](https://github.com/actions/setup-node).


Updates `actions/setup-node` from 6 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump the dev-patch-updates group with 28 updates (#1069)

Bumps the dev-patch-updates group with 28 updates:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.5.2` | `2.5.4` |
| [@codemirror/view](https://github.com/codemirror/view) | `6.43.5` | `6.43.6` |
| [@radix-ui/react-accordion](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/accordion) | `1.2.15` | `1.2.17` |
| [@radix-ui/react-alert-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/alert-dialog) | `1.1.18` | `1.1.20` |
| [@radix-ui/react-checkbox](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/checkbox) | `1.3.6` | `1.3.8` |
| [@radix-ui/react-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dialog) | `1.1.18` | `1.1.20` |
| [@radix-ui/react-dropdown-menu](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dropdown-menu) | `2.1.19` | `2.1.21` |
| [@radix-ui/react-label](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/label) | `2.1.11` | `2.1.12` |
| [@radix-ui/react-popover](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/popover) | `1.1.18` | `1.1.20` |
| [@radix-ui/react-progress](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/progress) | `1.1.11` | `1.1.13` |
| [@radix-ui/react-scroll-area](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/scroll-area) | `1.2.13` | `1.2.15` |
| [@radix-ui/react-select](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/select) | `2.3.2` | `2.3.4` |
| [@radix-ui/react-separator](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/separator) | `1.1.11` | `1.1.12` |
| [@radix-ui/react-slider](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/slider) | `1.4.2` | `1.4.4` |
| [@radix-ui/react-switch](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/switch) | `1.3.2` | `1.3.4` |
| [@radix-ui/react-tabs](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tabs) | `1.1.16` | `1.1.18` |
| [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tooltip) | `1.2.11` | `1.2.13` |
| [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.2` | `4.3.3` |
| [@uiw/codemirror-extensions-langs](https://github.com/uiwjs/react-codemirror) | `4.25.10` | `4.25.11` |
| [@uiw/codemirror-theme-github](https://github.com/uiwjs/react-codemirror) | `4.25.10` | `4.25.11` |
| [@uiw/react-codemirror](https://github.com/uiwjs/react-codemirror) | `4.25.10` | `4.25.11` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.9` | `4.1.10` |
| [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `4.1.9` | `4.1.10` |
| [i18next](https://github.com/i18next/i18next) | `26.3.4` | `26.3.6` |
| [radix-ui](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/radix-ui) | `1.6.1` | `1.6.3` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.8` | `17.0.10` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.2` | `4.3.3` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.9` | `4.1.10` |


Updates `@biomejs/biome` from 2.5.2 to 2.5.4
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.4/packages/@biomejs/biome)

Updates `@codemirror/view` from 6.43.5 to 6.43.6
- [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/view/commits)

Updates `@radix-ui/react-accordion` from 1.2.15 to 1.2.17
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/accordion/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/accordion)

Updates `@radix-ui/react-alert-dialog` from 1.1.18 to 1.1.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/alert-dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/alert-dialog)

Updates `@radix-ui/react-checkbox` from 1.3.6 to 1.3.8
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/checkbox/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/checkbox)

Updates `@radix-ui/react-dialog` from 1.1.18 to 1.1.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dialog)

Updates `@radix-ui/react-dropdown-menu` from 2.1.19 to 2.1.21
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dropdown-menu/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dropdown-menu)

Updates `@radix-ui/react-label` from 2.1.11 to 2.1.12
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/label/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/label)

Updates `@radix-ui/react-popover` from 1.1.18 to 1.1.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/popover/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/popover)

Updates `@radix-ui/react-progress` from 1.1.11 to 1.1.13
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/progress/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/progress)

Updates `@radix-ui/react-scroll-area` from 1.2.13 to 1.2.15
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/scroll-area/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/scroll-area)

Updates `@radix-ui/react-select` from 2.3.2 to 2.3.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/select/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/select)

Updates `@radix-ui/react-separator` from 1.1.11 to 1.1.12
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/separator/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/separator)

Updates `@radix-ui/react-slider` from 1.4.2 to 1.4.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/slider/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slider)

Updates `@radix-ui/react-switch` from 1.3.2 to 1.3.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/switch/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/switch)

Updates `@radix-ui/react-tabs` from 1.1.16 to 1.1.18
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tabs/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tabs)

Updates `@radix-ui/react-tooltip` from 1.2.11 to 1.2.13
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tooltip/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tooltip)

Updates `@tailwindcss/vite` from 4.3.2 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/@tailwindcss-vite)

Updates `@uiw/codemirror-extensions-langs` from 4.25.10 to 4.25.11
- [Release notes](https://github.com/uiwjs/react-codemirror/releases)
- [Commits](https://github.com/uiwjs/react-codemirror/compare/v4.25.10...v4.25.11)

Updates `@uiw/codemirror-theme-github` from 4.25.10 to 4.25.11
- [Release notes](https://github.com/uiwjs/react-codemirror/releases)
- [Commits](https://github.com/uiwjs/react-codemirror/compare/v4.25.10...v4.25.11)

Updates `@uiw/react-codemirror` from 4.25.10 to 4.25.11
- [Release notes](https://github.com/uiwjs/react-codemirror/releases)
- [Commits](https://github.com/uiwjs/react-codemirror/compare/v4.25.10...v4.25.11)

Updates `@vitest/coverage-v8` from 4.1.9 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/coverage-v8)

Updates `@vitest/ui` from 4.1.9 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/ui)

Updates `i18next` from 26.3.4 to 26.3.6
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.3.4...v26.3.6)

Updates `radix-ui` from 1.6.1 to 1.6.3
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/radix-ui/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/radix-ui)

Updates `react-i18next` from 17.0.8 to 17.0.10
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.8...v17.0.10)

Updates `tailwindcss` from 4.3.2 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/tailwindcss)

Updates `vitest` from 4.1.9 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@codemirror/view"
  dependency-version: 6.43.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-accordion"
  dependency-version: 1.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-alert-dialog"
  dependency-version: 1.1.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-checkbox"
  dependency-version: 1.3.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dialog"
  dependency-version: 1.1.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dropdown-menu"
  dependency-version: 2.1.21
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-label"
  dependency-version: 2.1.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-popover"
  dependency-version: 1.1.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-progress"
  dependency-version: 1.1.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-scroll-area"
  dependency-version: 1.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-select"
  dependency-version: 2.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-separator"
  dependency-version: 1.1.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-slider"
  dependency-version: 1.4.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-switch"
  dependency-version: 1.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tabs"
  dependency-version: 1.1.18
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tooltip"
  dependency-version: 1.2.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@uiw/codemirror-extensions-langs"
  dependency-version: 4.25.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@uiw/codemirror-theme-github"
  dependency-version: 4.25.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@uiw/react-codemirror"
  dependency-version: 4.25.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/ui"
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: i18next
  dependency-version: 26.3.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: radix-ui
  dependency-version: 1.6.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: react-i18next
  dependency-version: 17.0.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: tailwindcss
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: vitest
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump ws in the prod-patch-updates group (#1071)

Bumps the prod-patch-updates group with 1 update: [ws](https://github.com/websockets/ws).


Updates `ws` from 8.21.0 to 8.21.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.21.0...8.21.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.21.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump the major-updates group with 2 updates (#1072)

Bumps the major-updates group with 2 updates: [nanoid](https://github.com/ai/nanoid) and [typescript](https://github.com/microsoft/TypeScript).


Updates `nanoid` from 5.1.16 to 6.0.0
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.1.16...6.0.0)

Updates `typescript` from 6.0.3 to 7.0.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major-updates
- dependency-name: typescript
  dependency-version: 7.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: major-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: general qol additions and new analytics/telemetrics feature

* fix: incorrect version sent to posthog

* feat: add multiplayer/shared sessions for terminal and guacd

* feat: rework Electron desktop app to run standalone-first with optional two-way sync to a remote Termix server

* Fix Guacamole tab visibility lifecycle (#1074)

Co-authored-by: default-student <default-student@github.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* fix(alerts): send channel config as object payload instead of JSON string (#1075)

* fix tmux-monitor tailscale issue (#1076)

* Initial plan

* fix(tmux-monitor): explicitly handle tailscale auth in PanePreview hostConfig

For Tailscale-auth hosts the pane-preview attach path was building the
Terminal hostConfig with only the generic spread of host fields.  This
could omit or mismap auth-critical details and trigger a plain TCP/SSH
reachability path that doesn't work with Tailscale-only SSH endpoints.

The fix branches on `host.authType === "tailscale"` and:
- Carries `authType: "tailscale"` explicitly so the backend always selects
  the Tailscale-aware PTY path regardless of how the host object evolves.
- Derives `port` from `host.sshPort ?? host.port` so Tailscale SSH
  endpoints on a non-default SSH port are reached correctly.
- Leaves all non-tailscale auth types on the unchanged code path.

Reattach (bumping instanceId + attachNonce) continues to work because
terminalHostConfig is recomputed on every render with the latest
instanceIdRef.current value.

* refactor(tmux-monitor): simplify tailscale port logic with extracted variable

Address code review feedback: extract resolvedPort into a local variable
to avoid the duplicated `host.sshPort ?? host.port` expression that was
assigned to both `port` and `sshPort`.  Restructure as an if/else block
instead of an IIFE for readability.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* chore: run prettier

* chore: update beta release text

* fix: cant update credential of an RDP host

* feat: add custom key shortcuts

* feat: add support for MFA over SSH

* fix: Invalid websocket frame causing code 10006 crash triggering restart loop

* fix(net): correct SSRF blocklist false-positive blocking all outbound IPv4 (#1079)

* fix: correct IPv4-mapped-IPv6 blocklist entry blocking all outbound IPv4

::ffff:0:0/96 in the IPv6 blocklist matches every IPv4 address once
mapped, since Node's BlockList compares addresses in their mapped form
internally regardless of the declared family. This caused
safeOutboundFetch to reject all IPv4-resolved destinations as private,
breaking outbound requests (e.g. ntfy/webhook notifications) whenever
DNS resolved to IPv4. Replaced with individual mapped ranges mirroring
the existing IPv4 blocklist.

* test: cover isBlockedAddress and link the Node BlockList citation

Exports isBlockedAddress so its family-crossing behavior around
IPv4-mapped-IPv6 addresses can actually be asserted, instead of relying
on manual container debugging to notice a regression. Also swaps the
prior "Node's BlockList compares addresses in mapped form" comment for
one citing the documented example in the Node docs
(https://nodejs.org/api/net.html#class-netblocklist), since that
behavior isn't otherwise obvious from the addSubnet/check call sites.

Related: Termix-SSH/Support#1024

* refactor: derive IPv6 mirror from IPv4 list, split DNS error messages

Two follow-ups from review:

- The IPv6 blocklist previously hand-duplicated each IPv4 range as its
  IPv4-mapped-IPv6 equivalent. Nothing enforced the two stayed in sync,
  which is exactly how the original bug (a mismatched ::ffff:0:0/96
  entry blocking all IPv4) was introduced in the first place. Now
  derived from a single blockedIpv4Ranges list in one loop.

- The connect.lookup hook threw the same "Private destinations are not
  allowed" for both an empty DNS result and an actually-blocked address.
  An empty result is a resolution failure, not a privacy decision, and
  conflating the two is the same kind of opaque-error problem that made
  this bug slow to diagnose in production. Split into distinct messages.

Also extracted the lookup hook itself (createDnsLookupHook) so it can be
unit-tested against a fake resolver directly, instead of only through a
real fetch()/Agent call — the bug lived entirely in this callback, and
undici wraps any error thrown here as a generic "fetch failed" TypeError,
which is why isolating it matters for testability.

---------

Co-authored-by: brennanneoh <497569+brennanneoh@users.noreply.github.com>

* fix(ssh): do not offer chacha20-poly1305 without the native ssh2 binding (#1081)

The availability probe treated a working OpenSSL "chacha20" cipher as proof
that chacha20-poly1305@openssh.com is usable. It is not: ssh2 pure-JS
chacha20-poly1305 corrupts the transport, so the peer aborts the KEX
("incomplete message [preauth]") and the connection times out. Easy to hit
on jump-host connections whose target sshd negotiates chacha20-poly1305
first.

Only trust the native binding (sshcrypto.node); otherwise leave the cipher
disabled so filterCiphers() drops it and AES-GCM is negotiated instead.

Co-authored-by: XtraLarge <>

* fix: add Swiss German server layout (#1078)

* chore: update release notes

* feat: continue improving desktop app 2-way sync with logic fixes and a migration dialog

* fix: dekstop app showing auth form without syncing

* feat: create desktop auto sessions for existing setups

* feat: add electron backend killing

* fix: electron login and session related bugs and updated readme for v2.6.0

* chore: finalize release notes

* fix: click to expand hosts including extra bottom margin

* fix: desktop auth modal failing to log users in

* fix: desktop app failing to sync

* fix: reverse proxy causing sync error

* chore: lint, format, and bump version to 2.6.0

* chore: sync Crowdin translations for 2.6.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: L.H. <117188168+default-student@users.noreply.github.com>
Co-authored-by: default-student <default-student@github.com>
Co-authored-by: Brad Baker <xyzulu@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Brennan Neoh <brennanneoh@users.noreply.github.com>
Co-authored-by: brennanneoh <497569+brennanneoh@users.noreply.github.com>
Co-authored-by: XtraLarge <eMail@WilliWerres.de>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
This commit is contained in:
232 files changed
+50585 -32016

No files matched your search

+216 -3
View File
@@ -389,6 +389,45 @@
"noSavedServers": "Нема сачуваних сервера",
"removeServer": "Уклони"
},
"migrationNotice": {
"title": "Termix Desktop сада ради самостално",
"body1": "Ова апликација се раније директно повезивала са вашим Termix сервером. Прерађена је тако да ради потпуно самостално, чувајући хостове и акредитиве локално како би наставила да ради ван мреже. Двосмерна синхронизација са самостално хостованим Termix сервером је сада опционална.",
"body2": "Ваши постојећи хостови и акредитиви су и даље на {{url}}. Укључите даљинску синхронизацију и поново се повежите са тим сервером да бисте их вратили и одржали синхронизацију у будућности.",
"dismiss": "Не сада",
"setUpSync": "Подешавање даљинске синхронизације"
},
"remoteSync": {
"title": "Даљинска синхронизација",
"description": "Опционо, повежите ову десктоп апликацију са самостално хостованим Termix сервером да бисте синхронизовали своје хостове, акредитиве и исечке кода на свим уређајима. Апликација увек ради потпуно ван мреже, без обзира да ли се повежете или не.",
"notConnected": "Није повезано",
"connected": "Повезано",
"connectedTo": "Повезано са {{url}}",
"lastSynced": "Последња синхронизација {{time}}",
"neverSynced": "Никада није синхронизовано",
"syncError": "Грешка у синхронизацији: {{message}}",
"needsReauth": "Пријава је истекла",
"connectButton": "Повежи се са сервером",
"disconnectButton": "Прекини везу",
"syncNowButton": "Синхронизуј сада",
"syncing": "Синхронизација...",
"serverUrl": "URL сервера",
"enterServerUrl": "Молимо вас да унесете URL адресу сервера",
"mustIncludeProtocol": "URL сервера мора да почиње са http:// или https://",
"connectionTestFailed": "Није могуће доћи до Termix сервера на тој URL адреси",
"allowInvalidCertificate": "Дозволи неважећи сертификат",
"allowInvalidCertificateDesc": "Користите само за поуздане самохостоване сервере са самопотписаним сертификатима или сертификатима за IP адресу.",
"savedServers": "Сачувани сервери",
"removeServer": "Уклони",
"continueButton": "Настави",
"cancelButton": "Откажи",
"signInTitle": "Пријавите се на {{url}}",
"originTitle": "Порекло везе",
"originDescription": "Изаберите одакле SSH везе потичу подразумевано. Ово се може заменити за сваки хост.",
"originLocal": "Овај уређај (локална мрежа)",
"originRemote": "Удаљени сервер",
"bannerReconnect": "Поново се повежите",
"bannerMessage": "Даљинска синхронизација захтева поновну аутентификацију"
},
"versionCheck": {
"error": "Грешка при провери верзије",
"checkFailed": "Провера ажурирања није успела",
@@ -602,6 +641,7 @@
"overrideCredentialUsername": "Замени корисничко име акредитива",
"overrideCredentialUsernameDesc": "Користите корисничко име наведено горе уместо корисничког имена акредитива",
"oidcUsernameHint": "Користите $oidc.preferred_username да бисте заменили своје OIDC корисничко име.",
"tailscaleUsernameHint": "Ово мора бити Unix корисник чији је идентитет на Tailscale-у додељен у SSH ACL-у Tailnet-а, не нужно root.",
"jumpHostChain": "Скок ланца хоста",
"portKnocking": "Лук Нокинг",
"addKnock": "Додај порт",
@@ -650,6 +690,11 @@
"delayAfterMs": "Кашњење после (ms)",
"useSocks5Proxy": "Користите SOCKS5 прокси",
"useSocks5ProxyDesc": "Усмерите везу преко прокси сервера",
"connectionOrigin": "Порекло везе",
"connectionOriginDesc": "Одакле потиче SSH веза овог хоста. Замењује глобално подразумевано подешавање десктоп апликације.",
"connectionOriginDefault": "Користи подразумевано",
"connectionOriginLocal": "Овај уређај (локална мрежа)",
"connectionOriginRemote": "Удаљени сервер",
"proxyHost": "Прокси хост",
"proxyPort": "Прокси порт",
"proxyUsername": "Корисничко име проксија",
@@ -762,6 +807,14 @@
"customThemeBrightCyan": "Светло цијан",
"customThemeBrightWhite": "Светло бела",
"customThemeResetTooltip": "Ресетуј на подразумеване вредности",
"savedThemesLabel": "Сачуване теме",
"saveAsGlobalTheme": "Сачувај као глобалну тему",
"saveGlobalThemeNamePrompt": "Унесите име за ову тему",
"saveGlobalThemeSuccess": "Тема је сачувана",
"saveGlobalThemeError": "Чување теме није успело",
"applyGlobalThemeTooltip": "Примени ову тему",
"deleteGlobalThemeTooltip": "Обриши ову тему",
"noSavedThemes": "Још нема сачуваних тема",
"syntaxHighlightingLabel": "Истицање синтаксе",
"syntaxHighlightingDesc": "Обоји излаз терминала (грешке, путање, IP адресе, временске ознаке)",
"syntaxHighlightingCategories": "Истакните категорије",
@@ -791,6 +844,8 @@
"enableAutoTmuxDesc": "Аутоматски покрени или прикључи се tmux сесији",
"enableSessionLogging": "Записивање сесије",
"enableSessionLoggingDesc": "Снимите излаз терминалне сесије за каснији преглед",
"allowSessionSharing": "Дозволи дељење сесије",
"allowSessionSharingDesc": "Дозволите дељење сесија уживо на овом хосту путем линка или са другим корисницима",
"enableCommandHistory": "Историја команди",
"enableCommandHistoryDesc": "Снимање команди које се извршавају у овом терминалу за историју и аутоматско довршавање",
"linkClickBehaviorLabel": "Понашање при клику на линк",
@@ -895,6 +950,7 @@
"proxmoxResultImported": "{{count}} увезено",
"proxmoxResultUpdated": "{{count}} ажурирано",
"proxmoxResultFailed": "{{count}} није успело",
"proxmoxResultSkippedNoIp": "{{count}} прескочено (није пронађена IP адреса)",
"proxmoxImportComplete": "Увоз Proxmox-а завршен: {{summary}}",
"proxmoxDiscoveryFailed": "Откривање није успело",
"proxmoxImportFailed": "Увоз није успео",
@@ -961,6 +1017,9 @@
"failedToSaveCredential": "Чување акредитива није успело",
"credentialNameRequired": "Унесите име за акредитив",
"credentialAuthRequired": "Додајте лозинку, SSH кључ или обоје",
"createCredentialFromHostBtn": "Креирај акредитив",
"createCredentialFromHostTitle": "Креирај акредитив од хоста",
"createCredentialFromHostDesc": "Направите унос акредитива за вишекратну употребу и дељење, унапред попуњен тренутним корисничким именом, лозинком и/или SSH кључем овог хоста.",
"backToHosts": "Назад на хостове",
"backToCredentials": "Назад на акредитиве",
"pinned": "Закачено",
@@ -1000,6 +1059,9 @@
"folderNestingHint": "Користите / да бисте раздвојили нивое и креирали угнежђене фасцикле.",
"folderColor": "Боја",
"folderIcon": "Икона",
"folderCredential": "Акредитив",
"folderCredentialNone": "Није додељен акредитив",
"folderCredentialHint": "Домаћини у овој фасцикли који користе ауторизацију „Сачувани акредитиви“ без изабраних сопствених акредитива наследиће овај.",
"folderPreview": "Преглед",
"folderNameFallback": "Неименована фасцикла",
"createFolderButton": "Направи фасциклу",
@@ -1181,6 +1243,10 @@
"filterTagsGroup": "Ознаке",
"shareHost": "Дели хост",
"shareHostTitle": "Подели: {{name}}",
"shareFolder": "Дели фасциклу",
"shareFolderTitle": "Дели фасциклу: {{name}}",
"folderSharedSuccessfully": "Дељено {{count}} хост(ова) у фолдеру",
"failedToShareFolder": "Дељење фасцикле није успело",
"sharing": {
"loadError": "Учитавање података о дељењу није успело. Молимо покушајте поново.",
"shareWithSection": "Подели са",
@@ -1221,6 +1287,7 @@
"shareWithCount": "Подели ({{count}})",
"currentAccess": "Тренутни приступ",
"noAccessEntries": "Овај хост још није дељен",
"folderShareSummary": "Дељено {{shared}} од {{total}} хост(ова) у овој фасцикли",
"grantedBy": "Додељено од стране",
"expires": "Истиче",
"expired": "Истекло",
@@ -1242,6 +1309,8 @@
"authMethod": "Метода овлашћења",
"authTypeDirect": "Директно",
"authTypeCredential": "Акредитив",
"authTypeNone": "Ниједан",
"authTypeNoneDesc": "Акредитиви се не чувају. Сваки пут када се повежете, биће вам затражено корисничко име и лозинка; они се не чувају.",
"selectCredential": "Изаберите акредитив...",
"connectionSettings": "Подешавања везе",
"displaySettings": "Подешавања екрана",
@@ -1259,6 +1328,7 @@
"rdpPort": "РДП порт",
"username": "Корисничко име",
"password": "Лозинка",
"passwordSaved": "Лозинка сачувана, унесите текст да бисте је променили",
"domain": "Домен",
"securityMode": "Безбедносни режим",
"colorDepth": "Дубина боје",
@@ -1424,7 +1494,60 @@
"expiresIn": "Истиче за {{duration}}",
"search": "Претражи везе...",
"noSearchResults": "Ниједна веза не одговара вашој претрази",
"rename": "Преименуј сесију"
"rename": "Преименуј сесију",
"sectionSharedWithMe": "Дељено са мном",
"sharedBy": "Дели {{username}}",
"join": "Придружи се",
"sharedSessionLabel": "{{hostName}} (дељено)"
},
"sessionSharing": {
"guestView": {
"loading": "Повезивање са дељеном сесијом...",
"linkInvalid": "Овај линк за дељење је неважећи, истекао је или је опозван",
"rateLimited": "Превише покушаја, покушајте поново ускоро",
"sessionEnded": "Ова сесија је завршена",
"readOnlyBadge": "Само преглед"
},
"modalTitle": "Дели сесију",
"shareButton": "Дели",
"notReadyToShare": "Сесија још није спремна за дељење",
"modeTab": {
"link": "Линк",
"user": "Корисник"
},
"linkModeDescription": "Свако ко има овај линк може да се придружи, није потребан налог.",
"userModeDescription": "Делите са одређеним корисником који већ има приступ овом хосту. Ако још немају приступ, прво поделите хост са њима или користите линк. Након дељења, сесија се појављује на њиховој картици „Везе“.",
"permissionLevel": {
"label": "Ниво дозволе",
"readOnly": "Само за читање",
"readOnlyDescription": "Може да гледа сесију уживо, али не може да куца или да комуницира.",
"readWrite": "Читање и писање",
"readWriteDescription": "Може да куца и интерагује са сесијом баш као и власник."
},
"expiryLabel": "Истек линка",
"createLinkButton": "Направи линк",
"createShareButton": "Подели са корисником",
"searchUsersPlaceholder": "Претражи кориснике...",
"noUsersFound": "Није пронађен ниједан корисник",
"linkCreated": "Линк за дељење је направљен",
"linkCopied": "Линк је копиран у међуспремник",
"copyLink": "Копирај линк",
"shareCreated": "Сесија је дељена. Појавиће се на њиховој картици „Везе“.",
"shareFailed": "Није успело креирање дељења",
"userLacksHostAccess": "Тај корисник још увек нема приступ овом хосту. Прво поделите хост са њим или користите линк.",
"activeShares": "Активне акције",
"noActiveShares": "Нема активних дељења за ову сесију",
"revoke": "Поништи",
"revokeConfirmTitle": "Да ли желите да опозовете ово дељење?",
"revokeConfirmDescription": "Свако ко користи ово дељење ће одмах изгубити приступ.",
"revoked": "Дељење опозвано",
"revokeFailed": "Опозивање дељења није успело",
"joinCount": "{{count}} придружи се",
"joinCount_other": "{{count}} придруживања",
"expiresAt": "Истиче {{date}}",
"linkShareBadge": "Линк",
"userShareBadge": "Корисник: {{username}}",
"loadSharesFailed": "Учитавање активних дељења није успело"
},
"guacamole": {
"connecting": "Повезивање са {{type}} сесијом...",
@@ -1436,6 +1559,9 @@
"reconnect": "Поново се повежите",
"retry": "Покушај поново",
"guacdUnavailable": "Услуга удаљеног рачунара (guacd) није доступна. Молимо вас да се уверите да је guacd покренут, доступан и правилно конфигурисан у администраторским подешавањима.",
"credentialPromptTitle": "Унесите RDP акредитиве",
"credentialPromptDescription": "Овај хост је подешен да тражи акредитиве при повезивању. Они се користе само за ову сесију и не чувају се.",
"connect": "Повежи се",
"ctrlAltDel": "Ctrl+Alt+Del",
"toolbar": {
"ctrlAltDel": "Ctrl+Alt+Del",
@@ -1461,7 +1587,9 @@
"reconnect": "Поновно повезивање сесије",
"collapse": "Савиј траку са алаткама",
"expand": "Прошири траку са алаткама",
"dragHandle": "Превуците да бисте променили положај"
"dragHandle": "Превуците да бисте променили положај",
"switchToTrackpad": "Пребаците се у режим додирне табле (превуците да бисте померили курсор, додирните да бисте кликнули)",
"switchToTouch": "Пребаците се на режим додира (додирните директно место где желите да кликнете)"
}
},
"terminal": {
@@ -1508,6 +1636,11 @@
"totpRequired": "Потребна је двофакторска аутентификација",
"totpCodeLabel": "Верификациони код",
"totpVerify": "Верификуј",
"mfaPromptRequired": "Потребна је аутентификација",
"mfaPushRequired": "Потребна је аутентификација путем поруке",
"mfaMenuPlaceholder": "Унесите свој одговор",
"mfaWaitingApproval": "Чекање одобрења на вашем уређају...",
"mfaSendRequest": "Пошаљи захтев",
"warpgateAuthRequired": "Потребна је аутентификација Варпгејта",
"warpgateSecurityKey": "Безбедносни кључ",
"warpgateAuthUrl": "URL адреса за аутентификацију",
@@ -2277,7 +2410,8 @@
"resetCodeRateLimited": "Ограничена брзина: Превише покушаја верификације. Молимо покушајте поново касније.",
"resetCodeRateLimitedWithTime": "Ограничена брзина: Превише покушаја верификације. Молимо сачекајте {{time}} секунди пре него што покушате поново.",
"authTokenSaveFailed": "Чување токена за аутентификацију није успело",
"failedToLoadServer": "Учитавање сервера није успело"
"failedToLoadServer": "Учитавање сервера није успело",
"remoteServerRequired": "Потребан је удаљени сервер. Повежите се са удаљеним сервером у Подешавањима да бисте користили овај тип везе."
},
"messages": {
"registrationDisabled": "Регистрација новог налога је тренутно онемогућена од стране администратора. Молимо вас да се пријавите или контактирате администратора.",
@@ -2644,6 +2778,17 @@
"sslSaveFailed": "Чување SSL подешавања није успело",
"sslRequiresDomain": "Домен и имејл су обавезни",
"sslInfoNote": "Након издавања сертификата, омогућите SSL у променљивим окружења (ENABLE_SSL=true) и поново покрените Termix.",
"sslManualOption": "Ручно (отпремање сертификата)",
"sslManualCert": "Сертификат (ПЕМ)",
"sslManualCertPlaceholder": "-----ПОЧЕТАК СЕРТИФИКАТА-----",
"sslManualKey": "Приватни кључ (PEM)",
"sslManualKeyPlaceholder": "-----ПОЧЕТАК ПРИВАТНОГ КЉУЧА-----",
"sslManualDesc": "Налепите постојећи сертификат и приватни кључ, укључујући цео ланац ако то захтева ваш ЦА.",
"sslManualUpload": "Сертификат за отпремање и инсталирање",
"sslManualUploadLoading": "Отпремање сертификата...",
"sslManualUploadSuccess": "Сертификат је успешно отпремљен и инсталиран",
"sslManualUploadFailed": "Отпремање сертификата није успело",
"sslManualRequiresFields": "Потребни су сертификат и приватни кључ",
"auditLogTotal": "{{total}} укупно уноса",
"auditLogEmpty": "Нису пронађени уноси у евиденцију ревизије",
"auditLogSuccess": "Успех",
@@ -2672,6 +2817,12 @@
"commandHistoryEnabled": "Историја команди",
"commandHistoryEnabledDesc": "Дозволи снимање историје команди. Када је онемогућено, историја се не чува без обзира на подешавања за сваки хост.",
"updateCommandHistoryFailed": "Ажурирање подешавања историје команди није успело",
"analyticsEnabled": "Делите анонимну статистику коришћења",
"analyticsEnabledDesc": "Шаље анонимни дневни број корисника, хостова и коришћења функција како би се побољшао Termix. Никада се не укључују лични подаци или детаљи везе.",
"updateAnalyticsFailed": "Ажурирање подешавања аналитике није успело",
"sessionSharingGloballyEnabled": "Дозволи дељење сесије",
"sessionSharingGloballyEnabledDesc": "Дозвољава дељење сесија уживо терминала, RDP, VNC и Telnet сесија на нивоу целе инстанце. Замењује сваки прекидач за дељење по хосту када је онемогућен.",
"updateSessionSharingFailed": "Ажурирање подешавања дељења сесије није успело",
"sessionTimeout": "Временско ограничење сесије",
"hours": "сати",
"sessionTimeoutRange": "Мин. 1 сат · Макс. 720 сати",
@@ -3119,6 +3270,47 @@
"executionSuccess": "Успех",
"executionFailed": "Неуспешно"
},
"keybindings": {
"title": "Пречице на тастатури",
"description": "Прилагодите пречице за копирање, лепљење и контролу терминала или повежите тастере за слање текста или покретање исечка кода.",
"defaultsHeading": "Уграђене пречице",
"customHeading": "Прилагођене пречице",
"addBinding": "Додај пречицу",
"addBindingTitle": "Додај пречицу",
"editBindingTitle": "Измени пречицу",
"loading": "Учитавање...",
"noCustomBindings": "Још нема прилагођених пречица",
"defaultBadge": "Подразумевано",
"customizedBadge": "Прилагођено",
"customize": "Прилагоди",
"resetToDefault": "Ресетуј на подразумеване вредности",
"resetAllToDefaults": "Ресетуј све на подразумеване вредности",
"close": "Затвори",
"cancel": "Откажи",
"saveBinding": "Сачувај пречицу",
"saveError": "Чување пречица на тастатури није успело",
"pressKeysToRecord": "Комбинација тастера",
"pressKeysPlaceholder": "Кликните и притисните тастере",
"recording": "Притисните тастере...",
"comboRequiredError": "Прво притисните комбинацију тастера",
"textRequiredError": "Унесите текст за слање",
"controlCodeRequiredError": "Унесите једно слово за контролни код",
"snippetRequiredError": "Изаберите исечак",
"conflictWarning": "Ова комбинација је већ повезана са {{combo}}. Чување ће активирати обе.",
"actionLabel": "Акција",
"actionCopy": "Копирај избор",
"actionPaste": "Залепи",
"actionSendControlCode": "Пошаљи сигнал Ctrl+слово",
"actionSendText": "Пошаљи текст",
"actionRunSnippet": "Покрени постојећи исечак кода",
"controlCodeLabel": "Писмо",
"textLabel": "Текст за слање",
"appendEnterLabel": "Притисните Ентер након слања",
"snippetLabel": "Исечак",
"selectSnippetPlaceholder": "Изаберите исечак",
"orphanedSnippetWarning": "фрагмент није пронађен",
"clipboardPermissionNote": "Може затражити дозволу за међуспремник при првој употреби у неким прегледачима."
},
"userProfile": {
"donateTitle": "Нека Термикс остане жив",
"donateDescription": "Termix је бесплатан, самостално хостован и изградило га је само неколико људи у своје слободно време. Ако вам је уштедео време или новац, донација криптовалута помаже да се одржи.",
@@ -3134,6 +3326,7 @@
"sectionAppearance": "Изглед",
"sectionSecurity": "Безбедност",
"sectionApiKeys": "API кључеви",
"sectionData": "Подаци",
"sectionC2sTunnels": "C2S тунели",
"usernameLabel": "Корисничко име",
"roleLabel": "Улога",
@@ -3162,6 +3355,9 @@
"settingsTerminal": "Терминал",
"commandAutocomplete": "Аутоматско довршавање команди",
"commandAutocompleteDesc": "Прикажи аутоматско довршавање током куцања",
"keyboardShortcuts": "Пречице на тастатури",
"keyboardShortcutsDescription": "Прилагодите пречице за копирање, лепљење и команде у терминалу",
"manageShortcuts": "Управљај",
"terminalLinkBehavior": "Кликните на линк терминала",
"terminalLinkBehaviorDesc": "Подразумевано понашање при клику на линкове у терминалу",
"historyTracking": "Праћење историје",
@@ -3228,6 +3424,22 @@
"apiKeyUsageHint": "Укључите свој кључ у",
"apiKeyUsageHintHeader": "заглавље.",
"apiKeyPermissionsHint": "Кључеви наслеђују дозволе корисника који их креира.",
"exportData": "Извези моје податке",
"exportDataDesc": "Преузмите резервну копију својих хостова, акредитива и подешавања да бисте их пренели на други уређај",
"export": "Извоз",
"exporting": "Извоз...",
"importData": "Увези моје податке",
"importDataDesc": "Вратите своје хостове, акредитиве и подешавања из .sqlite датотеке резервне копије",
"importDataSelected": "Изабрано: {{name}}",
"selectFile": "Изаберите датотеку",
"changeFile": "Промена",
"import": "Увоз",
"importing": "Увоз...",
"exportSuccess": "Подаци су успешно извезени",
"exportFailed": "Извоз података није успео",
"importSelectFile": "Прво изаберите датотеку",
"importCompleted": "Увоз завршен: {{total}} ставки је увезено, {{skipped}} прескочено",
"importFailed": "Увоз није успео: {{error}}",
"roleUser": "Корисник",
"authMethodDual": "Двострука аутентификација",
"authMethodOidc": "ОИДЦ",
@@ -3379,6 +3591,7 @@
"pageUp": "PgUp",
"pageDown": "ПгДн",
"delete": "Дел",
"paste": "Залепи",
"editQuickKeys": "Уреди брзе тастере",
"quickKeysTitle": "Брзи тастери",
"quickKeysDesc": "Додирните × да бисте уклонили. Подржава до 8 знакова.",