Fix: SSH credential public key decryption across browser sessions #342
Reference in New Issue
Block a user
Delete Branch "fix/ssh-credential-public-key-decryption"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fix SSH Credential Public Key Decryption Issue
🐛 Problem Description
User Experience Issue
When a user adds SSH credentials (with SSH key authentication) in one browser session, everything works perfectly - they can view the credentials and connect to SSH terminals without any issues. However, when the same user logs in from a different browser, a critical bug appears:
What the user sees:
Example of the broken public key display:
See the screenshot showing the issue - the private key displays properly while the public key shows encrypted JSON.
Impact
Reproduction Steps
🔍 Root Cause
The issue was a field name mismatch in the encryption/decryption system:
Drizzle ORM returns query results with camelCase property names (e.g.,
publicKey,privateKey,keyPassword) based on the schema definition insrc/backend/database/db/schema.ts:The
ENCRYPTED_FIELDSconfiguration insrc/backend/utils/field-crypto.tsonly listed snake_case field names (e.g.,public_key,private_key,key_password)When
DataCrypto.decryptRecord()checked if a field should be decrypted, it looked for the camelCase property name (publicKey) in a Set that only contained the snake_case name (public_key)The check failed →
shouldEncryptField()returnedfalse→ field was not decrypted → raw encrypted JSON was returned to the frontendTechnical Flow
Why did this only affect cross-browser sessions?
The issue always existed, but wasn't immediately visible because:
✅ Solution
Updated
src/backend/utils/field-crypto.tsto include both camelCase and snake_case versions of all encrypted field names in theENCRYPTED_FIELDSconfiguration:Before:
After:
This ensures that:
Additional Fix in
lazy-field-encryption.tsAlso updated the legacy field name mapping to work bidirectionally, ensuring proper fallback handling for both naming conventions.
🧪 Testing
Manual Testing Steps
After this fix:
Expected Behavior
ssh-rsa AAAAB3NzaC1...)📝 Changed Files
src/backend/utils/field-crypto.ts- UpdatedENCRYPTED_FIELDSto include both camelCase and snake_case naming conventionssrc/backend/utils/lazy-field-encryption.ts- Enhanced legacy field name mapping for bidirectional support🔗 Related Issues
Fixes the critical issue where SSH public keys displayed as encrypted JSON when users logged in from different browsers, preventing terminal connections from working and causing user confusion.
📸 Visual Evidence
The attached screenshot shows the bug - notice how the SSH Public Key field displays the encrypted JSON structure instead of the actual public key, while the SSH Private Key displays correctly.
Summary of Changes
Hello @thorved, I'm Gemini Code Assist1 ! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request resolves a critical bug that prevented SSH public keys from being correctly decrypted and displayed when a user accessed their credentials from a new browser session. Previously, the public key would appear as encrypted JSON, leading to failed SSH terminal connections. The solution involves updating the encryption system's field name configurations to properly recognize both camelCase and snake_case property names, ensuring consistent and correct decryption of SSH credentials across all browser sessions.
Highlights
ENCRYPTED_FIELDSconfiguration only contained snake_case names, causing decryption to be skipped for affected fields.ENCRYPTED_FIELDSconfiguration insrc/backend/utils/field-crypto.tshas been updated to include both camelCase and snake_case versions of all relevant encrypted field names, ensuring proper decryption regardless of the naming convention used by the ORM.src/backend/utils/lazy-field-encryption.tsenhances legacy field name mapping to work bidirectionally, further improving compatibility and robustness.Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point by creating a comment using either
/gemini <command>or@gemini-code-assist <command>. Below is a summary of the supported commands on the current page./gemini review/gemini summary/gemini helpCustomization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a
.gemini/folder in the base of the repository. Detailed instructions can be found here.Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩︎
Code Review
This pull request effectively addresses a critical bug where SSH public keys were not being decrypted correctly across different browser sessions. The root cause, a mismatch between
camelCaseproperty names from the ORM andsnake_casenames in the encryption configuration, is well-identified. The solution of adding both naming conventions to the configuration is a direct fix. I've added a couple of suggestions to improve the long-term maintainability of this solution by reducing code duplication and making the configuration less error-prone.@@ -32,3 +44,4 @@"publicKey",]),};While adding both
snake_caseandcamelCaseversions of the field names fixes the issue, it introduces duplication and makes maintenance more error-prone. A developer might forget to add both versions for a new encrypted field in the future.A more robust and maintainable approach would be to keep only the canonical
snake_casenames inENCRYPTED_FIELDSand handle the case conversion inside theshouldEncryptFieldmethod. This would centralize the logic and keep the configuration clean.For example,
shouldEncryptFieldcould convert the incomingfieldNametosnake_casebefore checking for its existence in the set. This would work for bothcamelCaseandsnake_caseinputs and would allow you to revert this part of the change, simplifying the configuration.Well, that explains that issue. I'll merge this tomorrow when I have time, since it's 2 am right now. I will probably try to do a 1.7.2 release tomorrow just to get this fixed. Thank you.