usb_forensic/sources/
mountpoints2.rs1use crate::{Attribute, Claim, DeviceKey, HistorySource, Provenance, SourceKind, Value};
12use peripheral_core::mountpoints2::UserMount;
13
14pub struct MountPoints2Source<'a> {
16 mounts: &'a [UserMount],
17}
18
19impl<'a> MountPoints2Source<'a> {
20 #[must_use]
22 pub fn new(mounts: &'a [UserMount]) -> Self {
23 Self { mounts }
24 }
25}
26
27impl HistorySource for MountPoints2Source<'_> {
28 fn claims(&self) -> Vec<Claim> {
29 self.mounts
30 .iter()
31 .filter_map(|mount| {
32 let when = mount.last_mounted?;
34 Some(Claim {
35 device: DeviceKey(mount.volume_guid.clone()),
36 attribute: Attribute::LastConnected,
37 value: Value::Timestamp(when),
38 provenance: Provenance {
39 source: SourceKind::MountPoints2,
40 locator: mount
41 .source
42 .key_path
43 .clone()
44 .unwrap_or_else(|| mount.source.file.clone()),
45 },
46 })
47 })
48 .collect()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use peripheral_core::Provenance as PcProvenance;
56
57 fn mount(guid: &str, when: Option<i64>) -> UserMount {
58 UserMount {
59 volume_guid: guid.to_string(),
60 last_mounted: when,
61 source: PcProvenance {
62 file: "NTUSER.DAT".to_string(),
63 line: 0,
64 key_path: Some(format!("…\\MountPoints2\\{guid}")),
65 },
66 }
67 }
68
69 #[test]
70 fn a_timed_mount_yields_a_last_connected_claim_keyed_by_volume_guid() {
71 let mounts = [mount(
72 "{a2f2048e-d228-11e4-b630-000c29ff2429}",
73 Some(1_427_230_953),
74 )];
75 let claims = MountPoints2Source::new(&mounts).claims();
76 assert_eq!(claims.len(), 1);
77 assert_eq!(
78 claims[0].device,
79 DeviceKey("{a2f2048e-d228-11e4-b630-000c29ff2429}".to_string())
80 );
81 assert_eq!(claims[0].attribute, Attribute::LastConnected);
82 assert_eq!(claims[0].value, Value::Timestamp(1_427_230_953));
83 assert_eq!(claims[0].provenance.source, SourceKind::MountPoints2);
84 }
85
86 #[test]
87 fn a_mount_without_a_time_is_skipped() {
88 let mounts = [mount("{guid}", None)];
89 assert!(MountPoints2Source::new(&mounts).claims().is_empty());
90 }
91
92 #[test]
93 fn locator_falls_back_to_the_file_without_a_key_path() {
94 let mut m = mount("{guid}", Some(1));
95 m.source.key_path = None;
96 let mounts = [m];
97 let claims = MountPoints2Source::new(&mounts).claims();
98 assert_eq!(claims[0].provenance.locator, "NTUSER.DAT");
99 }
100}