scryptenc-cli 0.8.1

An utility for encrypt and decrypt files
// SPDX-FileCopyrightText: 2022 Shun Sakai
//
// SPDX-License-Identifier: GPL-3.0-or-later

// Lint levels of Clippy.
#![allow(clippy::multiple_crate_versions)]

mod app;
mod cli;
mod input;
mod output;
mod params;
mod passphrase;
mod utils;

use std::{
    io,
    process::{self, Termination},
};

use scryptenc::Error as ScryptencError;

/// The system exit code of this package.
#[derive(Debug)]
enum ExitCode {
    /// The successful exit.
    Success,

    /// An error occurred.
    Failure,

    /// Data was not a valid scrypt-encrypted block.
    InvalidFormat,

    /// The version was the unrecognized scrypt version number.
    UnknownVersion,

    /// Decrypting files takes too much memory.
    LackOfMemory,

    /// Decrypting files takes too much CPU time.
    LackOfCpuTime,

    /// Passphrase is incorrect.
    InvalidPassphrase,

    /// The scrypt parameters were invalid.
    InvalidParams,

    /// Decrypting files takes too much resources.
    LackOfResources,

    /// Error defined by `<sysexits.h>`.
    Other(sysexits::ExitCode),
}

impl From<sysexits::ExitCode> for ExitCode {
    fn from(code: sysexits::ExitCode) -> Self {
        Self::Other(code)
    }
}

impl Termination for ExitCode {
    fn report(self) -> process::ExitCode {
        match self {
            Self::Success => process::ExitCode::SUCCESS,
            Self::Failure => process::ExitCode::FAILURE,
            Self::InvalidFormat => 7.into(),
            Self::UnknownVersion => 8.into(),
            Self::LackOfMemory => 9.into(),
            Self::LackOfCpuTime => 10.into(),
            Self::InvalidPassphrase => 11.into(),
            Self::InvalidParams => 14.into(),
            Self::LackOfResources => 15.into(),
            Self::Other(code) => code.into(),
        }
    }
}

fn main() -> ExitCode {
    match app::run() {
        Ok(()) => ExitCode::Success,
        Err(err) => {
            eprintln!("Error: {err:?}");
            if let Some(e) = err.downcast_ref::<io::Error>() {
                return sysexits::ExitCode::from(e.kind()).into();
            }
            if let Some(e) = err.downcast_ref::<ScryptencError>() {
                return match e {
                    ScryptencError::InvalidLength
                    | ScryptencError::InvalidMagicNumber
                    | ScryptencError::InvalidChecksum
                    | ScryptencError::InvalidMac(_) => ExitCode::InvalidFormat,
                    ScryptencError::UnknownVersion(_) => ExitCode::UnknownVersion,
                    ScryptencError::InvalidParams(_) => ExitCode::InvalidParams,
                    ScryptencError::InvalidHeaderMac(_) => ExitCode::InvalidPassphrase,
                };
            }
            if let Some(e) = err.downcast_ref::<params::Error>() {
                return match e {
                    params::Error::Memory => ExitCode::LackOfMemory,
                    params::Error::CpuTime => ExitCode::LackOfCpuTime,
                    params::Error::Resources => ExitCode::LackOfResources,
                };
            }
            ExitCode::Failure
        }
    }
}