keyring-manager 0.10.0

Cross-platform library for managing passwords
Documentation
use crate::tests::ios_accessibility::*;
use crate::tests::*;
use backtrace::Backtrace;
use directories::*;
use log::*;
use simplelog::*;
use std::panic;
use std::path::PathBuf;
use std::sync::Once;

fn get_cache_dir() -> PathBuf {
    if let Some(my_proj_dirs) = ProjectDirs::from("org", "Keyring", "KeyRingTests") {
        PathBuf::from(my_proj_dirs.cache_dir())
    } else {
        PathBuf::from("./")
    }
}

#[no_mangle]
pub extern "C" fn run_tests() {
    if let Err(e) = run_tests_internal() {
        panic!("failed to run unit tests: {}", e);
    }
}

/// Idempotent: the locked-device entry points in ios_locked.rs are reached without run_tests when
/// only that gate is being run, and simplelog rejects a second init.
pub(super) fn init_logging() {
    static ONCE: Once = Once::new();
    ONCE.call_once(|| {
        let mut logs: Vec<Box<dyn SharedLogger>> = Vec::new();

        let mut cb = ConfigBuilder::new();

        logs.push(TermLogger::new(
            LevelFilter::Trace,
            cb.build(),
            TerminalMode::Mixed,
            ColorChoice::Auto,
        ));
        if let Err(e) = CombinedLogger::init(logs) {
            eprintln!("logger init error: {}", e);
        }

        panic::set_hook(Box::new(|panic_info| {
            let bt = Backtrace::new();
            if let Some(location) = panic_info.location() {
                error!(
                    "panic occurred in file '{}' at line {}",
                    location.file(),
                    location.line(),
                );
            } else {
                error!("panic occurred but can't get location information...");
            }
            if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
                error!("panic payload: {:?}", s);
            } else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
                error!("panic payload: {:?}", s);
            } else if let Some(a) = panic_info.payload().downcast_ref::<std::fmt::Arguments>() {
                error!("panic payload: {:?}", a);
            } else {
                error!("no panic payload");
            }
            error!("Backtrace:\n{:?}", bt);
        }));
    });
}

fn run_tests_internal() -> std::result::Result<(), String> {
    init_logging();

    run_unit_tests();

    Ok(())
}

fn run_unit_tests() {
    info!("Starting unit tests");

    let platform_keyring_manager = KeyringManager::new_secure(TEST_APPLICATION).unwrap();
    let insecure_keyring_manager = KeyringManager::new_insecure(
        TEST_APPLICATION,
        &get_cache_dir().join("test_insecure_keyring"),
    )
    .unwrap();

    info!("TEST: secure_test_escaped_password_input");
    exec_test_escaped_password_input(&platform_keyring_manager);
    info!("TEST: secure_test_add_ascii_password");
    exec_test_add_ascii_password(&platform_keyring_manager);
    info!("TEST: secure_test_round_trip_ascii_password");
    exec_test_round_trip_ascii_password(&platform_keyring_manager);
    info!("TEST: secure_test_add_non_ascii_password");
    exec_test_add_non_ascii_password(&platform_keyring_manager);
    info!("TEST: secure_test_round_trip_non_ascii_password");
    exec_test_round_trip_non_ascii_password(&platform_keyring_manager);
    info!("TEST: secure_test_multiple");
    exec_test_multiple(&platform_keyring_manager);
    info!("TEST: secure_test_list_keys");
    exec_test_list_keys(&platform_keyring_manager);
    info!("TEST: insecure_test_escaped_password_input");
    exec_test_escaped_password_input(&insecure_keyring_manager);
    info!("TEST: insecure_test_add_ascii_password");
    exec_test_add_ascii_password(&insecure_keyring_manager);
    info!("TEST: insecure_test_round_trip_ascii_password");
    exec_test_round_trip_ascii_password(&insecure_keyring_manager);
    info!("TEST: insecure_test_add_non_ascii_password");
    exec_test_add_non_ascii_password(&insecure_keyring_manager);
    info!("TEST: insecure_test_round_trip_non_ascii_password");
    exec_test_round_trip_non_ascii_password(&insecure_keyring_manager);
    info!("TEST: insecure_test_multiple");
    exec_test_multiple(&insecure_keyring_manager);
    info!("TEST: insecure_test_list_keys");
    exec_test_list_keys(&insecure_keyring_manager);

    // Accessibility last: the first failed assert kills the run, and these seed items deliberately.
    info!("TEST: secure_test_accessibility_born_current");
    exec_test_accessibility_born_current(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_promotion_on_read");
    exec_test_accessibility_promotion_on_read(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_promotion_converges");
    exec_test_accessibility_promotion_converges(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_data_integrity");
    exec_test_accessibility_data_integrity(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_write_paths");
    exec_test_accessibility_write_paths(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_downgrade");
    exec_test_accessibility_downgrade(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_absent");
    exec_test_accessibility_absent(&platform_keyring_manager);
    info!("TEST: secure_test_accessibility_concurrent");
    exec_test_accessibility_concurrent(&platform_keyring_manager);

    info!("Finished unit tests");
}