Commit Graph

16 Commits

Author SHA1 Message Date
陈大猫 904af93a1d fix(credentials): 防止解密失败后二次加密污染本地与云端 (#2702) (#2770)
* fix(credentials): stop double-encrypting undecryptable safeStorage blobs

When local decrypt failed (e.g. OSCrypt key churn after reboot), encrypt
used to wrap the leftover enc:v1 ciphertext again, permanently poisoning
the vault. Startup sync could also push those placeholders to cloud and
make download restore the same poison.

- Keep real enc:v1 blobs unchanged on encrypt (header check, no wrap)
- Strip device-bound placeholders when applying portable sync payloads
- Guard startup local-wins / merge round-trips before upload
- Skip vault init re-encrypt writes when secrets are still undecrypted

Fixes #2702

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(sync): strip enc:v1 secrets from smart-merge uploads

Bugbot found that after local apply sanitized placeholders, legacy v1
smart-merge could still decrypt an unstripped remote, merge it, and
re-upload the poison. Strip device-bound credentials on remote decrypt
and again on the merged payload before upload.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(credentials): address Codex P2 review on #2702

- Always re-encrypt vault init batches so plaintext siblings are not
  left unprotected when one record is a stale enc:v1 placeholder
- Sanitize device-bound secrets before convergent restore prepare so
  CRDT replica commit matches vault import
- Require a complete safeStorage blob (header + min 31 bytes) before
  treating enc:v1 as ciphertext; encrypt header-only coincidences

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(credentials): address Codex P1 review on #2702

- Decode enc:v1 payloads with atob in the renderer-safe domain helper
- Heal poisoned remote secrets from local/base before smart-merge so
  good credentials are not discarded as remote-only deletions
- Keep post-merge strip so leftover enc:v1 never uploads

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(credentials): address Codex P1 CBC min and startup heal

- Accept 19-byte v10/v11 CBC OSCrypt blobs (not only 31-byte GCM)
- Heal poisoned remote secrets before startup smart-merge
- Strip unresolved placeholders on merge round-trip upload

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(sync): sanitize payloads at every apply/commit boundary

Codex P1: vault apply stripped enc:v1 while commitRemoteInspection and
convergent materialization could keep the poison. Sanitize merged/remote
payloads before apply+base commit, strip on CRDT materialization, and
sanitize convergent apply inputs.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(sync): heal local and remote secrets before smart-merge

Smart-merge could select a locally-changed entity whose only secret
delta was enc:v1 poison, then strip and upload empty secrets. Heal
both sides from the opposite payload/base before merge on all sync
paths.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(sync): keep enc:v1 intact during convergent materialize

Stripping device-bound secrets inside materializeSyncPayloadFromConvergentState
broke envelope validation for poisoned-but-consistent v2 snapshots, so decrypt
could not hydrate the clouds #2702 needs to recover. Portable stripping stays
at apply/upload boundaries.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(credentials): detect Windows DPAPI by decoded header bytes

Real DPAPI blobs start with 01 00 00 00 d0 8c... and base64-encode as
AQAAANCM..., so the previous AQAAAA string prefix rejected them and
allowed double-wrapping after key rotation. Match decoded headers in
both the main-process bridge and renderer predicate.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* test(credentials): use complete enc:v1 fixtures for stricter detector

Short placeholders like enc:v1:djEwAAAA no longer pass the platform
header + minimum-size checks. Update auth/SFTP/proxy/sync fixtures to
full v10-shaped blobs so npm test matches production validation.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(sync): treat preferred credential deletions as authoritative

When healing enc:v1 before merge, an empty/missing secret on a present
preferred entity is an intentional clear and must not be revived from
base. Only fall back to base when preferred is absent or also poisoned.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(credentials): reject impossible v10/v11 ciphertext lengths

Accept only CBC-aligned sizes (19+16n) or GCM-sized blobs (>=31) so
coincidental enc:v1 plaintext of intermediate length is encrypted instead
of treated as an undecryptable placeholder.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

* fix(credentials): require full DPAPI provider GUID signature

Accept Windows safeStorage blobs only when they start with version
01 00 00 00 plus provider GUID df9d8cd0-1501-11d1-8c7a-00c04fc297eb,
so coincidental 01 00 00 00 prefixes are not treated as ciphertext.

Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
2026-08-06 13:17:24 +08:00
bincxz c1635a0f55 Give Telnet its own identity selection 2026-06-29 23:48:41 +08:00
bincxz 2796975526 Address identity proxy review gaps 2026-06-29 23:26:53 +08:00
陈大猫 45c9b9e86d Collapse host notes editor
Move host notes below connection fields and hide empty notes behind a switch.
2026-06-29 13:56:16 +08:00
bincxz 156fcbebed fix host hostname whitespace handling 2026-06-25 15:03:12 +08:00
陈大猫 df359f6a9a Simplify host icon color setting (#1546) 2026-06-22 10:49:24 +08:00
Ryanisgood 52bc48f73a 为主机添加可自定义图标和颜色 (#1504) 2026-06-17 23:32:36 +08:00
bincxz 28a7184cc4 fix(proxy): harden ProxyCommand summaries 2026-06-05 15:35:21 +08:00
陈奇 11da55abf7 fix: respect group telnet port defaults during protocol switch
When a host is in a group with telnetPort configured, switching
protocol should not override the port to 23 — let the group default
take effect. Also handles undefined port during switch (fallback to
protocol default when no group defaults exist).
2026-06-05 02:15:50 +00:00
陈奇 e751c0f23e fix: preserve group-inherited Telnet port on save
When a host inherits its Telnet port from a group config
(groupDefaults.telnetPort), the save handler should leave
port as undefined rather than materialising 23.

Added hasGroupTelnetPortDefault parameter to
resolvePrimaryProtocolSavePort to preserve inheritance.
2026-06-05 02:12:30 +00:00
陈奇 f4b5beec01 fix(host-details): auto-switch default port when toggling primary protocol between SSH/Telnet
When a user toggles the primary protocol to Telnet, the port field
previously stayed at 22 (SSH default). Now it auto-switches:
- SSH → Telnet: port 22 → 23
- Telnet → SSH: port 23 → 22
Custom ports are preserved.

Also fixes the save handler to fall back to 23 for telnet when
no explicit port is set, matching the telnet protocol default.

Closes #1251
2026-06-05 02:09:09 +00:00
陈大猫 ea5320d94a Fix #954: unify Tooltip styling + replace native selects (#961)
* Fix #954: unify Tooltip styling + replace native selects

Replace native HTML title= tooltips and native <select> dropdowns
with the existing Radix-based Tooltip / Select components so they
share the app's rounded styling, theme tokens and i18n pipeline.
Adds a global TooltipProvider in AppWithProviders so every
descendant Tooltip works without a per-file Provider wrapper.

Scope (driven by the issue #954 examples and "全部都处理" follow-up):

- TerminalLayer toolbar: Add Terminal / Split View / SFTP / Scripts
  / Theme / AI Chat / Move panel / Close panel.
- TopTabs middle bar: quick switcher, more tabs, AI assistant, theme
  toggle, settings; window-control buttons (min/max/close), tray
  close and hotkey reset/disable have their native title dropped per
  the user's explicit opt-out ("可以不用Tooltip,直接全局禁用
  原生title 属性").
- AI panels: AIChatSidePanel session history / new chat / delete,
  ConversationExport, AgentSelector, ChatInput attach / expand /
  permission, ModelSelector, ProviderCard, ai-elements/tool-call.
- SFTP: SftpSidePanel header, SftpBreadcrumb, SftpFileRow,
  SftpPaneToolbar, SftpTabBar, SftpTransferQueue.
- Settings: SettingsPage close, SettingsAppearanceTab theme/accent
  swatches, SettingsFileAssociationsTab edit/remove, SettingsSystemTab
  crash-log paths and global hotkey reset.
- Host vault: HostDetailsPanel (clear / suggestions / show-password /
  key path / browse key), GroupDetailsPanel, KnownHostsManager,
  ConnectionLogsManager, KeychainManager, SyncStatusButton,
  CloudSyncSettings, LogView, QuickSwitcher, ScriptsSidePanel,
  Terminal status bar copy-host + broadcast/focus, ZmodemProgressIndicator.
- Terminal subcomponents: HostKeywordHighlightPopover, TerminalComposeBar,
  TerminalConnectionDialog, TerminalSearchBar.
- Editor: TextEditorPane (subtitle, search, wrap, promote-to-tab).
- TrayPanel session rows and port-forwarding rows.

Native <select> migrated to custom Select component:
- SerialConnectModal (data bits, stop bits, parity, flow control)
- SerialHostDetailsPanel (same four fields)
- HostDetailsPanel backspace behavior
- GroupDetailsPanel backspace behavior
- SettingsTerminalTab local shell picker
- terminal/ThemeSidePanel font weight

Hardcoded English strings extracted to i18n. New keys for both
en and zh-CN: terminal.layer.*, topTabs.*, ai.chat.* (sessionHistory,
attach, collapse, expand, enableAgent), zmodem.*, settings.shortcuts.
resetToDefault. Inline help text on SnippetsManager package-name input
removed because the same hint is already shown in a visible <p> below
the input.

Existing per-file <TooltipProvider> wrappers (SnippetsManager,
ScriptsSidePanel, SelectHostPanel, RuleCard, HostDetailsPanel proxy
section) are left in place — they nest harmlessly under the global
provider and stay self-sufficient for component tests.

Tests:
- tsc clean for changed files (pre-existing repo-wide errors
  unrelated to this PR).
- All 802 tests pass (3 skipped pre-existing).
- HostDetailsPanel.proxyProfile.test and TextEditorPane.test
  updated to wrap with TooltipProvider, matching the runtime
  context now needed by the migrated components.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix #954: wrap Settings + Tray windows with TooltipProvider

Settings and the tray panel mount as separate Electron windows with
their own React root in index.tsx, so they do not inherit the global
TooltipProvider added under AppWithProviders. After the unified
Tooltip migration, any settings tab that used a Tooltip (Appearance,
Application, FileAssociations, System, Shortcuts, Terminal, AI
ProviderCard, AI ModelSelector) — and TrayPanel — threw
"Tooltip must be used within TooltipProvider" and rendered nothing.

Wrap both branches with TooltipProvider at the same level as
ToastProvider in index.tsx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 20:14:24 +08:00
bincxz eb1fd9c127 Harden Telnet auto-login 2026-05-07 12:57:54 +08:00
bincxz 5cf1dd1de6 Match Telnet port field width to SSH 2026-05-07 11:46:59 +08:00
bincxz b9ac14f497 Improve Telnet credential login 2026-05-07 11:22:24 +08:00
bincxz 72e305fb7a Add reusable proxy profiles 2026-05-06 17:33:46 +08:00