Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ A Polkit authentication agent for Wayland desktops, built with `iced_layershell`
* Lightweight and fast
* Built with Rust and the Iced toolkit
* Wayland native
* Retry mechanism (up to 3 attempts) if authentication fails

### Planned Features

* [ ] Retry if authentication fails
* [ ] Use system theme for a more integrated look and feel
* [ ] CSS-based styling for customization

Expand Down
110 changes: 92 additions & 18 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use iced_layershell::to_layer_message;
use polkit_agent_rs::polkit::UnixUser;
use std::collections::BTreeMap;

use futures::channel::mpsc::Sender;
use iced::widget::{Space, button, column, pick_list, row, text, text_input};
use iced::{Bottom, Center, Fill};
use polkit_agent_rs::RegisterFlags;
Expand All @@ -23,25 +24,57 @@ mod mypolkit;
use mypolkit::MyPolkit;

const OBJECT_PATH: &str = "/org/waycrate/PolicyKit1/AuthenticationAgent";
const MAX_RETRIES: u32 = 3;

fn start_session(session: &AgentSession, password: String, task: gio::Task<String>) {
fn start_session(
username: String,
cookie: String,
password: String,
task: gio::Task<String>,
window_id: Id,
sender: Arc<Mutex<Sender<Message>>>,
) {
let user: UnixUser = UnixUser::new_for_name(&username).unwrap();
let session = AgentSession::new(&user, &cookie);
let sub_loop = glib::MainLoop::new(None, true);

let sub_loop_2 = sub_loop.clone();
let sender_clone = sender.clone();

session.connect_completed(move |session, _success| {
session.connect_completed(move |session, success| {
unsafe {
task.clone().return_result(Ok("success".to_string()));
if success {
task.clone().return_result(Ok("success".to_string()));
let _ = sender_clone
.lock()
.unwrap()
.try_send(Message::AuthenticationSuccess(window_id));
} else {
task.clone().return_result(Err(glib::Error::new(
glib::FileError::Failed,
"Authentication failed",
)));
let _ = sender_clone
.lock()
.unwrap()
.try_send(Message::AuthenticationFailed(
window_id,
"Authentication failed".to_string(),
));
}
}
session.cancel();
sub_loop_2.quit();
});
session.connect_show_info(|_session, info| {

session.connect_show_info(move |_session, info| {
println!("info: {info}");
});
session.connect_show_error(|_session, error| {

session.connect_show_error(move |_session, error| {
eprintln!("error: {error}");
});

session.connect_request(move |session, request, _echo_on| {
println!("{}", request);
if !request.starts_with("Password:") {
Expand Down Expand Up @@ -83,11 +116,14 @@ struct AuthSession {
error: Option<String>,
task: gio::Task<String>,
message: String,
retry_count: u32,
max_retries: u32,
}

#[derive(Debug, Default)]
#[derive(Debug)]
struct PolkitApp {
sessions: BTreeMap<iced::window::Id, AuthSession>,
sender: Option<Arc<Mutex<Sender<Message>>>>,
}

#[to_layer_message(multi)]
Expand All @@ -103,6 +139,7 @@ pub enum Message {
AuthenticationSuccess(Id),
AuthenticationFailed(Id, String),
IcedEvent(Event),
SetSender(Arc<Mutex<Sender<Message>>>),
}

impl PolkitApp {
Expand All @@ -116,6 +153,7 @@ impl PolkitApp {
(
Self {
sessions: BTreeMap::new(),
sender: None,
},
Command::none(),
)
Expand All @@ -130,6 +168,7 @@ impl PolkitApp {
iced::Subscription::run(|| {
iced::stream::channel(100, |sender| {
let sender = Arc::new(Mutex::new(sender));
let sender_clone = sender.clone();

std::thread::spawn(move || {
let main_loop = glib::MainLoop::new(None, true);
Expand All @@ -154,7 +193,13 @@ impl PolkitApp {
main_loop.run();
});

futures::future::ready(())
async move {
let _ = sender_clone
.lock()
.unwrap()
.try_send(Message::SetSender(sender_clone.clone()));
futures::future::pending::<()>().await;
}
})
}),
iced::window::close_events().map(Message::WindowClosed),
Expand Down Expand Up @@ -190,6 +235,8 @@ impl PolkitApp {
error: None,
task,
message: messg,
retry_count: 0,
max_retries: MAX_RETRIES,
},
);

Expand Down Expand Up @@ -220,15 +267,21 @@ impl PolkitApp {
}

Message::Authenticate(id) => {
if let Some(session) = self.sessions.get(&id) {
let user: UnixUser = UnixUser::new_for_name(&session.selected_user).unwrap();
let ass = AgentSession::new(&user, &session.cookie);
if let Some(session) = self.sessions.get_mut(&id) {
let username = session.selected_user.clone();
let cookie = session.cookie.clone();
let password = session.password.clone();
let task = session.task.clone();

session.error = None;

start_session(&ass, session.password.clone(), session.task.clone());
} else {
return Command::none();
if let Some(sender) = self.sender.clone() {
std::thread::spawn(move || {
start_session(username, cookie, password, task, id, sender);
});
}
}
task::effect(Action::Window(WindowAction::Close(id)))
Command::none()
}

Message::AuthenticationSuccess(id) => {
Expand All @@ -237,7 +290,20 @@ impl PolkitApp {

Message::AuthenticationFailed(id, error) => {
if let Some(session) = self.sessions.get_mut(&id) {
session.error = Some(error);
session.retry_count += 1;

if session.retry_count >= session.max_retries {
return task::effect(Action::Window(WindowAction::Close(id)));
}

let remaining = session.max_retries - session.retry_count;
session.error = Some(format!(
"{}. {} attempt{} remaining.",
error,
remaining,
if remaining == 1 { "" } else { "s" }
));
session.password.clear();
}
Command::none()
}
Expand All @@ -246,6 +312,11 @@ impl PolkitApp {
task::effect(Action::Window(WindowAction::Close(id)))
}

Message::SetSender(sender) => {
self.sender = Some(sender);
Command::none()
}

_ => Command::none(),
}
}
Expand Down Expand Up @@ -289,9 +360,12 @@ impl PolkitApp {
.spacing(20)
.padding(25)
];
if let Some(_error) = &session.error {
// content = content
// .push(text(error).style(|theme| iced::theme::Text::Color(theme.palette().danger)));
if let Some(error) = &session.error {
content = content.push(
text(error)
.size(14)
.color(iced::Color::from_rgb(0.8, 0.0, 0.0)),
);
}

content = content.push(Space::with_height(Fill)).push(
Expand Down