Skip to content

Commit 14a1466

Browse files
committed
feat: password obfuscation
1 parent 35f3a25 commit 14a1466

File tree

3 files changed

+47
-9
lines changed

3 files changed

+47
-9
lines changed

src/components/cred.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use tui::{backend::Backend, layout::Rect, Frame};
44

55
use asyncgit::sync::cred::BasicAuthCredential;
66

7-
use crate::components::TextInputComponent;
7+
use crate::components::{InputType, TextInputComponent};
88
use crate::{
99
components::{
1010
visibility_blocking, CommandBlocking, CommandInfo, Component,
@@ -37,13 +37,15 @@ impl CredComponent {
3737
key_config.clone(),
3838
&strings::username_popup_title(&key_config),
3939
&strings::username_popup_msg(&key_config),
40-
),
40+
)
41+
.with_input_type(InputType::Singleline),
4142
input_password: TextInputComponent::new(
4243
theme,
4344
key_config.clone(),
4445
&strings::password_popup_title(&key_config),
4546
&strings::password_popup_msg(&key_config),
46-
),
47+
)
48+
.with_input_type(InputType::Password),
4749
key_config,
4850
cred: BasicAuthCredential::new(None, None),
4951
}

src/components/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub use reset::ResetComponent;
4141
pub use select_branch::SelectBranchComponent;
4242
pub use stashmsg::StashMsgComponent;
4343
pub use tag_commit::TagCommitComponent;
44-
pub use textinput::TextInputComponent;
44+
pub use textinput::{InputType, TextInputComponent};
4545
pub use utils::filetree::FileTreeItemKind;
4646

4747
use crate::ui::style::Theme;

src/components/textinput.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@ use crate::{
99
};
1010
use anyhow::Result;
1111
use crossterm::event::{Event, KeyCode, KeyModifiers};
12+
use itertools::Itertools;
13+
use std::ops::Range;
1214
use tui::{
1315
backend::Backend, layout::Rect, style::Modifier, text::Span,
1416
widgets::Clear, Frame,
1517
};
1618

19+
#[derive(PartialEq)]
20+
pub enum InputType {
21+
Singleline,
22+
Multiline,
23+
Password,
24+
}
25+
1726
/// primarily a subcomponet for user input of text (used in `CommitComponent`)
1827
pub struct TextInputComponent {
1928
title: String,
@@ -23,6 +32,7 @@ pub struct TextInputComponent {
2332
theme: SharedTheme,
2433
key_config: SharedKeyConfig,
2534
cursor_position: usize,
35+
input_type: InputType,
2636
}
2737

2838
impl TextInputComponent {
@@ -41,9 +51,18 @@ impl TextInputComponent {
4151
title: title.to_string(),
4252
default_msg: default_msg.to_string(),
4353
cursor_position: 0,
54+
input_type: InputType::Multiline,
4455
}
4556
}
4657

58+
pub const fn with_input_type(
59+
mut self,
60+
input_type: InputType,
61+
) -> Self {
62+
self.input_type = input_type;
63+
self
64+
}
65+
4766
/// Clear the `msg`.
4867
pub fn clear(&mut self) {
4968
self.msg.clear();
@@ -113,7 +132,7 @@ impl TextInputComponent {
113132
// if the cursor is not at the first character.
114133
if self.cursor_position > 0 {
115134
txt.push(Span::styled(
116-
&self.msg[..self.cursor_position],
135+
self.get_msg(0..self.cursor_position),
117136
style,
118137
));
119138
}
@@ -122,7 +141,9 @@ impl TextInputComponent {
122141
.next_char_position()
123142
// if the cursor is at the end of the msg
124143
// a whitespace is used to underline
125-
.map_or(" ", |pos| &self.msg[self.cursor_position..pos]);
144+
.map_or(" ".to_owned(), |pos| {
145+
self.get_msg(self.cursor_position..pos)
146+
});
126147

127148
if cursor_str == "\n" {
128149
txt.push(Span::styled(
@@ -142,12 +163,22 @@ impl TextInputComponent {
142163
// still remaining characters.
143164
if let Some(pos) = self.next_char_position() {
144165
if pos < self.msg.len() {
145-
txt.push(Span::styled(&self.msg[pos..], style));
166+
txt.push(Span::styled(
167+
self.get_msg(pos..self.msg.len()),
168+
style,
169+
));
146170
}
147171
}
148172

149173
txt
150174
}
175+
176+
fn get_msg(&self, range: Range<usize>) -> String {
177+
match self.input_type {
178+
InputType::Password => range.map(|_| "*").join(""),
179+
_ => self.msg[range].to_owned(),
180+
}
181+
}
151182
}
152183

153184
impl DrawableComponent for TextInputComponent {
@@ -166,8 +197,13 @@ impl DrawableComponent for TextInputComponent {
166197
self.get_draw_text()
167198
};
168199

169-
let area = ui::centered_rect(60, 20, f.size());
170-
let area = ui::rect_min(10, 3, area);
200+
let area = match self.input_type {
201+
InputType::Multiline => {
202+
let area = ui::centered_rect(60, 20, f.size());
203+
ui::rect_min(10, 3, area)
204+
}
205+
_ => ui::centered_rect_absolute(32, 3, f.size()),
206+
};
171207

172208
f.render_widget(Clear, area);
173209
f.render_widget(

0 commit comments

Comments
 (0)