The latter needs implementation, but the API seems nice.
Showing the changes to git-credentials/src/program (3 of 8 files). Show all
Unified · Split
| @@ -8,6 +8,7 @@ impl Default for Cascade { · 7 unmodified lines | |||
| 8 | Cascade { | 8 | Cascade { |
| 9 | programs: Vec::new(), | 9 | programs: Vec::new(), |
| 10 | stderr: true, | 10 | stderr: true, |
| 11 | #[cfg(feature = "prompt")] | ||
| 11 | prompt: true, | 12 | prompt: true, |
| 12 | } | 13 | } |
| 13 | } | 14 | } |
| @@ -127,10 +128,10 @@ impl Cascade { · 113 unmodified lines | |||
| 127 | if self.prompt { | 128 | if self.prompt { |
| 128 | if let Some(ctx) = action.context_mut() { | 129 | if let Some(ctx) = action.context_mut() { |
| 129 | if let username @ None = &mut ctx.username { | 130 | if let username @ None = &mut ctx.username { |
| 130 | *username = crate::program::prompt::openly("Username: ")?.into(); | 131 | *username = git_prompt::openly("Username: ")?.into(); |
| 131 | } | 132 | } |
| 132 | if let password @ None = &mut ctx.password { | 133 | if let password @ None = &mut ctx.password { |
| 133 | *password = crate::program::prompt::securely("Password: ")?.into(); | 134 | *password = git_prompt::securely("Password: ")?.into(); |
| 134 | } | 135 | } |
| 135 | } | 136 | } |
| 136 | } | 137 | } |
| @@ -16,9 +16,6 @@ pub struct Cascade { · 15 unmodified lines | |||
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | mod cascade; | 18 | mod cascade; |
| 19 | #[cfg(feature = "prompt")] | ||
| 20 | /// | ||
| 21 | pub mod prompt; | ||
| 22 | 19 | ||
| 23 | /// The kind of helper program to use. | 20 | /// The kind of helper program to use. |
| 24 | #[derive(Debug, Clone, Eq, PartialEq)] | 21 | #[derive(Debug, Clone, Eq, PartialEq)] |
| @@ -1,52 +0,0 @@ | |||
| 1 | use std::borrow::Cow; | ||
| 2 | |||
| 3 | use rustyline::config::Configurer; | ||
| 4 | use rustyline::highlight::Highlighter; | ||
| 5 | use rustyline::{ColorMode, Editor, Result}; | ||
| 6 | use rustyline_derive::{Completer, Helper, Hinter, Validator}; | ||
| 7 | |||
| 8 | #[derive(Completer, Helper, Hinter, Validator)] | ||
| 9 | struct Mask { | ||
| 10 | apply: bool, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl Highlighter for Mask { | ||
| 14 | fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> { | ||
| 15 | use unicode_width::UnicodeWidthStr; | ||
| 16 | if self.apply { | ||
| 17 | Cow::Owned("*".repeat(line.width())) | ||
| 18 | } else { | ||
| 19 | Cow::Borrowed(line) | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | fn highlight_char(&self, _line: &str, _pos: usize) -> bool { | ||
| 24 | self.apply | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | /// Ask for information typed by the user after showing the prompt`, like `"Username: `. | ||
| 29 | pub fn openly(prompt: &str) -> Result<String> { | ||
| 30 | editor(false)?.readline(prompt) | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Ask for information _securely_ after showing the `prompt` (like `"password: "`) by not showing what's typed. | ||
| 34 | /// | ||
| 35 | /// # Security | ||
| 36 | /// | ||
| 37 | /// The current implementation does only mask the typed characters, they could still be read by an attacker. | ||
| 38 | /// To do this correctly, echoing has to be disabled entirely. See [this issue](https://github.com/kkawakam/rustyline/issues/58) | ||
| 39 | /// for progress on this. | ||
| 40 | pub fn securely(prompt: &str) -> Result<String> { | ||
| 41 | let mut ed = editor(true)?; | ||
| 42 | ed.set_color_mode(ColorMode::Forced); // force masking, otherwise disabling color won't trigger the highlighter. | ||
| 43 | ed.set_auto_add_history(false); | ||
| 44 | ed.readline(prompt) | ||
| 45 | } | ||
| 46 | |||
| 47 | fn editor(masked: bool) -> Result<Editor<Mask>> { | ||
| 48 | let h = Mask { apply: masked }; | ||
| 49 | let mut ed = Editor::new()?; | ||
| 50 | ed.set_helper(Some(h)); | ||
| 51 | Ok(ed) | ||
| 52 | } | ||