Skip to content

feat: prompt user on host key verification#943

Merged
lollipopkit merged 3 commits intomainfrom
lollipopkit/issue942
Oct 20, 2025
Merged

feat: prompt user on host key verification#943
lollipopkit merged 3 commits intomainfrom
lollipopkit/issue942

Conversation

@lollipopkit
Copy link
Owner

@lollipopkit lollipopkit commented Oct 19, 2025

Fixes #942

Summary by CodeRabbit

  • New Features

    • Adds interactive SSH host-key verification (fingerprint prompts, acceptance/persistence) and requires acceptance before SFTP actions.
    • Adds a developer-facing settings entry to view/decrypt/edit raw JSON configuration.
  • Documentation

    • Added localization strings for SSH host-key prompts and private-key messages in many languages.
  • Chores

    • Removed caching configuration from CI workflow.
  • Refactor

    • Updated several UI card/layouts for more consistent styling.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 19, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds interactive SSH host-key verification (prompt, caching, persistence) plus UI wiring for dialogs, settings storage support for known fingerprints, SFTP host-key checks before transfers, a global navigator key, and new localization strings for host-key prompts in many languages.

Changes

Cohort / File(s) Summary
CI config & App nav
/.github/workflows/analysis.yml, lib/app.dart, lib/core/app_navigator.dart
Removed Flutter action cache settings in workflow; added AppNavigator.key and wired it as navigatorKey on MaterialApp, exposing a global context getter.
SSH host-key verification core
lib/core/utils/server.dart
Added structured host-key verification: genClient accepts knownHostFingerprints, onHostKeyAccepted, onHostKeyPrompt; introduced _HostKeyVerifier, HostKeyPromptInfo, _loadKnownHostFingerprints, _persistHostKeyFingerprint, and ensureKnownHostKey.
Host-key helper & usage
lib/core/utils/host_key_helper.dart, lib/view/page/storage/local.dart, lib/view/page/storage/sftp.dart
Added ensureHostKeyAcceptedForSftp(BuildContext, Spi) and inserted pre-upload/download checks calling it; aborts SFTP actions if host key not accepted.
Settings persistence
lib/data/store/setting.dart
Added sshKnownHostFingerprints to SettingStore as Map<String, String> with normalization from raw objects.
Settings UI: raw JSON editor moved
lib/view/page/setting/entries/app.dart, lib/view/page/setting/entries/server.dart, lib/view/page/setting/entries/home_tabs.dart
Moved developer raw-settings editor into app.dart; removed dev-only editor UI from server.dart; replaced some Card wrappers with Padding+cardx in tab items.
Server UI refactor
lib/view/page/server/connection_stats.dart
Reworked server stats card layout from Card to Padding+Column, simplified time/stat rendering and dialog formatting.
Localization additions
lib/l10n/app_en.arb, lib/l10n/app_de.arb, lib/l10n/app_es.arb, lib/l10n/app_fr.arb, lib/l10n/app_id.arb, lib/l10n/app_ja.arb, lib/l10n/app_nl.arb, lib/l10n/app_pt.arb, lib/l10n/app_ru.arb, lib/l10n/app_tr.arb, lib/l10n/app_uk.arb, lib/l10n/app_zh.arb, lib/l10n/app_zh_tw.arb
Added localization keys for SSH/private-key flows: privateKeyNotFoundFmt, sshHostKeyChangedDesc, sshHostKeyFingerprintMd5Base64, sshHostKeyFingerprintMd5Hex, sshHostKeyType, sshHostKeyNewDesc, sshHostKeyStoredFingerprint.

Sequence Diagram(s)

sequenceDiagram participant User participant UI as Storage UI participant Helper as HostKeyHelper participant Store as SettingStore participant SSH as SSH Client / genClient participant Prompt as Prompt Flow User->>UI: Start SFTP action (upload/download) UI->>Helper: ensureHostKeyAcceptedForSftp(context, spi) Helper->>Store: read sshKnownHostFingerprints alt fingerprint known Helper-->>UI: return true else unknown Helper->>Prompt: show loading + trigger ensureKnownHostKey(spi) Prompt->>SSH: genClient + verify host key SSH-->>Prompt: fingerprint (md5 hex/base64, type) Prompt->>User: show fingerprint prompt User->>Prompt: accept / reject alt accept Prompt->>Store: persist fingerprint via onHostKeyAccepted Prompt-->>Helper: true Helper-->>UI: true else reject Prompt-->>Helper: false Helper-->>UI: false end end opt accepted UI->>SSH: proceed with SFTP operation end 
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Poem

🐰
I hopped through keys both new and old,
Checked fingerprints in silver and gold,
Saved the trust, prompted with care,
Dialogs open — I’m everywhere!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR contains several changes that appear unrelated to the core objective of prompting users on host key verification. The Flutter workflow analysis.yml removes caching configuration without clear justification for this infrastructure change. The connection_stats.dart undergoes significant UI styling refactoring unrelated to host key handling. The home_tabs.dart changes replace Card with Padding containers, and the developer feature is relocated from server.dart to app.dart without explanation. While the AppNavigator addition supports dialog prompting and localization/storage changes directly support the feature, these peripheral changes add scope beyond the stated objective of host key verification prompting. Consider isolating the out-of-scope changes into separate PRs. The Flutter workflow caching removal should be addressed separately with clear justification. The connection_stats.dart styling refactor and home_tabs.dart Card-to-Padding changes should be submitted independently. The developer feature relocation warrants a separate PR explaining the motivation. This will streamline review and maintain focus on the host key verification feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat: prompt user on host key verification" accurately captures the core feature being implemented across the changeset. The title directly reflects the primary objective of adding SSH host key verification with user prompting, which is evident in the additions of HostKeyPromptInfo, host key callbacks in genClient, ensureKnownHostKey function, and comprehensive localization strings for prompting scenarios. The title is concise, specific, and uses conventional commit semantics without vague terms.
Linked Issues Check ✅ Passed The PR comprehensively addresses the linked issue #942 "feat: prompt user if new host key" through multiple integrated changes. The implementation includes the SSH host key verification flow with user prompting callbacks (onHostKeyPrompt parameter), the HostKeyPromptInfo class for conveying prompt details, host key persistence via SettingStore.sshKnownHostFingerprints, localization strings across 12 language files for user-facing prompts, and integration into SFTP operations via ensureHostKeyAccepted checks. These changes collectively implement a complete host key verification system with user prompting as required by the linked issue.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5268193 and 49cdc92.

