Format Rust sources at 100 columns
This commit is contained in:
1 parent
4661f595f8
commit
610478f8c7
336 files changed
+23497
-7892
No files matched your search
@@ -94,10 +94,21 @@ struct Agent {
|
||||
impl Agent {
|
||||
async fn vendor(&self, action_id: &str) -> (String, String) {
|
||||
let lookup = async {
|
||||
let authority = zbus::Proxy::new(&self.connection, AUTHORITY, AUTHORITY_PATH, AUTHORITY_INTERFACE).await?;
|
||||
let authority = zbus::Proxy::new(
|
||||
&self.connection,
|
||||
AUTHORITY,
|
||||
AUTHORITY_PATH,
|
||||
AUTHORITY_INTERFACE,
|
||||
)
|
||||
.await?;
|
||||
let locale = std::env::var("LANG").unwrap_or_default();
|
||||
let actions: Vec<ActionDescription> = authority.call("EnumerateActions", &(locale,)).await?;
|
||||
Ok::<_, zbus::Error>(actions.into_iter().find(|action| action.action_id == action_id))
|
||||
let actions: Vec<ActionDescription> =
|
||||
authority.call("EnumerateActions", &(locale,)).await?;
|
||||
Ok::<_, zbus::Error>(
|
||||
actions
|
||||
.into_iter()
|
||||
.find(|action| action.action_id == action_id),
|
||||
)
|
||||
};
|
||||
// Missing metadata must never prevent authentication or cancellation.
|
||||
match tokio::time::timeout(std::time::Duration::from_secs(2), lookup).await {
|
||||
@@ -119,8 +130,9 @@ impl Agent {
|
||||
identities: Vec<Identity>,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let allowed = available_identities(&identities);
|
||||
let uid = choose_identity(&allowed)
|
||||
.ok_or_else(|| zbus::fdo::Error::Failed("No supported authentication identity".into()))?;
|
||||
let uid = choose_identity(&allowed).ok_or_else(|| {
|
||||
zbus::fdo::Error::Failed("No supported authentication identity".into())
|
||||
})?;
|
||||
let cancelled = Arc::new(AtomicBool::new(false));
|
||||
|
||||
{
|
||||
@@ -176,7 +188,11 @@ fn available_identities(identities: &[Identity]) -> Vec<u32> {
|
||||
for uid in identities
|
||||
.iter()
|
||||
.filter(|(kind, _)| kind == "unix-user")
|
||||
.filter_map(|(_, details)| details.get("uid").and_then(|uid| u32::try_from(uid.clone()).ok()))
|
||||
.filter_map(|(_, details)| {
|
||||
details
|
||||
.get("uid")
|
||||
.and_then(|uid| u32::try_from(uid.clone()).ok())
|
||||
})
|
||||
.filter(|uid| *uid <= i32::MAX as u32)
|
||||
{
|
||||
if !available.contains(&uid) {
|
||||
@@ -212,7 +228,10 @@ fn process_subject() -> Result<(String, HashMap<String, Value<'static>>), String
|
||||
.map_err(|error| error.to_string())?;
|
||||
let mut details = HashMap::new();
|
||||
details.insert("pid".to_owned(), Value::from(std::process::id()));
|
||||
details.insert("uid".to_owned(), Value::from(unsafe { libc::geteuid() } as i32));
|
||||
details.insert(
|
||||
"uid".to_owned(),
|
||||
Value::from(unsafe { libc::geteuid() } as i32),
|
||||
);
|
||||
details.insert("start-time".to_owned(), Value::from(started));
|
||||
Ok(("unix-process".into(), details))
|
||||
}
|
||||
@@ -233,7 +252,10 @@ async fn session_subject(
|
||||
"org.freedesktop.login1.Manager",
|
||||
)
|
||||
.await?;
|
||||
let path: zbus::zvariant::OwnedObjectPath = match manager.call("GetSessionByPID", &(std::process::id(),)).await {
|
||||
let path: zbus::zvariant::OwnedObjectPath = match manager
|
||||
.call("GetSessionByPID", &(std::process::id(),))
|
||||
.await
|
||||
{
|
||||
Ok(path) => path,
|
||||
Err(error) => {
|
||||
// A launcher in the user manager can be outside the session cgroup
|
||||
@@ -273,11 +295,15 @@ async fn run_agent() -> Result<(), Box<dyn std::error::Error>> {
|
||||
)
|
||||
.await?;
|
||||
let subject = session_subject(&connection).await?;
|
||||
let authority = zbus::Proxy::new(&connection, AUTHORITY, AUTHORITY_PATH, AUTHORITY_INTERFACE).await?;
|
||||
let authority =
|
||||
zbus::Proxy::new(&connection, AUTHORITY, AUTHORITY_PATH, AUTHORITY_INTERFACE).await?;
|
||||
let locale = std::env::var("LANG").unwrap_or_default();
|
||||
|
||||
authority
|
||||
.call::<_, _, ()>("RegisterAuthenticationAgent", &(subject, locale, AGENT_PATH))
|
||||
.call::<_, _, ()>(
|
||||
"RegisterAuthenticationAgent",
|
||||
&(subject, locale, AGENT_PATH),
|
||||
)
|
||||
.await?;
|
||||
std::future::pending::<()>().await;
|
||||
|
||||
@@ -343,9 +369,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn prompt_protocol_keeps_selection_response_and_echo_fields() {
|
||||
let selection: PromptEvent =
|
||||
serde_json::from_str(r#"{"type":"select_identity","generation":{"selection":2,"attempt":0},"uid":1001}"#)
|
||||
.unwrap();
|
||||
let selection: PromptEvent = serde_json::from_str(
|
||||
r#"{"type":"select_identity","generation":{"selection":2,"attempt":0},"uid":1001}"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
selection,
|
||||
PromptEvent::SelectIdentity {
|
||||
@@ -498,9 +525,15 @@ mod tests {
|
||||
agent.vendor("test.action").await,
|
||||
("Test vendor".into(), "https://example.test/vendor".into())
|
||||
);
|
||||
assert_eq!(agent.vendor("missing.action").await, (String::new(), String::new()));
|
||||
assert_eq!(
|
||||
agent.vendor("missing.action").await,
|
||||
(String::new(), String::new())
|
||||
);
|
||||
server.close().await.unwrap();
|
||||
assert_eq!(agent.vendor("test.action").await, (String::new(), String::new()));
|
||||
assert_eq!(
|
||||
agent.vendor("test.action").await,
|
||||
(String::new(), String::new())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -516,7 +549,10 @@ mod tests {
|
||||
let (kind, details) = process_subject().unwrap();
|
||||
assert_eq!(kind, "unix-process");
|
||||
assert_eq!(details["pid"], Value::from(std::process::id()));
|
||||
assert_eq!(details["uid"], Value::from(unsafe { libc::geteuid() } as i32));
|
||||
assert_eq!(
|
||||
details["uid"],
|
||||
Value::from(unsafe { libc::geteuid() } as i32)
|
||||
);
|
||||
assert!(u64::try_from(details["start-time"].clone()).unwrap() > 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -114,13 +114,18 @@ fn content_height(description: &str, status: Option<&str>) -> f32 {
|
||||
.lines()
|
||||
.map(|line| line.chars().count().div_ceil(48).max(1))
|
||||
.sum();
|
||||
let status_height = status.map_or(0, |message| 14 + 18 * message.chars().count().div_ceil(48).clamp(1, 3));
|
||||
let status_height = status.map_or(0, |message| {
|
||||
14 + 18 * message.chars().count().div_ceil(48).clamp(1, 3)
|
||||
});
|
||||
(214 + 18 * lines.saturating_sub(1) + status_height).min(360) as f32
|
||||
}
|
||||
|
||||
fn dialog_height(request: &AuthenticationRequest, status: Option<&str>, expanded: bool) -> f32 {
|
||||
let extra = if request.identities.len() > 1 { 54. } else { 0. }
|
||||
+ if has_details(request) { 40. } else { 0. }
|
||||
let extra = if request.identities.len() > 1 {
|
||||
54.
|
||||
} else {
|
||||
0.
|
||||
} + if has_details(request) { 40. } else { 0. }
|
||||
+ if expanded { 96. } else { 0. };
|
||||
(content_height(&request.message, status) + extra).min(360.)
|
||||
}
|
||||
@@ -141,7 +146,10 @@ fn action_icon(name: &str) -> Option<widget::icon::Handle> {
|
||||
.map(widget::icon::from_path)
|
||||
}
|
||||
|
||||
fn read_events(lines: impl Iterator<Item = std::io::Result<String>>, queue: &Mutex<VecDeque<PromptEvent>>) {
|
||||
fn read_events(
|
||||
lines: impl Iterator<Item = std::io::Result<String>>,
|
||||
queue: &Mutex<VecDeque<PromptEvent>>,
|
||||
) {
|
||||
for line in lines {
|
||||
let Ok(line) = line else { break };
|
||||
if let Ok(event) = serde_json::from_str(&line) {
|
||||
@@ -242,7 +250,11 @@ impl Prompt {
|
||||
|
||||
impl cosmic::Application for Prompt {
|
||||
type Executor = cosmic::executor::Default;
|
||||
type Flags = (Arc<Mutex<VecDeque<PromptEvent>>>, AuthenticationRequest, Appearance);
|
||||
type Flags = (
|
||||
Arc<Mutex<VecDeque<PromptEvent>>>,
|
||||
AuthenticationRequest,
|
||||
Appearance,
|
||||
);
|
||||
type Message = Message;
|
||||
const APP_ID: &'static str = "dev.ferese.Authentication";
|
||||
|
||||
@@ -255,11 +267,15 @@ impl cosmic::Application for Prompt {
|
||||
}
|
||||
|
||||
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||
Some(self.appearance.palette().application_style(if self.material.is_some() {
|
||||
cosmic::iced::Color::TRANSPARENT
|
||||
} else {
|
||||
self.appearance.surface
|
||||
}))
|
||||
Some(
|
||||
self.appearance
|
||||
.palette()
|
||||
.application_style(if self.material.is_some() {
|
||||
cosmic::iced::Color::TRANSPARENT
|
||||
} else {
|
||||
self.appearance.surface
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn init(mut core: Core, (incoming, request, appearance): Self::Flags) -> (Self, Task<Message>) {
|
||||
@@ -303,7 +319,8 @@ impl cosmic::Application for Prompt {
|
||||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
Subscription::batch([
|
||||
ferese_theme_client::service::subscription().map(|snapshot| Message::ThemeChanged(Box::new(snapshot))),
|
||||
ferese_theme_client::service::subscription()
|
||||
.map(|snapshot| Message::ThemeChanged(Box::new(snapshot))),
|
||||
cosmic::iced::time::every(Duration::from_millis(30)).map(|_| Message::Tick),
|
||||
cosmic::iced::event::listen_with(|event, _, id| match event {
|
||||
cosmic::iced::Event::Window(cosmic::iced::window::Event::Opened { .. }) => {
|
||||
@@ -321,8 +338,11 @@ impl cosmic::Application for Prompt {
|
||||
return cosmic::command::set_theme(self.appearance.theme());
|
||||
}
|
||||
Message::WindowOpened(id) => {
|
||||
return cosmic::iced::window::run(id, ferese_theme_client::material::ModalMaterial::attach)
|
||||
.map(|result| cosmic::Action::App(Message::MaterialAttached(result)));
|
||||
return cosmic::iced::window::run(
|
||||
id,
|
||||
ferese_theme_client::material::ModalMaterial::attach,
|
||||
)
|
||||
.map(|result| cosmic::Action::App(Message::MaterialAttached(result)));
|
||||
}
|
||||
Message::MaterialAttached(result) => {
|
||||
self.material = result.ok();
|
||||
@@ -336,7 +356,8 @@ impl cosmic::Application for Prompt {
|
||||
if uid == self.request.selected_uid
|
||||
&& generation.selection == self.request.generation.selection
|
||||
&& (generation.attempt > self.request.generation.attempt
|
||||
|| (generation == self.request.generation && self.awaiting_ack)) =>
|
||||
|| (generation == self.request.generation
|
||||
&& self.awaiting_ack)) =>
|
||||
{
|
||||
self.request.generation = generation;
|
||||
self.reset_authentication(uid);
|
||||
@@ -422,12 +443,18 @@ impl cosmic::Application for Prompt {
|
||||
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let palette = &self.appearance;
|
||||
let material_opacity = if palette.high_contrast { 1.0 } else { palette.surface.a };
|
||||
let material_opacity = if palette.high_contrast {
|
||||
1.0
|
||||
} else {
|
||||
palette.surface.a
|
||||
};
|
||||
let mut input = widget::text_input(&self.question, self.answer.as_str())
|
||||
.id(widget::Id::new("auth-response"))
|
||||
.font(palette.font)
|
||||
.padding([7, 12])
|
||||
.style(ferese_theme::controls::authentication_input(palette.palette()));
|
||||
.style(ferese_theme::controls::authentication_input(
|
||||
palette.palette(),
|
||||
));
|
||||
if !self.echo {
|
||||
input = input.password();
|
||||
}
|
||||
@@ -438,7 +465,9 @@ impl cosmic::Application for Prompt {
|
||||
});
|
||||
}
|
||||
let action = button::custom(ferese_theme::text("Authenticate", palette.font).size(13))
|
||||
.class(ferese_theme::controls::authentication_button(palette.palette()))
|
||||
.class(ferese_theme::controls::authentication_button(
|
||||
palette.palette(),
|
||||
))
|
||||
.height(Length::Fixed(36.))
|
||||
.padding([8, 16])
|
||||
.on_press_maybe((!self.waiting && !self.answer.is_empty()).then_some(Message::Submit));
|
||||
@@ -461,7 +490,10 @@ impl cosmic::Application for Prompt {
|
||||
.height(40)
|
||||
.center_x(40)
|
||||
.center_y(40)
|
||||
.class(ferese_theme::controls::surface(palette.accent.scale_alpha(0.13), 12.,)),
|
||||
.class(ferese_theme::controls::surface(
|
||||
palette.accent.scale_alpha(0.13),
|
||||
12.,
|
||||
)),
|
||||
column![
|
||||
ferese_theme::text("Authentication required", palette.font).size(18),
|
||||
ferese_theme::text(format!("Confirm as {user}"), palette.font)
|
||||
@@ -472,9 +504,10 @@ impl cosmic::Application for Prompt {
|
||||
]
|
||||
.spacing(12)
|
||||
.align_y(Alignment::Center);
|
||||
let mut information = column![ferese_theme::text(&self.request.message, palette.font).size(13)]
|
||||
.spacing(10)
|
||||
.width(Length::Fill);
|
||||
let mut information =
|
||||
column![ferese_theme::text(&self.request.message, palette.font).size(13)]
|
||||
.spacing(10)
|
||||
.width(Length::Fill);
|
||||
if has_details(&self.request) {
|
||||
information = information.push(
|
||||
button::custom(
|
||||
@@ -522,15 +555,26 @@ impl cosmic::Application for Prompt {
|
||||
ferese_theme::text("Account", palette.font)
|
||||
.size(12)
|
||||
.class(theme::Text::Color(palette.muted)),
|
||||
widget::dropdown(&self.identity_names[..], selected, Message::SelectIdentity)
|
||||
.width(Length::Fill),
|
||||
ferese_theme::icons::tinted(ferese_theme::icons::CHEVRON_DOWN, 16, palette.muted),
|
||||
widget::dropdown(
|
||||
&self.identity_names[..],
|
||||
selected,
|
||||
Message::SelectIdentity
|
||||
)
|
||||
.width(Length::Fill),
|
||||
ferese_theme::icons::tinted(
|
||||
ferese_theme::icons::CHEVRON_DOWN,
|
||||
16,
|
||||
palette.muted
|
||||
),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_y(Alignment::Center),
|
||||
)
|
||||
.padding([4, 10])
|
||||
.class(ferese_theme::controls::surface(palette.accent.scale_alpha(0.08), 8.)),
|
||||
.class(ferese_theme::controls::surface(
|
||||
palette.accent.scale_alpha(0.08),
|
||||
8.,
|
||||
)),
|
||||
);
|
||||
}
|
||||
body = body.push(input);
|
||||
@@ -582,7 +626,9 @@ fn detail_row<'a>(key: &'a str, value: &'a str, palette: &Appearance) -> Element
|
||||
.size(12)
|
||||
.class(theme::Text::Color(palette.muted))
|
||||
.width(Length::Fixed(106.)),
|
||||
ferese_theme::text(value, palette.font).size(12).width(Length::Fill),
|
||||
ferese_theme::text(value, palette.font)
|
||||
.size(12)
|
||||
.width(Length::Fill),
|
||||
]
|
||||
.spacing(8)
|
||||
.into()
|
||||
@@ -595,7 +641,9 @@ mod tests {
|
||||
|
||||
use cosmic::app::Core;
|
||||
|
||||
use super::{Appearance, Message, Prompt, action_icon, content_height, dialog_height, has_details};
|
||||
use super::{
|
||||
Appearance, Message, Prompt, action_icon, content_height, dialog_height, has_details,
|
||||
};
|
||||
use crate::tests::request_fixture;
|
||||
|
||||
#[test]
|
||||
@@ -610,7 +658,8 @@ mod tests {
|
||||
let (reader, mut writer) = UnixStream::pair().unwrap();
|
||||
let incoming = Arc::new(Mutex::new(VecDeque::new()));
|
||||
let queue = incoming.clone();
|
||||
let reader_thread = std::thread::spawn(move || super::read_events(BufReader::new(reader).lines(), &queue));
|
||||
let reader_thread =
|
||||
std::thread::spawn(move || super::read_events(BufReader::new(reader).lines(), &queue));
|
||||
writeln!(
|
||||
writer,
|
||||
"{{\"type\":\"request\",\"generation\":{{\"selection\":0,\"attempt\":0}},\"prompt\":\"Password:\",\"echo\":false}}"
|
||||
@@ -618,9 +667,13 @@ mod tests {
|
||||
.unwrap();
|
||||
drop(writer);
|
||||
reader_thread.join().unwrap();
|
||||
assert!(matches!(incoming.lock().unwrap().back(), Some(PromptEvent::Cancel)));
|
||||
assert!(matches!(
|
||||
incoming.lock().unwrap().back(),
|
||||
Some(PromptEvent::Cancel)
|
||||
));
|
||||
let appearance = Appearance::from_resolved(&ferese_config::theme::default_theme());
|
||||
let (mut prompt, _) = Prompt::init(Core::default(), (incoming, request_fixture(), appearance));
|
||||
let (mut prompt, _) =
|
||||
Prompt::init(Core::default(), (incoming, request_fixture(), appearance));
|
||||
*prompt.answer = "test-password".into();
|
||||
prompt.waiting = false;
|
||||
let _ = prompt.update(Message::Tick);
|
||||
@@ -636,7 +689,10 @@ mod tests {
|
||||
|
||||
let incoming = Arc::new(Mutex::new(VecDeque::new()));
|
||||
let appearance = Appearance::from_resolved(&ferese_config::theme::default_theme());
|
||||
let (mut prompt, _) = Prompt::init(Core::default(), (incoming.clone(), request_fixture(), appearance));
|
||||
let (mut prompt, _) = Prompt::init(
|
||||
Core::default(),
|
||||
(incoming.clone(), request_fixture(), appearance),
|
||||
);
|
||||
assert_eq!(prompt.select_identity(1), Some(1001));
|
||||
let older = prompt.request.generation;
|
||||
assert_eq!(prompt.select_identity(0), Some(1000));
|
||||
@@ -700,7 +756,10 @@ mod tests {
|
||||
assert_eq!(prompt.question, "Current password");
|
||||
|
||||
// A fresh retry gets its own generation, even for the same account.
|
||||
let retry = Generation { attempt: 1, ..current };
|
||||
let retry = Generation {
|
||||
attempt: 1,
|
||||
..current
|
||||
};
|
||||
incoming.lock().unwrap().extend([
|
||||
PromptEvent::IdentityChanged {
|
||||
generation: retry,
|
||||
@@ -732,7 +791,11 @@ mod tests {
|
||||
let appearance = Appearance::from_resolved(&ferese_config::theme::default_theme());
|
||||
let (mut prompt, _) = <Prompt as cosmic::Application>::init(
|
||||
Core::default(),
|
||||
(Arc::new(Mutex::new(VecDeque::new())), request_fixture(), appearance),
|
||||
(
|
||||
Arc::new(Mutex::new(VecDeque::new())),
|
||||
request_fixture(),
|
||||
appearance,
|
||||
),
|
||||
);
|
||||
*prompt.answer = "test-response".into();
|
||||
prompt.waiting = false;
|
||||
@@ -755,7 +818,10 @@ mod tests {
|
||||
fn full_requests_and_expanded_details_keep_the_height_cap() {
|
||||
let request = request_fixture();
|
||||
assert_eq!(dialog_height(&request, None, false), 360.);
|
||||
assert_eq!(dialog_height(&request, Some("Password not accepted"), true), 360.);
|
||||
assert_eq!(
|
||||
dialog_height(&request, Some("Password not accepted"), true),
|
||||
360.
|
||||
);
|
||||
assert!(has_details(&request));
|
||||
let mut short = request;
|
||||
short.message = "Short request".into();
|
||||
|
||||
@@ -37,21 +37,29 @@ impl Api {
|
||||
static LIBRARIES: OnceLock<Result<(Library, Library), String>> = OnceLock::new();
|
||||
let (agent, polkit) = LIBRARIES
|
||||
.get_or_init(|| {
|
||||
let agent = Library::new("libpolkit-agent-1.so.0").map_err(|e| e.to_string())?;
|
||||
let polkit = Library::new("libpolkit-gobject-1.so.0").map_err(|e| e.to_string())?;
|
||||
let agent =
|
||||
Library::new("libpolkit-agent-1.so.0").map_err(|e| e.to_string())?;
|
||||
let polkit =
|
||||
Library::new("libpolkit-gobject-1.so.0").map_err(|e| e.to_string())?;
|
||||
Ok((agent, polkit))
|
||||
})
|
||||
.as_ref()
|
||||
.map_err(Clone::clone)?;
|
||||
let user_new = *polkit.get(b"polkit_unix_user_new\0").map_err(|e| e.to_string())?;
|
||||
let session_new = *agent.get(b"polkit_agent_session_new\0").map_err(|e| e.to_string())?;
|
||||
let user_new = *polkit
|
||||
.get(b"polkit_unix_user_new\0")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let session_new = *agent
|
||||
.get(b"polkit_agent_session_new\0")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let initiate = *agent
|
||||
.get(b"polkit_agent_session_initiate\0")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let response = *agent
|
||||
.get(b"polkit_agent_session_response\0")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let cancel = *agent.get(b"polkit_agent_session_cancel\0").map_err(|e| e.to_string())?;
|
||||
let cancel = *agent
|
||||
.get(b"polkit_agent_session_cancel\0")
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(Self {
|
||||
user_new,
|
||||
@@ -69,7 +77,9 @@ pub fn check() -> Result<(), String> {
|
||||
}
|
||||
|
||||
pub(crate) fn username(uid: u32) -> String {
|
||||
let output = Command::new("getent").args(["passwd", &uid.to_string()]).output();
|
||||
let output = Command::new("getent")
|
||||
.args(["passwd", &uid.to_string()])
|
||||
.output();
|
||||
output
|
||||
.ok()
|
||||
.filter(|output| output.status.success())
|
||||
@@ -132,21 +142,32 @@ fn prompt_process(request: AuthenticationRequest) -> Result<PromptProcess, Strin
|
||||
Ok(process)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn request_signal(_session: Object, prompt: *const c_char, echo: c_int, data: *mut c_void) {
|
||||
unsafe extern "C" fn request_signal(
|
||||
_session: Object,
|
||||
prompt: *const c_char,
|
||||
echo: c_int,
|
||||
data: *mut c_void,
|
||||
) {
|
||||
let tx = unsafe { &*(data as *const Sender<SessionEvent>) };
|
||||
let prompt = unsafe { CStr::from_ptr(prompt) }.to_string_lossy().into_owned();
|
||||
let prompt = unsafe { CStr::from_ptr(prompt) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let _ = tx.send(SessionEvent::Request(prompt, echo != 0));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn info(_session: Object, text: *const c_char, data: *mut c_void) {
|
||||
let tx = unsafe { &*(data as *const Sender<SessionEvent>) };
|
||||
let text = unsafe { CStr::from_ptr(text) }.to_string_lossy().into_owned();
|
||||
let text = unsafe { CStr::from_ptr(text) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let _ = tx.send(SessionEvent::Info(text));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn error(_session: Object, text: *const c_char, data: *mut c_void) {
|
||||
let tx = unsafe { &*(data as *const Sender<SessionEvent>) };
|
||||
let text = unsafe { CStr::from_ptr(text) }.to_string_lossy().into_owned();
|
||||
let text = unsafe { CStr::from_ptr(text) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let _ = tx.send(SessionEvent::Error(text));
|
||||
}
|
||||
|
||||
@@ -155,7 +176,12 @@ unsafe extern "C" fn completed(_session: Object, success: c_int, data: *mut c_vo
|
||||
let _ = tx.send(SessionEvent::Completed(success != 0));
|
||||
}
|
||||
|
||||
unsafe fn connect(session: Object, name: &'static CStr, callback: gobject_ffi::GCallback, data: *mut c_void) {
|
||||
unsafe fn connect(
|
||||
session: Object,
|
||||
name: &'static CStr,
|
||||
callback: gobject_ffi::GCallback,
|
||||
data: *mut c_void,
|
||||
) {
|
||||
unsafe {
|
||||
gobject_ffi::g_signal_connect_data(
|
||||
session.cast(),
|
||||
@@ -195,7 +221,10 @@ impl Drop for SessionGuard {
|
||||
}
|
||||
|
||||
fn permitted_selection(request: &AuthenticationRequest, uid: u32) -> bool {
|
||||
request.identities.iter().any(|identity| identity.uid == uid)
|
||||
request
|
||||
.identities
|
||||
.iter()
|
||||
.any(|identity| identity.uid == uid)
|
||||
}
|
||||
|
||||
fn response_buffer(value: &str) -> Option<Zeroizing<Vec<u8>>> {
|
||||
@@ -273,7 +302,7 @@ fn run_session(
|
||||
unsafe extern "C" fn(Object, *const c_char, *mut c_void),
|
||||
unsafe extern "C" fn(),
|
||||
>(
|
||||
info as unsafe extern "C" fn(Object, *const c_char, *mut c_void)
|
||||
info as unsafe extern "C" fn(Object, *const c_char, *mut c_void),
|
||||
)),
|
||||
signal_data,
|
||||
);
|
||||
@@ -284,7 +313,7 @@ fn run_session(
|
||||
unsafe extern "C" fn(Object, *const c_char, *mut c_void),
|
||||
unsafe extern "C" fn(),
|
||||
>(
|
||||
error as unsafe extern "C" fn(Object, *const c_char, *mut c_void)
|
||||
error as unsafe extern "C" fn(Object, *const c_char, *mut c_void),
|
||||
)),
|
||||
signal_data,
|
||||
);
|
||||
@@ -295,7 +324,7 @@ fn run_session(
|
||||
unsafe extern "C" fn(Object, c_int, *mut c_void),
|
||||
unsafe extern "C" fn(),
|
||||
>(
|
||||
completed as unsafe extern "C" fn(Object, c_int, *mut c_void)
|
||||
completed as unsafe extern "C" fn(Object, c_int, *mut c_void),
|
||||
)),
|
||||
signal_data,
|
||||
);
|
||||
@@ -322,8 +351,13 @@ fn run_session(
|
||||
},
|
||||
)?;
|
||||
}
|
||||
SessionEvent::Info(text) => send(&mut process.writer, &PromptEvent::Info { generation, text })?,
|
||||
SessionEvent::Error(text) => send(&mut process.writer, &PromptEvent::Error { generation, text })?,
|
||||
SessionEvent::Info(text) => {
|
||||
send(&mut process.writer, &PromptEvent::Info { generation, text })?
|
||||
}
|
||||
SessionEvent::Error(text) => send(
|
||||
&mut process.writer,
|
||||
&PromptEvent::Error { generation, text },
|
||||
)?,
|
||||
SessionEvent::Completed(success) => outcome = Some(success),
|
||||
}
|
||||
}
|
||||
@@ -368,7 +402,11 @@ fn run_session(
|
||||
if !stopped
|
||||
&& (selected_uid.is_some()
|
||||
|| cancelled.load(Ordering::Acquire)
|
||||
|| process.child.try_wait().map_err(|e| e.to_string())?.is_some())
|
||||
|| process
|
||||
.child
|
||||
.try_wait()
|
||||
.map_err(|e| e.to_string())?
|
||||
.is_some())
|
||||
{
|
||||
unsafe { (api.cancel)(session) };
|
||||
stopped = true;
|
||||
@@ -402,7 +440,14 @@ pub fn authenticate(
|
||||
context
|
||||
.with_thread_default(|| {
|
||||
let mut process = prompt_process(request.clone())?;
|
||||
authenticate_sessions(&api, &mut request, &cookie, &context, &mut process, &cancelled)
|
||||
authenticate_sessions(
|
||||
&api,
|
||||
&mut request,
|
||||
&cookie,
|
||||
&context,
|
||||
&mut process,
|
||||
&cancelled,
|
||||
)
|
||||
})
|
||||
.map_err(|error| error.to_string())?
|
||||
}
|
||||
@@ -421,7 +466,9 @@ fn authenticate_sessions(
|
||||
loop {
|
||||
match run_session(api, request, cookie, context, process, cancelled) {
|
||||
Ok(SessionOutcome::Completed(true)) => break Ok(true),
|
||||
Ok(SessionOutcome::IdentityChanged { uid, generation }) if !cancelled.load(Ordering::Acquire) => {
|
||||
Ok(SessionOutcome::IdentityChanged { uid, generation })
|
||||
if !cancelled.load(Ordering::Acquire) =>
|
||||
{
|
||||
request.selected_uid = uid;
|
||||
request.generation = generation;
|
||||
}
|
||||
@@ -429,7 +476,9 @@ fn authenticate_sessions(
|
||||
failures += 1;
|
||||
// Switching accounts never resets this request's attempt budget.
|
||||
if failures >= MAX_AUTH_ATTEMPTS {
|
||||
break Err(format!("Authentication failed after {MAX_AUTH_ATTEMPTS} attempts"));
|
||||
break Err(format!(
|
||||
"Authentication failed after {MAX_AUTH_ATTEMPTS} attempts"
|
||||
));
|
||||
}
|
||||
request.generation.attempt += 1;
|
||||
}
|
||||
@@ -448,7 +497,12 @@ mod tests {
|
||||
|
||||
unsafe extern "C" fn fake_initiate(session: Object) {
|
||||
unsafe {
|
||||
gobject_ffi::g_signal_emit_by_name(session.cast(), c"request".as_ptr(), c"Password:".as_ptr(), 0 as c_int);
|
||||
gobject_ffi::g_signal_emit_by_name(
|
||||
session.cast(),
|
||||
c"request".as_ptr(),
|
||||
c"Password:".as_ptr(),
|
||||
0 as c_int,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +556,8 @@ mod tests {
|
||||
let mut uid = 1000;
|
||||
for line in BufReader::new(output).lines() {
|
||||
let Ok(line) = line else { break };
|
||||
if let Ok(PromptEvent::Request { generation, .. }) = serde_json::from_str::<PromptEvent>(&line)
|
||||
if let Ok(PromptEvent::Request { generation, .. }) =
|
||||
serde_json::from_str::<PromptEvent>(&line)
|
||||
{
|
||||
let count = counter.fetch_add(1, Ordering::SeqCst) + 1;
|
||||
let event = if count == 3 {
|
||||
@@ -527,7 +582,11 @@ mod tests {
|
||||
}
|
||||
}
|
||||
});
|
||||
let mut process = PromptProcess { child, writer, input };
|
||||
let mut process = PromptProcess {
|
||||
child,
|
||||
writer,
|
||||
input,
|
||||
};
|
||||
let mut request = request_fixture();
|
||||
let result = authenticate_sessions(
|
||||
&api,
|
||||
@@ -563,13 +622,21 @@ mod tests {
|
||||
let context = glib::MainContext::new();
|
||||
context
|
||||
.with_thread_default(|| {
|
||||
let mut child = Command::new("sleep").arg("5").stdin(Stdio::piped()).spawn().unwrap();
|
||||
let mut child = Command::new("sleep")
|
||||
.arg("5")
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let writer = BufWriter::new(child.stdin.take().unwrap());
|
||||
let cookie = CString::new("test-cookie").unwrap();
|
||||
let cancelled = AtomicBool::new(false);
|
||||
let mut request = request_fixture();
|
||||
let (tx, input) = mpsc::channel();
|
||||
let mut process = PromptProcess { child, writer, input };
|
||||
let mut process = PromptProcess {
|
||||
child,
|
||||
writer,
|
||||
input,
|
||||
};
|
||||
tx.send(PromptEvent::SelectIdentity {
|
||||
uid: 1001,
|
||||
generation: Generation {
|
||||
@@ -585,7 +652,8 @@ mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
run_session(&api, &request, &cookie, &context, &mut process, &cancelled).unwrap(),
|
||||
run_session(&api, &request, &cookie, &context, &mut process, &cancelled)
|
||||
.unwrap(),
|
||||
SessionOutcome::IdentityChanged {
|
||||
uid: 1001,
|
||||
generation: Generation {
|
||||
@@ -631,13 +699,15 @@ mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
run_session(&api, &request, &cookie, &context, &mut process, &cancelled).unwrap(),
|
||||
run_session(&api, &request, &cookie, &context, &mut process, &cancelled)
|
||||
.unwrap(),
|
||||
SessionOutcome::Completed(true)
|
||||
);
|
||||
assert_eq!(RESPONSES.load(Ordering::SeqCst), 1);
|
||||
tx.send(PromptEvent::Cancel).unwrap();
|
||||
assert_eq!(
|
||||
run_session(&api, &request, &cookie, &context, &mut process, &cancelled).unwrap(),
|
||||
run_session(&api, &request, &cookie, &context, &mut process, &cancelled)
|
||||
.unwrap(),
|
||||
SessionOutcome::Cancelled
|
||||
);
|
||||
})
|
||||
@@ -652,13 +722,24 @@ mod tests {
|
||||
let context = glib::MainContext::new();
|
||||
context
|
||||
.with_thread_default(|| {
|
||||
let mut child = Command::new("sleep").arg("5").stdin(Stdio::piped()).spawn().unwrap();
|
||||
let mut child = Command::new("sleep")
|
||||
.arg("5")
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let writer = BufWriter::new(child.stdin.take().unwrap());
|
||||
let (tx, input) = mpsc::channel();
|
||||
let mut process = PromptProcess { child, writer, input };
|
||||
let mut process = PromptProcess {
|
||||
child,
|
||||
writer,
|
||||
input,
|
||||
};
|
||||
for (selection, uid) in [(2, 1001), (3, 1000), (1, 1001), (2, 1001)] {
|
||||
tx.send(PromptEvent::SelectIdentity {
|
||||
generation: Generation { selection, attempt: 0 },
|
||||
generation: Generation {
|
||||
selection,
|
||||
attempt: 0,
|
||||
},
|
||||
uid,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Reference in new issue
Block a user