1use std::collections::HashMap;2use std::{fmt, fs};34use nix::unistd::{Uid, User};5use serde::{Deserialize, Serialize};6use zbus::zvariant::{OwnedValue, Type, Value};78pub fn emphasize(s: impl AsRef<str>) -> String {9 format!("<span style=\"italic\"><{}></span>", escape(s),)10}11fn command(s: impl AsRef<str>) -> String {12 format!("<u><tt>{}</tt></u>", s.as_ref())13}14fn escape(s: impl AsRef<str>) -> String {15 s.as_ref()16 .replace("&", """)17 .replace("<", "<")18 .replace(">", ">")19}2021pub struct PidDisplay(pub u32);22impl fmt::Display for PidDisplay {23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {24 if self.0 == 1 {25 emphasize("init").fmt(f)26 } else if let Ok(proc) = fs::read_to_string(format!("/proc/{}/cmdline", self.0)) {27 write!(28 f,29 "command: {}",30 command(31 proc.replace("\0", " ")32 .strip_suffix(" ")33 .expect("cmdline should end with NUL")34 )35 )36 } else if let Ok(proc) = fs::read_to_string(format!("/proc/{}/comm", self.0)) {37 write!(f, "process: {}", command(proc.replace("\0", " ")))38 } else {39 emphasize("unknown process").fmt(f)40 }41 }42}4344#[derive(Serialize, Deserialize, Type, PartialEq, Debug)]45pub struct Identity {46 pub kind: String,47 pub details: HashMap<String, OwnedValue>,48}4950impl Identity {51 pub fn uid(&self) -> Option<Uid> {52 if self.kind != "unix-user" {53 return None;54 }55 let uid = self.details.get("uid")?;56 let Value::U32(uid) = &**uid else {57 return None;58 };59 Some(Uid::from_raw(*uid))60 }61}6263impl fmt::Display for Identity {64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {65 match self.kind.as_str() {66 "unix-user" => match self.details.get("uid").map(|v| &**v) {67 Some(Value::U32(uid)) => match User::from_uid(Uid::from_raw(*uid)) {68 Ok(Some(u)) => write!(69 f,70 "user: {} {} {}",71 u.name,72 u.uid,73 if u.gecos.is_empty() {74 "".to_owned()75 } else {76 format!(": {}", escape(u.gecos.to_string_lossy()))77 }78 ),79 Ok(None) => emphasize("not found").fmt(f),80 Err(e) => {81 let user = format!("could not get user: {e}");82 emphasize(&user).fmt(f)?;83 Ok(())84 }85 },8687 _ => emphasize("unknown uid").fmt(f),88 },89 _ => emphasize(format!("identity of unknown kind: {}", self.kind)).fmt(f),90 }91 }92}9394impl Clone for Identity {95 fn clone(&self) -> Self {96 Self {97 kind: self.kind.clone(),98 details: self99 .details100 .iter()101 .map(|(k, v)| (k.clone(), v.try_clone().expect("no fds are expected")))102 .collect(),103 }104 }105}106107#[derive(Serialize, Deserialize, Type, PartialEq, Debug)]108pub struct BackendRequest {109 pub cookie: String,110 pub environment: HashMap<String, String>,111 pub prompter_path: String,112 pub identity: Identity,113}