mirror of
https://github.com/apognu/tuigreet.git
synced 2024-09-11 07:25:29 +03:00
Refactored the username mask concept behind a struct.
This commit is contained in:
parent
571677dec6
commit
6c1e01840d
@ -27,7 +27,7 @@ use crate::{
|
||||
},
|
||||
power::PowerOption,
|
||||
ui::{
|
||||
common::menu::Menu,
|
||||
common::{masked::MaskedString, menu::Menu},
|
||||
power::Power,
|
||||
sessions::{Session, SessionSource, SessionType},
|
||||
users::User,
|
||||
@ -124,10 +124,8 @@ pub struct Greeter {
|
||||
pub user_menu: bool,
|
||||
// Menu for user selection.
|
||||
pub users: Menu<User>,
|
||||
// Current username.
|
||||
pub username: String,
|
||||
// Value to display in place of the username (e.g. full name of the user).
|
||||
pub username_mask: Option<String>,
|
||||
// Current username. Masked to display the full name if available.
|
||||
pub username: MaskedString,
|
||||
// Prompt that should be displayed to ask for entry.
|
||||
pub prompt: Option<String>,
|
||||
|
||||
@ -194,8 +192,7 @@ impl Greeter {
|
||||
// If we should remember the last logged-in user.
|
||||
if greeter.remember {
|
||||
if let Some(username) = get_last_user_username() {
|
||||
greeter.username = username.clone();
|
||||
greeter.username_mask = get_last_user_name();
|
||||
greeter.username = MaskedString::from(username.clone(), get_last_user_name());
|
||||
|
||||
// If, on top of that, we should remember their last session.
|
||||
if greeter.remember_user_session {
|
||||
@ -237,7 +234,6 @@ impl Greeter {
|
||||
|
||||
if !soft {
|
||||
self.username.zeroize();
|
||||
self.username_mask.zeroize();
|
||||
}
|
||||
|
||||
if scrub_message {
|
||||
|
@ -13,6 +13,7 @@ use nix::sys::utsname;
|
||||
|
||||
use crate::{
|
||||
ui::{
|
||||
common::masked::MaskedString,
|
||||
sessions::{Session, SessionType},
|
||||
users::User,
|
||||
},
|
||||
@ -101,10 +102,10 @@ pub fn get_last_user_name() -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_last_username(username: &str, name: Option<&str>) {
|
||||
let _ = fs::write(LAST_USER_USERNAME, username);
|
||||
pub fn write_last_username(username: &MaskedString) {
|
||||
let _ = fs::write(LAST_USER_USERNAME, username.value.clone());
|
||||
|
||||
if let Some(name) = name {
|
||||
if let Some(ref name) = username.mask {
|
||||
let _ = fs::write(LAST_USER_NAME, name);
|
||||
} else {
|
||||
let _ = fs::remove_file(LAST_USER_NAME);
|
||||
|
16
src/ipc.rs
16
src/ipc.rs
@ -104,19 +104,19 @@ impl Ipc {
|
||||
Response::Success => {
|
||||
if greeter.done {
|
||||
if greeter.remember {
|
||||
write_last_username(&greeter.username, greeter.username_mask.as_deref());
|
||||
write_last_username(&greeter.username);
|
||||
|
||||
if greeter.remember_user_session {
|
||||
match greeter.session_source {
|
||||
SessionSource::Command(ref command) => {
|
||||
write_last_user_session(&greeter.username, command);
|
||||
delete_last_user_session_path(&greeter.username);
|
||||
write_last_user_session(&greeter.username.value, command);
|
||||
delete_last_user_session_path(&greeter.username.value);
|
||||
}
|
||||
|
||||
SessionSource::Session(index) => {
|
||||
if let Some(Session { path: Some(session_path), .. }) = greeter.sessions.options.get(index) {
|
||||
write_last_user_session_path(&greeter.username, session_path);
|
||||
delete_last_user_session(&greeter.username);
|
||||
write_last_user_session_path(&greeter.username.value, session_path);
|
||||
delete_last_user_session(&greeter.username.value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +161,11 @@ impl Ipc {
|
||||
match error_type {
|
||||
ErrorType::AuthError => {
|
||||
greeter.message = Some(fl!("failed"));
|
||||
self.send(Request::CreateSession { username: greeter.username.clone() }).await;
|
||||
self
|
||||
.send(Request::CreateSession {
|
||||
username: greeter.username.value.clone(),
|
||||
})
|
||||
.await;
|
||||
greeter.reset(true).await;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
ipc::Ipc,
|
||||
power::power,
|
||||
ui::{
|
||||
common::masked::MaskedString,
|
||||
sessions::{Session, SessionSource},
|
||||
users::User,
|
||||
},
|
||||
@ -31,7 +32,7 @@ pub async fn handle(greeter: Arc<RwLock<Greeter>>, input: KeyEvent, ipc: Ipc) ->
|
||||
modifiers: KeyModifiers::CONTROL,
|
||||
..
|
||||
} => match greeter.mode {
|
||||
Mode::Username => greeter.username = String::new(),
|
||||
Mode::Username => greeter.username = MaskedString::default(),
|
||||
Mode::Password => greeter.buffer = String::new(),
|
||||
Mode::Command => greeter.buffer = String::new(),
|
||||
_ => {}
|
||||
@ -163,7 +164,7 @@ pub async fn handle(greeter: Arc<RwLock<Greeter>>, input: KeyEvent, ipc: Ipc) ->
|
||||
} => {
|
||||
let value = {
|
||||
match greeter.mode {
|
||||
Mode::Username => &greeter.username,
|
||||
Mode::Username => &greeter.username.value,
|
||||
_ => &greeter.buffer,
|
||||
}
|
||||
};
|
||||
@ -180,13 +181,13 @@ pub async fn handle(greeter: Arc<RwLock<Greeter>>, input: KeyEvent, ipc: Ipc) ->
|
||||
|
||||
// Tab should validate the username entry (same as Enter).
|
||||
KeyEvent { code: KeyCode::Tab, .. } => match greeter.mode {
|
||||
Mode::Username if !greeter.username.is_empty() => validate_username(&mut greeter, &ipc).await,
|
||||
Mode::Username if !greeter.username.value.is_empty() => validate_username(&mut greeter, &ipc).await,
|
||||
_ => {}
|
||||
},
|
||||
|
||||
// Enter validates the current entry, depending on the active mode.
|
||||
KeyEvent { code: KeyCode::Enter, .. } => match greeter.mode {
|
||||
Mode::Username if !greeter.username.is_empty() => validate_username(&mut greeter, &ipc).await,
|
||||
Mode::Username if !greeter.username.value.is_empty() => validate_username(&mut greeter, &ipc).await,
|
||||
|
||||
Mode::Username if greeter.user_menu => {
|
||||
greeter.previous_mode = match greeter.mode {
|
||||
@ -230,8 +231,7 @@ pub async fn handle(greeter: Arc<RwLock<Greeter>>, input: KeyEvent, ipc: Ipc) ->
|
||||
let username = greeter.users.options.get(greeter.users.selected).cloned();
|
||||
|
||||
if let Some(User { username, name }) = username {
|
||||
greeter.username = username;
|
||||
greeter.username_mask = name;
|
||||
greeter.username = MaskedString::from(username, name);
|
||||
}
|
||||
|
||||
validate_username(&mut greeter, &ipc).await;
|
||||
@ -287,7 +287,7 @@ pub async fn handle(greeter: Arc<RwLock<Greeter>>, input: KeyEvent, ipc: Ipc) ->
|
||||
// current mode and the position of the cursor.
|
||||
async fn insert_key(greeter: &mut Greeter, c: char) {
|
||||
let value = match greeter.mode {
|
||||
Mode::Username => &greeter.username,
|
||||
Mode::Username => &greeter.username.value,
|
||||
Mode::Password => &greeter.buffer,
|
||||
Mode::Command => &greeter.buffer,
|
||||
Mode::Users | Mode::Sessions | Mode::Power | Mode::Processing => return,
|
||||
@ -301,7 +301,7 @@ async fn insert_key(greeter: &mut Greeter, c: char) {
|
||||
let mode = greeter.mode;
|
||||
|
||||
match mode {
|
||||
Mode::Username => greeter.username = value,
|
||||
Mode::Username => greeter.username.value = value,
|
||||
Mode::Password => greeter.buffer = value,
|
||||
Mode::Command => greeter.buffer = value,
|
||||
_ => {}
|
||||
@ -313,7 +313,7 @@ async fn insert_key(greeter: &mut Greeter, c: char) {
|
||||
// of the cursor.
|
||||
async fn delete_key(greeter: &mut Greeter, key: KeyCode) {
|
||||
let value = match greeter.mode {
|
||||
Mode::Username => &greeter.username,
|
||||
Mode::Username => &greeter.username.value,
|
||||
Mode::Password => &greeter.buffer,
|
||||
Mode::Command => &greeter.buffer,
|
||||
Mode::Users | Mode::Sessions | Mode::Power | Mode::Processing => return,
|
||||
@ -332,7 +332,7 @@ async fn delete_key(greeter: &mut Greeter, key: KeyCode) {
|
||||
let value = left.chain(right).collect();
|
||||
|
||||
match greeter.mode {
|
||||
Mode::Username => greeter.username = value,
|
||||
Mode::Username => greeter.username.value = value,
|
||||
Mode::Password => greeter.buffer = value,
|
||||
Mode::Command => greeter.buffer = value,
|
||||
Mode::Users | Mode::Sessions | Mode::Power | Mode::Processing => return,
|
||||
@ -349,18 +349,22 @@ async fn validate_username(greeter: &mut Greeter, ipc: &Ipc) {
|
||||
greeter.working = true;
|
||||
greeter.message = None;
|
||||
|
||||
ipc.send(Request::CreateSession { username: greeter.username.clone() }).await;
|
||||
ipc
|
||||
.send(Request::CreateSession {
|
||||
username: greeter.username.value.clone(),
|
||||
})
|
||||
.await;
|
||||
greeter.buffer = String::new();
|
||||
|
||||
if greeter.remember_user_session {
|
||||
if let Ok(last_session) = get_last_user_session_path(&greeter.username) {
|
||||
if let Ok(last_session) = get_last_user_session_path(&greeter.username.value) {
|
||||
if let Some(last_session) = Session::from_path(greeter, last_session).cloned() {
|
||||
greeter.sessions.selected = greeter.sessions.options.iter().position(|sess| sess.path == last_session.path).unwrap_or(0);
|
||||
greeter.session_source = SessionSource::Session(greeter.sessions.selected);
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(command) = get_last_user_session(&greeter.username) {
|
||||
if let Ok(command) = get_last_user_session(&greeter.username.value) {
|
||||
greeter.session_source = SessionSource::Command(command);
|
||||
}
|
||||
}
|
||||
@ -374,7 +378,11 @@ mod test {
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use super::handle;
|
||||
use crate::{ipc::Ipc, ui::sessions::SessionSource, Greeter, Mode};
|
||||
use crate::{
|
||||
ipc::Ipc,
|
||||
ui::{common::masked::MaskedString, sessions::SessionSource},
|
||||
Greeter, Mode,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn ctrl_u() {
|
||||
@ -383,7 +391,7 @@ mod test {
|
||||
{
|
||||
let mut greeter = greeter.write().await;
|
||||
greeter.mode = Mode::Username;
|
||||
greeter.username = "apognu".to_string();
|
||||
greeter.username = MaskedString::from("apognu".to_string(), None);
|
||||
}
|
||||
|
||||
let result = handle(greeter.clone(), KeyEvent::new(KeyCode::Char('u'), KeyModifiers::CONTROL), Ipc::new()).await;
|
||||
@ -392,7 +400,7 @@ mod test {
|
||||
let status = greeter.read().await;
|
||||
|
||||
assert!(matches!(result, Ok(_)));
|
||||
assert_eq!(status.username, "".to_string());
|
||||
assert_eq!(status.username.value, "".to_string());
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -54,8 +54,12 @@ async fn run() -> Result<(), Box<dyn Error>> {
|
||||
let mut events = Events::new().await;
|
||||
let ipc = Ipc::new();
|
||||
|
||||
if greeter.remember && !greeter.username.is_empty() {
|
||||
ipc.send(Request::CreateSession { username: greeter.username.clone() }).await;
|
||||
if greeter.remember && !greeter.username.value.is_empty() {
|
||||
ipc
|
||||
.send(Request::CreateSession {
|
||||
username: greeter.username.value.clone(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
let greeter = Arc::new(RwLock::new(greeter));
|
||||
|
49
src/ui/common/masked.rs
Normal file
49
src/ui/common/masked.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MaskedString {
|
||||
pub value: String,
|
||||
pub mask: Option<String>,
|
||||
}
|
||||
|
||||
impl MaskedString {
|
||||
pub fn from(value: String, mask: Option<String>) -> MaskedString {
|
||||
MaskedString { value, mask }
|
||||
}
|
||||
|
||||
pub fn get(&self) -> &str {
|
||||
match self.mask {
|
||||
Some(ref mask) => mask,
|
||||
None => &self.value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zeroize(&mut self) {
|
||||
self.value.zeroize();
|
||||
|
||||
if let Some(ref mut mask) = self.mask {
|
||||
mask.zeroize();
|
||||
}
|
||||
|
||||
self.mask = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::MaskedString;
|
||||
|
||||
#[test]
|
||||
fn get_value_when_unmasked() {
|
||||
let masked = MaskedString::from("value".to_string(), None);
|
||||
|
||||
assert_eq!(masked.get(), "value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mask_when_masked() {
|
||||
let masked = MaskedString::from("value".to_string(), Some("mask".to_string()));
|
||||
|
||||
assert_eq!(masked.get(), "mask");
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod masked;
|
||||
pub mod menu;
|
||||
|
@ -53,7 +53,7 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame) -> Result<(u16, u16), Box<dyn
|
||||
f.render_widget(greeting_label, chunks[GREETING_INDEX]);
|
||||
}
|
||||
|
||||
let username_label = if greeter.user_menu && greeter.username.is_empty() {
|
||||
let username_label = if greeter.user_menu && greeter.username.value.is_empty() {
|
||||
let prompt_text = Span::from(fl!("select_user"));
|
||||
|
||||
Paragraph::new(prompt_text).alignment(Alignment::Center)
|
||||
@ -63,7 +63,7 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame) -> Result<(u16, u16), Box<dyn
|
||||
Paragraph::new(username_text)
|
||||
};
|
||||
|
||||
let username = greeter.username_mask.as_deref().unwrap_or_else(|| greeter.username.as_ref());
|
||||
let username = greeter.username.get();
|
||||
let username_value_text = Span::from(username);
|
||||
let username_value = Paragraph::new(username_value_text);
|
||||
|
||||
@ -71,7 +71,7 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame) -> Result<(u16, u16), Box<dyn
|
||||
Mode::Username | Mode::Password => {
|
||||
f.render_widget(username_label, chunks[USERNAME_INDEX]);
|
||||
|
||||
if !greeter.user_menu || !greeter.username.is_empty() {
|
||||
if !greeter.user_menu || !greeter.username.value.is_empty() {
|
||||
f.render_widget(
|
||||
username_value,
|
||||
Rect::new(
|
||||
@ -124,7 +124,7 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame) -> Result<(u16, u16), Box<dyn
|
||||
|
||||
match greeter.mode {
|
||||
Mode::Username => {
|
||||
let username_length = greeter.username.chars().count();
|
||||
let username_length = greeter.username.get().chars().count();
|
||||
let offset = get_cursor_offset(greeter, username_length);
|
||||
|
||||
Ok((2 + cursor.x + fl!("username").chars().count() as u16 + offset as u16, USERNAME_INDEX as u16 + cursor.y))
|
||||
|
@ -12,7 +12,7 @@ pub fn titleize(message: &str) -> String {
|
||||
pub fn should_hide_cursor(greeter: &Greeter) -> bool {
|
||||
greeter.working
|
||||
|| greeter.done
|
||||
|| (greeter.user_menu && greeter.mode == Mode::Username && greeter.username.is_empty())
|
||||
|| (greeter.user_menu && greeter.mode == Mode::Username && greeter.username.value.is_empty())
|
||||
|| (greeter.mode == Mode::Password && greeter.prompt.is_none())
|
||||
|| greeter.mode == Mode::Users
|
||||
|| greeter.mode == Mode::Sessions
|
||||
|
Loading…
Reference in New Issue
Block a user