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 "<sub>command</sub>{}",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, "<sub>process</sub>{}", 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 fmt::Display for Identity {51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {52 match self.kind.as_str() {53 "unix-user" => match self.details.get("uid").map(|v| &**v) {54 Some(Value::U32(uid)) => match User::from_uid(Uid::from_raw(*uid)) {55 Ok(Some(u)) => write!(56 f,57 "<sub>user</sub>{}<sup>{}</sup>{}",58 u.name,59 u.uid,60 if u.gecos.is_empty() {61 "".to_owned()62 } else {63 format!(": {}", escape(u.gecos.to_string_lossy()))64 }65 ),66 Ok(None) => emphasize("not found").fmt(f),67 Err(e) => {68 let user = format!("could not get user: {e}");69 emphasize(&user).fmt(f)?;70 Ok(())71 }72 },7374 _ => emphasize("unknown uid").fmt(f),75 },76 _ => emphasize(format!("identity of unknown kind: {}", self.kind)).fmt(f),77 }78 }79}8081impl Clone for Identity {82 fn clone(&self) -> Self {83 Self {84 kind: self.kind.clone(),85 details: self86 .details87 .iter()88 .map(|(k, v)| (k.clone(), v.try_clone().expect("no fds are expected")))89 .collect(),90 }91 }92}9394#[derive(Serialize, Deserialize, Type, PartialEq, Debug)]95pub struct BackendRequest {96 pub cookie: String,97 pub environment: HashMap<String, String>,98 pub prompter_path: String,99 pub identity: Identity,100}