mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 09:28:21 +00:00
feat: password obfuscation
This commit is contained in:
parent
35f3a25cba
commit
a75f43de77
3 changed files with 47 additions and 9 deletions
|
|
@ -4,7 +4,7 @@ use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use asyncgit::sync::cred::BasicAuthCredential;
|
use asyncgit::sync::cred::BasicAuthCredential;
|
||||||
|
|
||||||
use crate::components::TextInputComponent;
|
use crate::components::{InputType, TextInputComponent};
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{
|
components::{
|
||||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||||
|
|
@ -37,13 +37,15 @@ impl CredComponent {
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
&strings::username_popup_title(&key_config),
|
&strings::username_popup_title(&key_config),
|
||||||
&strings::username_popup_msg(&key_config),
|
&strings::username_popup_msg(&key_config),
|
||||||
),
|
)
|
||||||
|
.with_input_type(InputType::Singleline),
|
||||||
input_password: TextInputComponent::new(
|
input_password: TextInputComponent::new(
|
||||||
theme,
|
theme,
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
&strings::password_popup_title(&key_config),
|
&strings::password_popup_title(&key_config),
|
||||||
&strings::password_popup_msg(&key_config),
|
&strings::password_popup_msg(&key_config),
|
||||||
),
|
)
|
||||||
|
.with_input_type(InputType::Password),
|
||||||
key_config,
|
key_config,
|
||||||
cred: BasicAuthCredential::new(None, None),
|
cred: BasicAuthCredential::new(None, None),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ pub use reset::ResetComponent;
|
||||||
pub use select_branch::SelectBranchComponent;
|
pub use select_branch::SelectBranchComponent;
|
||||||
pub use stashmsg::StashMsgComponent;
|
pub use stashmsg::StashMsgComponent;
|
||||||
pub use tag_commit::TagCommitComponent;
|
pub use tag_commit::TagCommitComponent;
|
||||||
pub use textinput::TextInputComponent;
|
pub use textinput::{InputType, TextInputComponent};
|
||||||
pub use utils::filetree::FileTreeItemKind;
|
pub use utils::filetree::FileTreeItemKind;
|
||||||
|
|
||||||
use crate::ui::style::Theme;
|
use crate::ui::style::Theme;
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,20 @@ use crate::{
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::event::{Event, KeyCode, KeyModifiers};
|
use crossterm::event::{Event, KeyCode, KeyModifiers};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::ops::Range;
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::Backend, layout::Rect, style::Modifier, text::Span,
|
backend::Backend, layout::Rect, style::Modifier, text::Span,
|
||||||
widgets::Clear, Frame,
|
widgets::Clear, Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum InputType {
|
||||||
|
Singleline,
|
||||||
|
Multiline,
|
||||||
|
Password,
|
||||||
|
}
|
||||||
|
|
||||||
/// primarily a subcomponet for user input of text (used in `CommitComponent`)
|
/// primarily a subcomponet for user input of text (used in `CommitComponent`)
|
||||||
pub struct TextInputComponent {
|
pub struct TextInputComponent {
|
||||||
title: String,
|
title: String,
|
||||||
|
|
@ -23,6 +32,7 @@ pub struct TextInputComponent {
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
key_config: SharedKeyConfig,
|
key_config: SharedKeyConfig,
|
||||||
cursor_position: usize,
|
cursor_position: usize,
|
||||||
|
input_type: InputType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextInputComponent {
|
impl TextInputComponent {
|
||||||
|
|
@ -41,9 +51,18 @@ impl TextInputComponent {
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
default_msg: default_msg.to_string(),
|
default_msg: default_msg.to_string(),
|
||||||
cursor_position: 0,
|
cursor_position: 0,
|
||||||
|
input_type: InputType::Multiline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn with_input_type(
|
||||||
|
mut self,
|
||||||
|
input_type: InputType,
|
||||||
|
) -> Self {
|
||||||
|
self.input_type = input_type;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear the `msg`.
|
/// Clear the `msg`.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.msg.clear();
|
self.msg.clear();
|
||||||
|
|
@ -113,7 +132,7 @@ impl TextInputComponent {
|
||||||
// if the cursor is not at the first character.
|
// if the cursor is not at the first character.
|
||||||
if self.cursor_position > 0 {
|
if self.cursor_position > 0 {
|
||||||
txt.push(Span::styled(
|
txt.push(Span::styled(
|
||||||
&self.msg[..self.cursor_position],
|
self.get_msg(0..self.cursor_position),
|
||||||
style,
|
style,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +141,9 @@ impl TextInputComponent {
|
||||||
.next_char_position()
|
.next_char_position()
|
||||||
// if the cursor is at the end of the msg
|
// if the cursor is at the end of the msg
|
||||||
// a whitespace is used to underline
|
// a whitespace is used to underline
|
||||||
.map_or(" ", |pos| &self.msg[self.cursor_position..pos]);
|
.map_or(" ".to_owned(), |pos| {
|
||||||
|
self.get_msg(self.cursor_position..pos)
|
||||||
|
});
|
||||||
|
|
||||||
if cursor_str == "\n" {
|
if cursor_str == "\n" {
|
||||||
txt.push(Span::styled(
|
txt.push(Span::styled(
|
||||||
|
|
@ -142,12 +163,22 @@ impl TextInputComponent {
|
||||||
// still remaining characters.
|
// still remaining characters.
|
||||||
if let Some(pos) = self.next_char_position() {
|
if let Some(pos) = self.next_char_position() {
|
||||||
if pos < self.msg.len() {
|
if pos < self.msg.len() {
|
||||||
txt.push(Span::styled(&self.msg[pos..], style));
|
txt.push(Span::styled(
|
||||||
|
self.get_msg(pos..self.msg.len()),
|
||||||
|
style,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
txt
|
txt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_msg(&self, range: Range<usize>) -> String {
|
||||||
|
match self.input_type {
|
||||||
|
InputType::Password => range.map(|_| "*").join(""),
|
||||||
|
_ => self.msg[range].to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for TextInputComponent {
|
impl DrawableComponent for TextInputComponent {
|
||||||
|
|
@ -166,8 +197,13 @@ impl DrawableComponent for TextInputComponent {
|
||||||
self.get_draw_text()
|
self.get_draw_text()
|
||||||
};
|
};
|
||||||
|
|
||||||
let area = ui::centered_rect(60, 20, f.size());
|
let area = match self.input_type {
|
||||||
let area = ui::rect_min(10, 3, area);
|
InputType::Multiline => {
|
||||||
|
let area = ui::centered_rect(60, 20, f.size());
|
||||||
|
ui::rect_min(10, 3, area)
|
||||||
|
}
|
||||||
|
_ => ui::centered_rect_absolute(32, 3, f.size()),
|
||||||
|
};
|
||||||
|
|
||||||
f.render_widget(Clear, area);
|
f.render_widget(Clear, area);
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue