rooster 2.14.1

A simple password manager
use crate::example_environment_variable_configuration;
use crate::io::CliInputOutput;
use crate::io::OutputType;
use std::path::PathBuf;

pub fn callback_exec(
    matches: &clap::ArgMatches,
    io: &mut impl CliInputOutput,
    rooster_file_path: &PathBuf,
) -> Result<(), i32> {
    let filename_as_string = rooster_file_path.to_string_lossy().into_owned();
    if rooster_file_path.exists() && !matches.get_flag("force-for-tests") {
        io.error(
            "Woops, there is already a Rooster file located at:",
            OutputType::Error,
        );
        io.error(format!("    {}", filename_as_string), OutputType::Error);
        io.nl(OutputType::Error);
        io.error(
            "Type `rooster --help` to see what Rooster can do for you.",
            OutputType::Error,
        );
        return Err(1);
    }

    io.title("Welcome to Rooster", OutputType::Standard);
    io.nl(OutputType::Standard);
    io.info(
        "Rooster is a simple password manager. Let's get started! Type ENTER to continue.",
        OutputType::Standard,
    );

    if let Err(err) = io.read_line() {
        io.error(
            format!("Woops, I didn't see the ENTER key (reason: {:?}).", err),
            OutputType::Error,
        );
        return Err(1);
    }

    io.title("The master password", OutputType::Standard);
    io.nl(OutputType::Standard);
    io.info(
        "With Rooster, you only need to remember one password: \
    the master password. It keeps all of you other passwords safe. The stronger it is, the better your passwords are \
                      protected."
    , OutputType::Standard);
    io.nl(OutputType::Standard);

    let master_password = io
        .prompt_password("Choose your master password: ")
        .map_err(|err| {
            io.error(
                format!("Woops, I couldn't read the master passwords ({:?}).", err),
                OutputType::Error,
            );
            1
        })?;

    if master_password.is_empty() {
        io.error("Your master password cannot be empty.", OutputType::Error);
        return Err(1);
    }

    let store = match crate::password::v2::PasswordStore::new(master_password) {
        Ok(store) => store,
        Err(err) => {
            io.error(
                format!(
                    "Woops, I couldn't use the random number generator on your machine \
                     (reason: {:?}). Without it, I can't create a secure password file.",
                    err
                ),
                OutputType::Error,
            );
            return Err(1);
        }
    };

    let mut file = match crate::create_password_file(filename_as_string.as_str()).map_err(|_| 1) {
        Ok(file) => file,
        Err(err) => {
            io.error(
                format!(
                    "Woops, I couldn't create a new password file (reason: {:?})",
                    err
                ),
                OutputType::Error,
            );
            return Err(1);
        }
    };

    if let Err(err) = store.sync(&mut file) {
        if let Err(err) = std::fs::remove_file(rooster_file_path) {
            io.error(
                format!(
                    "Woops, I was able to create a new password file but couldn't save \
                     it (reason: {:?}). You may want to remove this dangling file:",
                    err
                ),
                OutputType::Error,
            );
            io.error(format!("    {}", filename_as_string), OutputType::Error);
            return Err(1);
        }
        io.error(
            format!(
                "Woops, I couldn't create a new password file (reason: {:?}).",
                err
            ),
            OutputType::Error,
        );
        return Err(1);
    }

    io.nl(OutputType::Standard);
    io.title("All done and ready to rock", OutputType::Standard);
    io.nl(OutputType::Standard);
    io.success("You passwords will be saved in:", OutputType::Standard);
    io.success(format!("    {}", filename_as_string), OutputType::Standard);
    io.nl(OutputType::Standard);
    io.info(
        "If you wish to change the location of your password file, you can set it in the \
        ROOSTER_FILE environment variable. For instance:",
        OutputType::Standard,
    );
    io.info(
        format!("    {}", example_environment_variable_configuration()),
        OutputType::Standard,
    );
    io.nl(OutputType::Standard);
    io.info(
        "Type `rooster --help` to see what Rooster can do for you.",
        OutputType::Standard,
    );

    Ok(())
}