Add option to hijack SSH Askpass to prompt for passphrase/pin#423
Add option to hijack SSH Askpass to prompt for passphrase/pin#423idursun merged 8 commits intoidursun:mainfrom
Conversation
fef551a to
2062342
Compare
internal/askpass/server.go
Outdated
| done <-chan struct{} | ||
| } | ||
|
|
||
| func ensureConnFromDescendant(conn net.Conn, parentPID int) error { |
There was a problem hiding this comment.
As a security measure, only descendants from already known PIDs can prompt the user for a password (since any other process could connect to the socket and send a password-retrieving message).
idursun
left a comment
There was a problem hiding this comment.
Hey thanks for this.
I am definitely not an expert in this field, so might have missed actual workflow.
I left a couple of comments just after skimming the code briefly.
Additionally, I see that the askpass hook is only implemented for RunCommand which is basically runs the command in a separate go routine, so that's why it didn't deadlock.
However, we have a lot of usages of RunImmediate which runs in the UI thread in places. (e.g. loading the description of the selected revision), and I am sure this would deadlock in those places as the UI thread is waiting for a password to be entered and won't respond to any other messages until it gets past it.
I also don't know what jj commands would trigger entering a passphrase. I am guessing only the ones that creates or modifies commits. However, would it ask for passphrase if the user configured the jj log to show signed commits. I am guessing it would so we cannot safely assume this applies only to the write operations.
Is there a path where we can check if a passphrase is needed at the start and don't care about it for the rest of the app? Even if we can do it, is there a scenario where the passphrase is needed again due to some expiry, etc?
| cmd := exec.Command("ssh", "git@"+host, "-p", port, | ||
| "-o", "StrictHostKeyChecking=yes", | ||
| "-o", "UserKnownHostsFile="+knownHost, | ||
| "-o", "PubkeyAuthentication=no", | ||
| "-o", "PreferredAuthentications=password", | ||
| "-o", "PKCS11Provider=none", | ||
| ) |
There was a problem hiding this comment.
I tried running the tests through nix and this failed. This will fail on every system that doesn't have ssh available, including package builds, possible windows builds as well.
There was a problem hiding this comment.
Good point. I added an error check: if ssh client is not available, this test is skipped.
internal/askpass/server.go
Outdated
| } | ||
|
|
||
| func readPPid(pid int) (int, error) { | ||
| f, err := os.Open(fmt.Sprintf("/proc/%d/status", pid)) |
There was a problem hiding this comment.
I think this is unix specific, will probably fail on other systems.
There was a problem hiding this comment.
That's why askpass performs a smoke test in StartListening: smokeTestPeerCred. It checks that peercred and readPPid work for a simple case.
|
Thanks for the quick review! I managed to hack a password prompt UI within the codebase. This can be tested by uncommenting a line in In my case I only need the password prompt when performing remote operations. I think that for commit signing, you only need the private key (i.e. the passphrase), when writing (checking the signature only needs access to the public key, which should not require the passphrase). my last push (with ssh pin prompt) happened using |
we should all sign our commits with |
This wouldn't address my usecase of a tpm-based ssh key. Each usage prompts for the PIN. |
|
Hey, thanks! I am glad you could implement the UI part as well. Very much how I would implement it myself. Please go ahead with this approach, as long as everything is behind a feature flag and no-op when the flag is off then I am happy to review it one more time once it is ready for review and merge. Tests will fail because nix vendor hash won't match, I can fix it for you. |
7929915 to
5d5ebb3
Compare
i second this 😆 🫡 |
| err = errors.New(output.String()) | ||
| msg := output.String() | ||
| if len(env) == 0 && slices.Contains([]string{"linux", "darwin"}, runtime.GOOS) { | ||
| msg += "\nHint: enable ssh.hijack_askpass if you expected a password prompt (e.g. ssh passphrase)" |
There was a problem hiding this comment.
I added a "just-in-time" hint: if a command fails and ssh.hijack_askpass is not enabled, inform the user about the existence of this setting.
The goal is to not clutter the interface for normal use (having an error here is unusual), while giving the user a chance to fix its setting quickly (without having to dig too deep in the docs).
|
Hey thanks for the updates. Test suite is failing on my mac. I don't know why though. I have In any case, can we scope these tests to |
idursun
left a comment
There was a problem hiding this comment.
Hey thanks for working on this. I am glad it is working for you.
As I mentioned in the comment, the tests are failing on my machine (Mac). It would be nice if we can scope those tests only to linux as they are passing in the CI.
I also added a comment about a possible rename.
I am happy to merge this if you can address those. Thanks!
Indeed, macos needed some minor adjustments. Since I don't have a mac, I enabled the CI tests for macos and iterated until they passed: oliverpool#1 They should now succeed on your computer. |
idursun
left a comment
There was a problem hiding this comment.
Thanks for this!
Obviously, I was not able to test this but since this is working for you and it is behind a configuration option, I am happy to merge it.
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [idursun/jjui](https://github.com/idursun/jjui) | patch | `v0.9.8` → `v0.9.9` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>idursun/jjui (idursun/jjui)</summary> ### [`v0.9.9`](https://github.com/idursun/jjui/releases/tag/v0.9.9) [Compare Source](idursun/jjui@v0.9.8...v0.9.9) ### Release Notes Another release with small improvements and bug fixes. Thanks to all contributors! #### 🎉 New Features ##### Custom Commands & Lua API Enhancements - **Custom Commands with Sequence Keys** ([#​420](idursun/jjui#420)) - Added `key_sequence` property allowing custom commands to be invoked with multiple key presses in sequence - Added `desc` property for command descriptions - Introduced sequence overlay UI showing available key sequences when first key is pressed - Example: `key_sequence = ["w", "b", "l"]` - **Lua API: Choose Method and UI** ([#​427](idursun/jjui#427)) ([#​442](idursun/jjui#442)) - New `choose()` function for interactive selection prompts in Lua scripts - New `input()` function to prompt users for text input with customizable title and prompt - New `split_lines()` function for text processing - **Lua API: Await on Operation Results** ([#​422](idursun/jjui#422)) - `start_inline_describe()` now returns boolean indicating if operation was applied or cancelled - Enables conditional command execution based on user actions - Fixes [#​310](idursun/jjui#310) - **Lua API: Interactive Commands** ([commit 8b257263](idursun/jjui@8b257263)) - Added `jj_interactive` Lua function for interactive jj command execution ##### Navigation & UI Improvements - **Ace Jump for Operations** ([#​445](idursun/jjui#445)) - Pressing 'f' in set\_parents/duplicate/rebase/squash modes now triggers ace jump - After jump completes, returns to the original operation mode instead of normal mode - Closes [#​394](idursun/jjui#394) - **Preview Width Variable** ([#​452](idursun/jjui#452)) - Added `$preview_width` placeholder variable for preview commands - Exposes actual view width (in columns) to enable tools like delta to use `--side-by-side` correctly - Width updates dynamically when preview pane is resized - Similar to fzf's `$FZF_PREVIEW_COLUMNS` - **Configurable Flash Message Display Time** ([#​456](idursun/jjui#456)) - New config key: `ui.flash_message_display_seconds` (default: 4) - Special value `0` means messages display until manually dismissed - Fixes [#​455](idursun/jjui#455) - **Page Up/Down Key Configuration** ([#​437](idursun/jjui#437)) - ScrollUp/Down keys now registered in config instead of hardcoded - Keys exposed to configuration for customization - Fixes [#​360](idursun/jjui#360) ##### SSH & Authentication - **SSH Askpass Support** ([#​423](idursun/jjui#423)) - New `[ssh] hijack_askpass` setting to prompt for SSH passphrases/PINs within jjui - Works on Linux and macOS - Properly handles prompt overriding and cancellation - Fixes [#​100](idursun/jjui#100) #### 🐛 Bug Fixes - **Exec Command History** ([#​458](idursun/jjui#458)) - Fixed issue where selected command history wasn't applied in exec mode - Input value now properly updated when selecting from fuzzy/regex suggestions - Selected commands correctly saved to history - **Menu Pagination Display** ([#​446](idursun/jjui#446)) - Fixed incorrect `%d/%d` pagination display - Height now calculated before pagination render - Added tab/shift+tab to short help menu - Fixes [#​444](idursun/jjui#444) - **Flash Message Width** ([#​432](idursun/jjui#432)) - Added maxWidth (50% of screen) to flash message rendering - Messages now properly line-wrap instead of extending beyond window width - **Operation Log Refresh** ([#​431](idursun/jjui#431)) - Operation log now returns Refresh and SelectionChanged messages upon closing - Fixes [#​430](idursun/jjui#430) - **Custom Commands List Sorting** ([commit 3fa9783a](idursun/jjui@3fa9783a)) - Fixed custom commands list to use stable sort - Fixes [#​424](idursun/jjui#424) - **JJ Error Pass-through** ([#​421](idursun/jjui#421)) - jjui now properly passes through stderr from jj commands - Error messages are more informative and show actual jj errors - **Navigation Message Display** ([commit 94a4a874](idursun/jjui@94a4a874)) - Navigation messages now only shown for paged scrolls #### What's Changed - main: pass through jj error by [@​baggiiiie](https://github.com/baggiiiie) in [#​421](idursun/jjui#421) - feat(lua): add ability to await on operation results (cancelled/applied) by [@​idursun](https://github.com/idursun) in [#​422](idursun/jjui#422) - oplog: return Refresh and SelectionChanged upon oplog closing by [@​baggiiiie](https://github.com/baggiiiie) in [#​431](idursun/jjui#431) - feat(nix): add comprehensive nix flake by [@​doprz](https://github.com/doprz) in [#​426](idursun/jjui#426) - Add option to hijack SSH Askpass to prompt for passphrase/pin by [@​oliverpool](https://github.com/oliverpool) in [#​423](idursun/jjui#423) - feat(lua): add choose method and ui by [@​idursun](https://github.com/idursun) in [#​427](idursun/jjui#427) - flash: add maxWidth to flash msg rendering by [@​baggiiiie](https://github.com/baggiiiie) in [#​432](idursun/jjui#432) - keys: add pageup/down to keys config by [@​baggiiiie](https://github.com/baggiiiie) in [#​437](idursun/jjui#437) - chore(github): Add Adda0 as an automatic reviewer for Nix-related changes by [@​Adda0](https://github.com/Adda0) in [#​440](idursun/jjui#440) - feat: add .editorconfig by [@​doprz](https://github.com/doprz) in [#​434](idursun/jjui#434) - Add input and log to custom\_commands API by [@​ArnaudBger](https://github.com/ArnaudBger) in [#​442](idursun/jjui#442) - oplog,list: refactor scrolling with Scrollable/StreamableList interface by [@​baggiiiie](https://github.com/baggiiiie) in [#​429](idursun/jjui#429) - menu: calculate height before pagination render by [@​baggiiiie](https://github.com/baggiiiie) in [#​446](idursun/jjui#446) - operations: enable ace jump for set\_parents/duplicate/rebase/squash by [@​baggiiiie](https://github.com/baggiiiie) in [#​445](idursun/jjui#445) - feat: make flash message display time configurable by [@​living180](https://github.com/living180) in [#​456](idursun/jjui#456) - feat: add $width variable for preview commands by [@​pablospe](https://github.com/pablospe) in [#​452](idursun/jjui#452) - status: fix exec command history not applied by [@​baggiiiie](https://github.com/baggiiiie) in [#​458](idursun/jjui#458) #### New Contributors - [@​doprz](https://github.com/doprz) made their first contribution in [#​426](idursun/jjui#426) - [@​oliverpool](https://github.com/oliverpool) made their first contribution in [#​423](idursun/jjui#423) - [@​living180](https://github.com/living180) made their first contribution in [#​456](idursun/jjui#456) - [@​pablospe](https://github.com/pablospe) made their first contribution in [#​452](idursun/jjui#452) **Full Changelog**: <idursun/jjui@v0.9.8...v0.9.9> </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi43NS4xIiwidXBkYXRlZEluVmVyIjoiNDIuNzUuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6OnBhdGNoIl19-->
Fixes #100
As proposed in #100 (comment), this adds a
[ssh] hijack_askpasssetting to prompt the user for the ssh passphrase/pin when needed.The backend should works on linux and macos (platform support is limited by what https://github.com/tailscale/peercred supports) and is properly tested.
UI tasks:
enterreturn the captured password to the handler