⛔ Files ignored due to path filters (13)
  • lib/generated/l10n/l10n.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_de.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_en.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_es.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_fr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_id.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ja.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_nl.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_pt.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ru.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_tr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_uk.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_zh.dart is excluded by !**/generated/**
📒 Files selected for processing (17)
  • lib/core/utils/host_key_helper.dart (1 hunks)
  • lib/core/utils/server.dart (7 hunks)
  • lib/l10n/app_de.arb (3 hunks)
  • lib/l10n/app_en.arb (3 hunks)
  • lib/l10n/app_es.arb (3 hunks)
  • lib/l10n/app_fr.arb (3 hunks)
  • lib/l10n/app_id.arb (3 hunks)
  • lib/l10n/app_ja.arb (3 hunks)
  • lib/l10n/app_nl.arb (3 hunks)
  • lib/l10n/app_pt.arb (3 hunks)
  • lib/l10n/app_ru.arb (3 hunks)
  • lib/l10n/app_tr.arb (3 hunks)
  • lib/l10n/app_uk.arb (3 hunks)
  • lib/l10n/app_zh.arb (3 hunks)
  • lib/l10n/app_zh_tw.arb (3 hunks)
  • lib/view/page/storage/local.dart (2 hunks)
  • lib/view/page/storage/sftp.dart (6 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
lib/view/page/storage/local.dart (1)

42-60: Refactor: Code duplication detected (see earlier comment).

This _ensureHostKeyAccepted method is identical to the one in lib/view/page/storage/sftp.dart (lines 52-70). Please refer to the refactoring suggestion in that file to extract this to a shared utility.

🧹 Nitpick comments (14)
lib/l10n/app_zh_tw.arb (2)

174-175: Add translator notes and regenerate l10n

String looks good. Please add ARB metadata (@"privateKeyNotFoundFmt": {"description": "...","placeholders":{"keyId":{"type":"String"}}}) to aid translators, and run flutter gen-l10n after ARB edits. Also confirm consumers pass keyId.


229-233: Placeholders and terminology check for SSH host key prompts

Copy reads well. Please:

  • Keep MD5 terms consistent across locales (e.g., “MD5 十六進位”).
  • Add placeholder metadata for serverName and fingerprint.
  • Regenerate localization classes (flutter gen-l10n).
lib/view/page/setting/entries/app.dart (2)

288-294: Gate “(Dev) Edit raw json” behind a developer flag

Currently visible to all users. Please gate behind BuildMode.isDebug, a hidden “dev mode” toggle, or Beta flag to prevent accidental destructive edits; optionally style with a danger color/icon.


296-404: Harden raw-settings editor: multi-encrypted selection, safer saves, and UI consistency

  • Only first encrypted key is handled. If multiple exist, offer a picker of encrypted entries before decrypting.
  • Non-encrypted path overwrites and deletes missing keys. Add a confirmation summarizing added/changed/removed counts; consider backing up the current map to a timestamped key before applying.
  • Don’t retain password longer than needed; avoid class-level capture and clear locals after use.
  • Use Btnx.cancelOk for dialog actions to match project UI conventions.
  • Consider excluding internal keys by default (includeInternalKeys: false) with an “Include internal keys” toggle.

Minimal UI consistency diff (actions area):

- actions: [ - TextButton(onPressed: () => context.pop(null), child: Text(libL10n.cancel)), - TextButton(onPressed: () => context.pop(controller.text.trim()), child: Text(libL10n.ok)), - ], + actions: Btnx.cancelOk( + onCancel: () => context.pop(null), + onOk: () => context.pop(controller.text.trim()), + ),
lib/view/page/setting/entries/home_tabs.dart (1)

86-90: Spacing change vs previous Card margin

Switch to Padding + .cardx changes horizontal/vertical spacing (8/1 vs previous Card’s margin, likely ~16/4). If visual density regressed, consider padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4) to match prior layout. Reorderable key placement is correct.

lib/l10n/app_tr.arb (2)

174-175: Regenerate l10n and add placeholder metadata

Text is fine. Please add metadata with placeholder types/descriptions for keyId and run flutter gen-l10n.


229-233: Ensure consistent placeholder names and terminology

Placeholders serverName and fingerprint look consistent. Consider “MD5 onaltılık” for “hex” if you prefer fully localized wording. Don’t forget to regenerate localization classes.

lib/l10n/app_pt.arb (1)

174-175: Add ARB descriptions for translators and regenerate

Looks good. Please add @"privateKeyNotFoundFmt" metadata with placeholder schema and run flutter gen-l10n.

lib/data/store/setting.dart (1)

75-85: LGTM with suggestion: Consider documenting the key format.

The implementation correctly persists SSH host key fingerprints with proper type conversion and safe defaults. The fromObj converter handles edge cases well.

Consider adding a comment documenting the expected key format for clarity:

/// Trusted SSH host key fingerprints keyed by `serverId::keyType`. /// Example key: "server123::ssh-ed25519" or "server456::ssh-rsa" late final sshKnownHostFingerprints = propertyDefault<Map<String, String>>(
lib/core/utils/server.dart (5)

59-62: New host-key API surface is solid; please document the contract.

The added params and default wiring look good. Add brief dartdoc to clarify:

  • knownHostFingerprints key format (“::”).
  • onHostKeyAccepted persistence expectations and when it fires (new vs update).
  • onHostKeyPrompt async behavior and fail-closed default.

Also applies to: 65-68


218-221: Unify mismatch log into a single message.

Combine details into one line for easier scanning and consistent logger usage.

- Loggers.app.warning( - 'SSH host key mismatch for ${spi.name}', - 'expected $existing but received $fingerprintHex ($keyType)', - ); + Loggers.app.warning( + 'SSH host key mismatch for ${spi.name} ($keyType): expected $existing but received $fingerprintHex.' + );

298-331: ensureKnownHostKey flow is good; consider passing prompt/persist for consistency.

You pass cache but rely on defaults for prompt/persist. Optional: thread through onHostKeyPrompt/onHostKeyAccepted so callers can customize UX in this preflight too.


232-240: Storage helpers are robust; consider growth control.

Map copy/update with early‑return is good. Optionally add a cap/eviction or diagnostics (count, size) to prevent unbounded growth in long‑running installs.

Also applies to: 242-255


345-354: Fingerprint formatting helpers: clarify algorithm in names/comments.

_fingerprintToHex and _fingerprintToBase64 assume the input is already a digest. Rename or document (e.g., “MD5 digest to hex with colons”). If SHA256 is used, reflect that in labels.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cbb48e and 5268193.

⛔ Files ignored due to path filters (13)
  • lib/generated/l10n/l10n.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_de.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_en.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_es.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_fr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_id.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ja.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_nl.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_pt.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ru.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_tr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_uk.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_zh.dart is excluded by !**/generated/**
📒 Files selected for processing (24)
  • .github/workflows/analysis.yml (0 hunks)
  • lib/app.dart (2 hunks)
  • lib/core/app_navigator.dart (1 hunks)
  • lib/core/utils/server.dart (7 hunks)
  • lib/data/store/setting.dart (1 hunks)
  • lib/l10n/app_de.arb (3 hunks)
  • lib/l10n/app_en.arb (3 hunks)
  • lib/l10n/app_es.arb (3 hunks)
  • lib/l10n/app_fr.arb (3 hunks)
  • lib/l10n/app_id.arb (3 hunks)
  • lib/l10n/app_ja.arb (3 hunks)
  • lib/l10n/app_nl.arb (3 hunks)
  • lib/l10n/app_pt.arb (3 hunks)
  • lib/l10n/app_ru.arb (3 hunks)
  • lib/l10n/app_tr.arb (3 hunks)
  • lib/l10n/app_uk.arb (3 hunks)
  • lib/l10n/app_zh.arb (3 hunks)
  • lib/l10n/app_zh_tw.arb (3 hunks)
  • lib/view/page/server/connection_stats.dart (5 hunks)
  • lib/view/page/setting/entries/app.dart (1 hunks)
  • lib/view/page/setting/entries/home_tabs.dart (1 hunks)
  • lib/view/page/setting/entries/server.dart (0 hunks)
  • lib/view/page/storage/local.dart (3 hunks)
  • lib/view/page/storage/sftp.dart (6 hunks)
💤 Files with no reviewable changes (2)
  • .github/workflows/analysis.yml
  • lib/view/page/setting/entries/server.dart
🧰 Additional context used
📓 Path-based instructions (3)
lib/l10n/**/*.arb

