spytrap-adb 0.3.5

Test a phone for stalkerware using adb and usb debugging to scan for suspicious apps and configuration
Documentation
use crate::errors::*;
use bstr::ByteSlice;
use forensic_adb::Device;
use std::str;

const CMD: &str = "pm list packages";

#[derive(Debug, PartialEq)]
pub struct Apk {
    pub id: String,
}

pub async fn list_packages(device: &Device) -> Result<Vec<Apk>> {
    let output = device
        .execute_host_exec_out_command(CMD)
        .await
        .with_context(|| anyhow!("Failed to run: {:?}", CMD))?;
    parse_output(&output)
}

fn parse_output(output: &[u8]) -> Result<Vec<Apk>> {
    let mut pkgs = Vec::new();
    for line in output.lines() {
        if line.is_empty() {
            continue;
        }
        let line = String::from_utf8_lossy(line);

        if let Some(package) = line.strip_prefix("package:") {
            debug!("discovered package={:?}", package);

            pkgs.push(Apk {
                id: package.to_string(),
            });
        }
    }

    Ok(pkgs)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    pub fn test_parse_output() {
        let data = b"package:org.jitsi.meet
package:org.lineageos.overlay.accent.black
package:com.android.cts.priv.ctsshim
package:org.lineageos.overlay.accent.brown
package:org.lineageos.overlay.accent.green
package:com.android.internal.display.cutout.emulation.corner
package:org.lineageos.overlay.customization.blacktheme
";

        let pkgs = parse_output(data).unwrap();
        assert_eq!(
            &pkgs,
            &[
                Apk {
                    id: "org.jitsi.meet".to_string()
                },
                Apk {
                    id: "org.lineageos.overlay.accent.black".to_string()
                },
                Apk {
                    id: "com.android.cts.priv.ctsshim".to_string()
                },
                Apk {
                    id: "org.lineageos.overlay.accent.brown".to_string()
                },
                Apk {
                    id: "org.lineageos.overlay.accent.green".to_string()
                },
                Apk {
                    id: "com.android.internal.display.cutout.emulation.corner".to_string()
                },
                Apk {
                    id: "org.lineageos.overlay.customization.blacktheme".to_string()
                }
            ]
        );
    }
}