diff --git a/src/configuration.rs b/src/configuration.rs
index 1565d2e..ba07b1a 100644
--- a/src/configuration.rs
+++ b/src/configuration.rs
@@ -14,11 +14,12 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-use crate::passwords::Password;
+use crate::passwords::{Password, try_retrieve_password_from_keyring};
use jid::BareJid;
use keyring::Entry;
-use log::error;
+use log::{error, info};
use serde_derive::{Deserialize, Serialize};
+use crate::types::LoginCredentials;
/// The configuration struct containing all the configuration options.
#[derive(Default, Debug, Serialize, Deserialize)]
@@ -70,3 +71,22 @@ pub fn load_config() -> Configuration {
}
}
}
+
+/// Retrieve the full login credentials from the config and keyring, if they exist.
+pub fn try_retrieve_credentials(config: &Configuration) -> Option {
+ if let (Some(user), Some(nick)) = (&config.stored_username, &config.stored_default_nick) {
+ if let Some(password) = try_retrieve_password_from_keyring(&user) {
+ Some(LoginCredentials {
+ username: user.clone(),
+ default_nick: nick.clone(),
+ password,
+ })
+ } else {
+ info!("No stored password found; will not try to log in.");
+ None
+ }
+ } else {
+ info!("No stored username or default nick found; will not try to log in.");
+ None
+ }
+}
\ No newline at end of file
diff --git a/src/widgets/login_screen.rs b/src/widgets/login_screen.rs
index dfa72f3..1f0adf6 100644
--- a/src/widgets/login_screen.rs
+++ b/src/widgets/login_screen.rs
@@ -19,6 +19,11 @@ use dioxus::hooks::use_state;
use dioxus::prelude::*;
use std::fmt::Debug;
+use std::str::FromStr;
+use jid::BareJid;
+use log::error;
+use crate::passwords::Password;
+use crate::types::LoginCredentials;
#[derive(Debug, Clone, PartialEq)]
pub enum LoginStatus {
@@ -49,6 +54,32 @@ impl Debug for LoginAttempt {
}
}
+pub fn validate_login_attempt(x: LoginAttempt) -> Result {
+ let LoginAttempt {
+ username,
+ default_nick,
+ password,
+ } = x;
+
+ // First, validate the username as a jid:
+ let jid = match BareJid::from_str(&username) {
+ Ok(x) => x,
+ Err(e) => {
+ error!("Invalid JID: {}", e);
+ return Err(format!("Invalid JID: {}", e));
+ }
+ };
+
+ // Wrap the password in a Password struct.
+ let password = Password(password);
+
+ Ok(LoginCredentials {
+ username: jid,
+ default_nick,
+ password,
+ })
+}
+
/// The props for the login screen widget, including:
/// * The xmpp address to pre-fill in the username field.
/// * The default nick to pre-fill in the default nick field.
diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs
index fd11da8..3d72a37 100644
--- a/src/widgets/mod.rs
+++ b/src/widgets/mod.rs
@@ -23,6 +23,7 @@ use crate::widgets::room_view::RoomView;
use crate::widgets::sidebar::SideBar;
use crate::xmpp_interface::NetworkCommand;
use dioxus::core::{Element, Scope};
+use crate::widgets::login_screen::validate_login_attempt;
use dioxus::prelude::*;
use futures_util::StreamExt;
@@ -30,7 +31,7 @@ use jid::BareJid;
use log::{error, info};
use std::collections::HashMap;
-use crate::configuration::{load_config, Configuration};
+use crate::configuration::{load_config, Configuration, try_retrieve_credentials};
use crate::xmpp_interface;
use crate::configuration::store_login_details;
@@ -46,24 +47,6 @@ pub mod room_view;
pub mod send_message;
pub mod sidebar;
-fn try_retrieve_credentials(config: &Configuration) -> Option {
- if let (Some(user), Some(nick)) = (&config.stored_username, &config.stored_default_nick) {
- if let Some(password) = try_retrieve_password_from_keyring(&user) {
- Some(LoginCredentials {
- username: user.clone(),
- default_nick: nick.clone(),
- password,
- })
- } else {
- info!("No stored password found; will not try to log in.");
- None
- }
- } else {
- info!("No stored username or default nick found; will not try to log in.");
- None
- }
-}
-
pub fn App(cx: Scope) -> Element {
let messages = use_ref(cx, || HashMap::new());
let current_room = use_state(cx, || None::);
@@ -103,34 +86,18 @@ pub fn App(cx: Scope) -> Element {
cached_nick: config.read().stored_default_nick.clone().unwrap_or("".to_string()),
login_state: connection_status.current().as_ref().clone(),
on_login_attempt: move |x: LoginAttempt| {
-
- let LoginAttempt { username, default_nick, password } = x;
-
- // First, validate the username as a jid:
- let jid = match BareJid::from_str(&username) {
- Ok(x) => x,
- Err(e) => {
- error!("Invalid JID: {}", e);
- return;
- }
- };
-
- // Wrap the password in a Password struct.
- let password = Password(password);
-
- // Store the login details in the config and keyring for auto-login next time.
- config.with_mut(|c| {
- store_login_details(jid.clone(), default_nick.clone(), &password, c);
- });
-
- // Finally, send the login command to the xmpp interface.
- coroutine.send(NetworkCommand::TryLogin {
- credentials: LoginCredentials {
- username: jid,
- default_nick,
- password,
+ // Validate the login attempt.
+ match validate_login_attempt(x) {
+ Ok(x) => {
+ config.with_mut(|c| {
+ store_login_details(x.username.clone(), x.default_nick.clone(), &x.password, c);
+ });
+ coroutine.send(NetworkCommand::TryLogin { credentials: x });
},
- });
+ Err(e) => {
+ error!("Invalid login attempt: {}", e);
+ }
+ }
},
}
}
@@ -138,7 +105,6 @@ pub fn App(cx: Scope) -> Element {
} else {
// We're logged in; show a sidebar and a room view.
-
rsx!{
// Sidebar.