📄 CodeRabbit inference engine (CLAUDE.md)

lib/l10n/**/*.arb: After modifying ARB files, run: flutter gen-l10n to regenerate localization
Keep localized strings in ARB files under lib/l10n/ (Flutter i18n)

Files:

  • lib/l10n/app_ru.arb
  • lib/l10n/app_tr.arb
  • lib/l10n/app_uk.arb
  • lib/l10n/app_de.arb
  • lib/l10n/app_nl.arb
  • lib/l10n/app_pt.arb
  • lib/l10n/app_id.arb
  • lib/l10n/app_zh_tw.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_zh.arb
  • lib/l10n/app_ja.arb
  • lib/l10n/app_fr.arb
lib/data/store/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Persist state using Hive stores placed under lib/data/store/

Files:

  • lib/data/store/setting.dart
lib/view/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

lib/view/**/*.dart: Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk)
Prefer using libL10n strings before adding new ones to project l10n
Split UI into build, actions, and utils; use extension on to separate concerns

Files:

  • lib/view/page/storage/local.dart
  • lib/view/page/setting/entries/home_tabs.dart
  • lib/view/page/server/connection_stats.dart
  • lib/view/page/setting/entries/app.dart
  • lib/view/page/storage/sftp.dart
🧠 Learnings (5)
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR PR: lollipopkit/flutter_server_box#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-08T09:36:41.682Z Learning: Applies to lib/data/model/sftp/**/*.dart : Place SFTP models under lib/data/model/sftp/ 

Applied to files:

  • lib/view/page/storage/local.dart
  • lib/view/page/storage/sftp.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR PR: lollipopkit/flutter_server_box#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-08T09:36:41.682Z Learning: Applies to lib/data/model/ssh/**/*.dart : Place SSH models under lib/data/model/ssh/ 

Applied to files:

  • lib/view/page/storage/local.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR PR: lollipopkit/flutter_server_box#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-08T09:36:41.682Z Learning: Applies to lib/view/**/*.dart : Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk) 

Applied to files:

  • lib/app.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR PR: lollipopkit/flutter_server_box#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-08T09:36:41.682Z Learning: Applies to lib/view/**/*.dart : Prefer using libL10n strings before adding new ones to project l10n 

Applied to files:

  • lib/app.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR PR: lollipopkit/flutter_server_box#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-08T09:36:41.682Z Learning: Applies to lib/data/model/server/**/*.dart : Place server management models under lib/data/model/server/ 

Applied to files:

  • lib/view/page/storage/sftp.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check
🔇 Additional comments (15)
lib/l10n/app_pt.arb (1)

229-233: Perfect! The verification is complete. All critical concerns have been resolved:

