Skip to content

Commit 24e3bd2

Browse files
cli: Avoid crashing if items are locked
By not querying any sensitive data if the items are locked except the label which is queryable.
1 parent 78446c3 commit 24e3bd2

1 file changed

Lines changed: 100 additions & 41 deletions

File tree

cli/src/main.rs

Lines changed: 100 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -62,84 +62,130 @@ impl Termination for Error {
6262
#[derive(Serialize)]
6363
struct ItemOutput {
6464
label: String,
65-
secret: String,
66-
created_at: String,
67-
modified_at: String,
65+
/// Those are None if the item is locked
66+
#[serde(skip_serializing_if = "Option::is_none")]
67+
secret: Option<String>,
68+
#[serde(skip_serializing_if = "Option::is_none")]
69+
created_at: Option<String>,
70+
#[serde(skip_serializing_if = "Option::is_none")]
71+
modified_at: Option<String>,
6872
#[serde(skip_serializing_if = "Option::is_none")]
6973
schema: Option<String>,
7074
#[serde(skip_serializing_if = "Option::is_none")]
7175
content_type: Option<String>,
72-
attributes: HashMap<String, String>,
76+
#[serde(skip_serializing_if = "Option::is_none")]
77+
attributes: Option<HashMap<String, String>>,
78+
is_locked: bool,
7379
}
7480

7581
impl ItemOutput {
7682
fn new(
77-
secret: &oo7::Secret,
83+
secret: Option<&oo7::Secret>,
7884
label: &str,
79-
mut attributes: HashMap<String, String>,
80-
created: Duration,
81-
modified: Duration,
85+
mut attributes: Option<HashMap<String, String>>,
86+
created: Option<Duration>,
87+
modified: Option<Duration>,
88+
is_locked: bool,
8289
as_hex: bool,
8390
) -> Self {
84-
let bytes = secret.as_bytes();
8591
let local_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC);
8692

87-
let created = OffsetDateTime::from_unix_timestamp(created.as_secs() as i64)
88-
.unwrap()
89-
.to_offset(local_offset);
90-
let modified = OffsetDateTime::from_unix_timestamp(modified.as_secs() as i64)
91-
.unwrap()
92-
.to_offset(local_offset);
93+
let created = created.map(|created| {
94+
OffsetDateTime::from_unix_timestamp(created.as_secs() as i64)
95+
.unwrap()
96+
.to_offset(local_offset)
97+
});
98+
let modified = modified.map(|modified| {
99+
OffsetDateTime::from_unix_timestamp(modified.as_secs() as i64)
100+
.unwrap()
101+
.to_offset(local_offset)
102+
});
93103

94104
let format = time::format_description::parse_borrowed::<2>(
95105
"[year]-[month]-[day] [hour]:[minute]:[second]",
96106
)
97107
.unwrap();
98108

99-
let secret_str = if as_hex {
100-
hex::encode(bytes)
101-
} else {
102-
match std::str::from_utf8(bytes) {
103-
Ok(s) => s.to_string(),
104-
Err(_) => hex::encode(bytes),
109+
let secret_str = secret.map(|s| {
110+
let bytes = s.as_bytes();
111+
if as_hex {
112+
hex::encode(bytes)
113+
} else {
114+
match std::str::from_utf8(bytes) {
115+
Ok(s) => s.to_string(),
116+
Err(_) => hex::encode(bytes),
117+
}
105118
}
106-
};
119+
});
107120

108-
let schema = attributes.remove(oo7::XDG_SCHEMA_ATTRIBUTE);
109-
let content_type = attributes.remove(oo7::CONTENT_TYPE_ATTRIBUTE);
121+
let schema = attributes
122+
.as_mut()
123+
.and_then(|attrs| attrs.remove(oo7::XDG_SCHEMA_ATTRIBUTE));
124+
let content_type = attributes
125+
.as_mut()
126+
.and_then(|attrs| attrs.remove(oo7::CONTENT_TYPE_ATTRIBUTE));
110127

111128
Self {
112129
label: label.to_string(),
113130
secret: secret_str,
114-
created_at: created.format(&format).unwrap(),
115-
modified_at: modified.format(&format).unwrap(),
131+
created_at: created.map(|created| created.format(&format).unwrap()),
132+
modified_at: modified.map(|modified| modified.format(&format).unwrap()),
116133
schema,
117134
content_type,
118135
attributes,
136+
is_locked,
119137
}
120138
}
121139

122140
fn from_file_item(item: &oo7::file::UnlockedItem, as_hex: bool) -> Self {
123141
Self::new(
124-
&item.secret(),
142+
Some(&item.secret()),
125143
item.label(),
126-
item.attributes()
127-
.iter()
128-
.map(|(k, v)| (k.to_string(), v.to_string()))
129-
.collect(),
130-
item.created(),
131-
item.modified(),
144+
Some(
145+
item.attributes()
146+
.iter()
147+
.map(|(k, v)| (k.to_string(), v.to_string()))
148+
.collect(),
149+
),
150+
Some(item.created()),
151+
Some(item.modified()),
152+
false,
132153
as_hex,
133154
)
134155
}
135156

136157
async fn from_dbus_item(item: &oo7::dbus::Item, as_hex: bool) -> Result<Self, Error> {
158+
use oo7::dbus::ServiceError;
159+
160+
let is_locked = item.is_locked().await?;
161+
let secret = match item.secret().await {
162+
Ok(secret) => Ok(Some(secret)),
163+
Err(oo7::dbus::Error::Service(ServiceError::IsLocked(_))) => Ok(None),
164+
Err(e) => Err(e),
165+
}?;
166+
let attributes = match item.attributes().await {
167+
Ok(attributes) => Ok(Some(attributes)),
168+
Err(oo7::dbus::Error::Service(ServiceError::IsLocked(_))) => Ok(None),
169+
Err(e) => Err(e),
170+
}?;
171+
let created = match item.created().await {
172+
Ok(created) => Ok(Some(created)),
173+
Err(oo7::dbus::Error::Service(ServiceError::IsLocked(_))) => Ok(None),
174+
Err(e) => Err(e),
175+
}?;
176+
let modified = match item.modified().await {
177+
Ok(modified) => Ok(Some(modified)),
178+
Err(oo7::dbus::Error::Service(ServiceError::IsLocked(_))) => Ok(None),
179+
Err(e) => Err(e),
180+
}?;
181+
137182
Ok(Self::new(
138-
&item.secret().await?,
183+
secret.as_ref(),
139184
&item.label().await?,
140-
item.attributes().await?,
141-
item.created().await?,
142-
item.modified().await?,
185+
attributes,
186+
created,
187+
modified,
188+
is_locked,
143189
as_hex,
144190
))
145191
}
@@ -148,16 +194,29 @@ impl ItemOutput {
148194
impl fmt::Display for ItemOutput {
149195
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150196
writeln!(f, "[{}]", self.label)?;
151-
writeln!(f, "secret = {}", self.secret)?;
152-
writeln!(f, "created = {}", self.created_at)?;
153-
writeln!(f, "modified = {}", self.modified_at)?;
197+
if let Some(ref secret) = self.secret {
198+
writeln!(f, "secret = {}", secret)?;
199+
}
200+
if let Some(ref created_at) = self.created_at {
201+
writeln!(f, "created = {}", created_at)?;
202+
}
203+
if let Some(ref modified_at) = self.modified_at {
204+
writeln!(f, "modified = {}", modified_at)?;
205+
}
154206
if let Some(schema) = &self.schema {
155207
writeln!(f, "schema = {schema}")?;
156208
}
157209
if let Some(content_type) = &self.content_type {
158210
writeln!(f, "content_type = {content_type}")?;
159211
}
160-
writeln!(f, "attributes = {:?}", self.attributes)?;
212+
if let Some(attributes) = &self.attributes {
213+
writeln!(f, "attributes = {:?}", attributes)?;
214+
}
215+
if self.is_locked {
216+
writeln!(f, "locked = true")?;
217+
} else {
218+
writeln!(f, "locked = false")?;
219+
}
161220
Ok(())
162221
}
163222
}

0 commit comments

Comments
 (0)