All six new keys exist in all 13 locales
All consumers pass correct parameters matching the placeholders (serverName, fingerprint, keyId)
Generated l10n files exist (lib/generated/l10n/) confirming flutter gen-l10n was run

The only remaining item from the original review is an optional suggestion about terminology ("hex" vs "hexadecimal"), which is a matter of localization preference, not a correctness issue.

No actionable issues require resolution.

lib/l10n/app_fr.arb (1)

174-174: Ensure localization regeneration after merge.

As per coding guidelines, after modifying ARB files, you need to run flutter gen-l10n to regenerate localization code. Please verify this step will be completed before deployment.

Based on coding guidelines.

Also applies to: 229-233

lib/view/page/server/connection_stats.dart (2)

44-44: Nice UX improvement.

Adding a tooltip to the refresh button improves accessibility and user experience.


73-140: Layout refactoring looks clean.

The refactoring from Card-based to Padding-based layout with .cardx simplifies the structure while maintaining functionality. The inline success rate display and consolidated time items improve readability.

lib/app.dart (1)

6-6: LGTM! Global navigator enables host key prompts.

Wiring the global navigator key enables the app to show dialogs from non-UI contexts, which is essential for SSH host key verification prompts introduced in this PR.

Also applies to: 91-91

lib/view/page/storage/sftp.dart (1)

311-313: LGTM: Host key verification is consistently enforced.

The host key verification is properly enforced before all SFTP operations (edit, save callback, download, upload). This ensures that users cannot accidentally perform SFTP operations with untrusted hosts, which is an important security measure.

Also applies to: 327-330, 354-356, 688-690

lib/core/app_navigator.dart (1)

1-8: LGTM: Clean global navigator implementation.

The AppNavigator class follows Flutter best practices for providing global navigator access. The use of an abstract final class with static members is appropriate for this utility pattern, and the optional context getter is useful for conditional navigation flows.

lib/view/page/storage/local.dart (1)

396-398: LGTM: Host key verification before upload.

The host key verification is properly enforced before uploading files to the remote server, preventing uploads to untrusted hosts.

lib/l10n/app_id.arb (1)

174-174: Reminder: Regenerate localization files.

After modifying ARB files, ensure you run:

flutter gen-l10n

As per coding guidelines.

Also applies to: 229-233

lib/l10n/app_en.arb (1)

174-174: No action required—localization files already regenerated.

The ARB files in lib/l10n/ and their corresponding generated files in lib/generated/l10n/ were both modified in the same commit, confirming that flutter gen-l10n was already executed. The generated localization files are up-to-date.

lib/l10n/app_zh.arb (1)

174-174: Reminder: Regenerate localization files.

After modifying ARB files (lines 174, 229-233), ensure you run the following command to regenerate localization classes:

flutter gen-l10n

Per coding guidelines for ARB modifications. Generated files are gitignored but should be regenerated locally to ensure app_localizations files reflect the new SSH host key verification strings.

lib/core/utils/server.dart (4)

109-115: Host-key verifier integration looks correct.

Passing hostKeyVerifier.call into onVerifyHostKey for both pwd and key auth paths is consistent. Nice.

Also applies to: 124-124, 138-138


257-263: Fail‑closed default is secure; ensure non‑UI callers always provide a prompt.

When AppNavigator.context is null, the prompt returns false and connection fails. Confirm all non‑UI or background flows pass a custom onHostKeyPrompt to avoid unintended hard failures.


177-201: ---

MD5 fingerprint representation is correct; storage approach is acceptable given API constraints.

The verification confirms that dartssh2 supplies the MD5 fingerprint as raw digest bytes (via Uint8List), not the raw host key. Your conversion to MD5 hex display is accurate and standard. While MD5 is cryptographically outdated, the code stores a stable representation (MD5 hex) suitable for TOFU semantics.

Since dartssh2 does not provide raw host key bytes or SHA256 digests, computing SHA256 on your end is not feasible. The current approach—converting and storing the MD5 hex value—aligns with what the library provides.

The flow and storage strategy are sound.


80-87: I need to understand the full context around line 89 and verify how jumpClient is retained. Let me gather more information:

I need to see the complete function context where jumpClient is created and used. Let me search for that:

Now let me look at the actual code structure in server.dart to understand the full context:

Based on my research, I can now provide an informed rewrite. SSHForwardChannel is designed to implement SSHSocket for better interoperability, and the dartssh2 documentation shows the exact pattern of creating a jumpServer, calling forwardLocal, and using the result without explicitly retaining the jumpServer reference. This indicates the library manages the reference lifecycle automatically.

The concern about jumpClient lifetime being a potential leak appears to stem from incomplete understanding of how dartssh2 handles channel-to-client reference retention. Given that this pattern is documented and recommended by the library authors, and SSHForwardChannel is explicitly designed to implement SSHSocket interface, the returned forward channel maintains the necessary references to keep the underlying SSH connection alive.

No critical lifetime issue detected; review comment should be resolved.

The pattern shown in your code aligns with dartssh2's intended usage. However, if you need explicit lifecycle management for auditing purposes, you could document this behavior with a comment in the code.

Comment on lines +280 to +281
SelectableText('${l10n.privateKey}: ${info.keyType}'),
SelectableText(l10n.sshHostKeyFingerprintMd5Hex(info.fingerprintHex)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

UI text: “privateKey” label is misleading; it’s the host key type.

Replace the label with a dedicated l10n like sshHostKeyType.

- SelectableText('${l10n.privateKey}: ${info.keyType}'), + // e.g., add l10n.sshHostKeyType = "Host key type" + SelectableText('${l10n.sshHostKeyType}: ${info.keyType}'),

I can help add the new l10n key if desired.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In lib/core/utils/server.dart around lines 280-281, the UI currently uses l10n.privateKey as the label but that is misleading because it displays the host key type; replace the label with a new dedicated localization key (e.g. l10n.sshHostKeyType) in the SelectableText call and remove the incorrect privateKey usage, then add the new sshHostKeyType entry to the app's ARB/translation files (with appropriate context/comment) and update any generated localization code so the new key is available to use. 
"port": "Poort",
"preferDiskAmount": "Geef de schijfcapaciteit prioriteit bij weergave",
"privateKey": "Privésleutel",
"privateKeyNotFoundFmt": "Privésleutel [{keyId}] niet gevonden.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Reminder: Regenerate localization files.

After modifying ARB files, ensure you run:

As per coding guidelines.

Also applies to: 229-233


🏁 Script executed:

flutter gen-l10n

Length of output: 45


I'll verify the ARB file modifications and check for generated localization files.

 The `flutter gen-l10n` command could not be executed in the verification environment (Flutter toolchain not available). Please manually verify that you ran the following command after making changes to the ARB files: This ensures that the localization dart files are regenerated to include your new translation keys. --- 🏁 Script executed: ```shell #!/bin/bash # Check the modified ARB file and surrounding context echo "=== Checking app_nl.arb around line 174 ===" sed -n '170,180p' lib/l10n/app_nl.arb echo "" echo "=== Checking app_nl.arb around line 229 ===" sed -n '225,235p' lib/l10n/app_nl.arb echo "" echo "=== Checking for generated localization files ===" find lib -name "*localizations*" -o -name "*app_localizations*" | head -20 echo "" echo "=== Checking .dart_tool directory for generated files ===" ls -la .dart_tool/flutter_gen/gen_l10n/ 2>/dev/null || echo "Directory not found" 

Length of output: 2020


🏁 Script executed:

#!/bin/bash # Check if localization generation output files exist echo "=== Looking for generated localization dart files ===" find . -path "*/l10n/*.dart" -o -path "*/generated/*.dart" 2>/dev/null | grep -i local | head -20

Length of output: 53


🏁 Script executed:

#!/bin/bash # Get file modification times to understand if regeneration is needed echo "=== ARB file modification time ===" stat lib/l10n/app_nl.arb 2>/dev/null | grep -i modify echo "" echo "=== Generated localization files (if any) ===" find lib -name "*.g.dart" 2>/dev/null | head -10

Length of output: 485


🏁 Script executed:

flutter gen-l10n

Length of output: 45


Run flutter gen-l10n to regenerate localization files.

The ARB files at lines 174 and 229-233 have been modified, but the generated localization dart files are missing from the repository. This indicates the regeneration step has not been completed.

Execute:

flutter gen-l10n

This is required to generate the Dart localization classes that incorporate your new translation keys.

🤖 Prompt for AI Agents
In lib/l10n/app_nl.arb around line 174 (and related edits at lines 229-233), new/changed ARB keys were committed but the generated Dart localization files were not updated; run the Flutter localization generator to produce and commit the updated localization classes: run "flutter gen-l10n" from the project root (or the configured l10n build target), verify that the generated .dart files in the project's l10n/generated (or configured output) folder now include the new keys, then add and commit those generated files so the translations and code are in sync. 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant