From 38db145022bcb41e9ae54835836ef1bf9986ca53 Mon Sep 17 00:00:00 2001 From: "Daniel P. Clark" <6ftdan@gmail.com> Date: Sat, 14 May 2022 20:09:37 -0400 Subject: [PATCH] Update deprecations & fmt & v0.1.9 --- Cargo.toml | 11 +- src/core.rs | 462 ++++++++++++++++++----------------- src/main.rs | 364 ++++++++++++---------------- src/model/cli_reporter.rs | 24 +- src/model/mod.rs | 4 +- src/model/report_data.rs | 83 ++++--- src/model/work_load.rs | 26 +- src/process_input.rs | 92 +++---- src/reporter/benchmark.rs | 109 +++++---- src/reporter/mod.rs | 6 +- src/reporter/spinner.rs | 24 +- src/reporter/ticker_tape.rs | 8 +- src/result.rs | 104 ++++---- src/resume.rs | 464 +++++++++++++++++++++--------------- src/validators.rs | 128 +++++----- src/web.rs | 22 +- 16 files changed, 995 insertions(+), 936 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1cd108c..04a6f33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "abrute" -version = "0.1.8" +version = "0.1.9" authors = ["Daniel P. Clark <6ftdan@gmail.com>"] description = "AESCrypt Brute force attempter." documentation = "http://danielpclark.github.io/abrute/index.html" @@ -13,12 +13,13 @@ categories = ["cryptography"] [dependencies] array_tool = "^1.0" -tempdir = "~0.3" -clap = "~2.29" +clap = {version="~3.1.18",features=["cargo"]} digits = "~1.1.0" -rayon = "~0.8.2" +lazy_static = "1.4.0" +libc = "0.2.125" num_cpus = "~1.7" +rayon = "~0.8.2" serde = "1.0.24" serde_json = "1.0.8" tiny_http = "~0.5" -lazy_static = "1.0.0" +tempdir = "~0.3" diff --git a/src/core.rs b/src/core.rs index 04d5c89..f01ef10 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,275 +1,293 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. +use super::result::Error; use digits::Digits; -use ::model::work_load::WorkLoad; -use ::model::cli_reporter::CliReporter; -use std::io::{Read}; -use std::process::{Command, Output}; +use model::cli_reporter::CliReporter; +use model::work_load::WorkLoad; use rayon::prelude::*; -use super::result::Error; +use std::io::Read; +use std::process::{Command, Output}; extern crate num_cpus; extern crate tempdir; -use resume::{ResumeKey,ResumeFile}; use self::tempdir::TempDir; -use std::{fs,path,env}; -use std::time::{Duration, Instant}; -use ::{ITERATIONS,SUCCESS}; -use std::sync::{Arc, Mutex}; +use resume::{ResumeFile, ResumeKey}; use std::sync::atomic::Ordering; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; +use std::{env, fs, path}; +use {ITERATIONS, SUCCESS}; fn has_five_minutes_passed(t: Instant) -> bool { - Instant::now().duration_since(t) > Duration::new(300,0) + Instant::now().duration_since(t) > Duration::new(300, 0) } fn update_report_data(five_min_iters: usize, last: &Digits, fmp: &Arc>) { - let mut lock = fmp.try_lock(); - if let Ok(ref mut mutex) = lock { - **mutex = (five_min_iters, last.to_s()); - } + let mut lock = fmp.try_lock(); + if let Ok(ref mut mutex) = lock { + **mutex = (five_min_iters, last.to_s()); + } } -fn chunk_sequence(d: &mut Digits, adj: Option, chunk: usize, step: Option) -> Vec { - let qty: usize = num_cpus::get() * chunk; - let mut counter = 0; - let mut result = vec![]; - loop { - if counter >= qty { break; } - - if let Some(a) = adj.clone() { - if d.base() > 3 { - for _ in 0..step.unwrap_or(1) { - d.step_non_adjacent(a.parse::().unwrap() as usize); +fn chunk_sequence( + d: &mut Digits, + adj: Option, + chunk: usize, + step: Option, +) -> Vec { + let qty: usize = num_cpus::get() * chunk; + let mut counter = 0; + let mut result = vec![]; + loop { + if counter >= qty { + break; } - result.push(d.to_s()); + + if let Some(a) = adj.clone() { + if d.base() > 3 { + for _ in 0..step.unwrap_or(1) { + d.step_non_adjacent(a.parse::().unwrap() as usize); + } + result.push(d.to_s()); + counter += 1; + continue; + } + } + + let step_size = d.gen(step.unwrap_or(1) as u64); + result.push(d.mut_add(step_size).to_s()); counter += 1; - continue; - } } - - let step_size = d.gen(step.unwrap_or(1) as u64); - result.push(d.mut_add(step_size).to_s()); - counter += 1; - } - result + result } fn aes_command(value: &str, target: &str) -> Output { - Command::new("aescrypt"). - arg("-d"). - arg("-p"). - arg(value). - arg(target). - output(). - unwrap() + Command::new("aescrypt") + .arg("-d") + .arg("-p") + .arg(value) + .arg(target) + .output() + .unwrap() } fn unzip_command(value: &str, target: &str) -> Output { - let mut dir = path::PathBuf::from(&target); - dir.pop(); - Command::new("unzip"). - current_dir(dir). - arg("-u"). - arg("-P"). - arg(value). - arg(target). - output(). - unwrap() + let mut dir = path::PathBuf::from(&target); + dir.pop(); + Command::new("unzip") + .current_dir(dir) + .arg("-u") + .arg("-P") + .arg(value) + .arg(target) + .output() + .unwrap() } fn progress_report<'a>(reporter: &CliReporter, sequencer: &Digits) { - reporter.report(sequencer); + reporter.report(sequencer); } fn has_reached_end<'a>(sequencer: &Digits, max: usize) -> Result<(), Error> { - if sequencer.length() > max { - return Err(Error::PasswordNotFound); - } + if sequencer.length() > max { + return Err(Error::PasswordNotFound); + } - Ok(()) + Ok(()) } pub fn aescrypt_core_loop<'a>(work_load: WorkLoad) -> Result<(), Error> { - let WorkLoad( - characters, - max, - mut sequencer, - target, - adj, - chunk_size, - cluster_step, - reporter_handler, - cli_reporter - ) = work_load; - let mut time_keeper = Instant::now(); - let mut five_minute_iterations: usize = 0; - loop { - has_reached_end(&sequencer, max)?; - progress_report(&cli_reporter, &sequencer); - - let chunk = chunk_sequence( - &mut sequencer, - adj.clone(), - chunk_size.clone().map_or(32, |s| s.parse::().ok().unwrap()), - cluster_step - ); - let code: Mutex> = Mutex::new(vec![]); - - chunk.par_iter().for_each(|ref value| - { - let output = aes_command(&value, &target); - - ITERATIONS.fetch_add(1, Ordering::SeqCst); - - if output.status.success() { - let mut code_mutex = code.lock().unwrap(); - code_mutex.push(value.clone().to_string()); - SUCCESS.store(true, Ordering::SeqCst); - println!("Success!\nPassword is: {}", value); + let WorkLoad( + characters, + max, + mut sequencer, + target, + adj, + chunk_size, + cluster_step, + reporter_handler, + cli_reporter, + ) = work_load; + let mut time_keeper = Instant::now(); + let mut five_minute_iterations: usize = 0; + loop { + has_reached_end(&sequencer, max)?; + progress_report(&cli_reporter, &sequencer); + + let chunk = chunk_sequence( + &mut sequencer, + adj.clone(), + chunk_size + .clone() + .map_or(32, |s| s.parse::().ok().unwrap()), + cluster_step, + ); + let code: Mutex> = Mutex::new(vec![]); + + chunk.par_iter().for_each(|ref value| { + let output = aes_command(&value, &target); + + ITERATIONS.fetch_add(1, Ordering::SeqCst); + + if output.status.success() { + let mut code_mutex = code.lock().unwrap(); + code_mutex.push(value.clone().to_string()); + SUCCESS.store(true, Ordering::SeqCst); + println!("Success!\nPassword is: {}", value); + } + }); + + let code = code.lock().unwrap(); + if !code.is_empty() { + // Other attempts will erase the output file as there is always an empty file + // created in place when trying to decrypt. So we need to take the correct + // answer and decrypt the source one last time. Otherwise we'd need to isolate + // every attempt in a temp dir or mem dir and copying that much data that many + // times would be very slow and difficult to implement in a threaded way. + + aes_command(code.first().unwrap(), &target[..]); + ResumeFile::purge(); + break; } - } - ); - - let code = code.lock().unwrap(); - if !code.is_empty() { - // Other attempts will erase the output file as there is always an empty file - // created in place when trying to decrypt. So we need to take the correct - // answer and decrypt the source one last time. Otherwise we'd need to isolate - // every attempt in a temp dir or mem dir and copying that much data that many - // times would be very slow and difficult to implement in a threaded way. - - aes_command(code.first().unwrap(), &target[..]); - ResumeFile::purge(); - break; - } - if has_five_minutes_passed(time_keeper) { - let global_iterations = ITERATIONS.load(Ordering::SeqCst); - five_minute_iterations = global_iterations - five_minute_iterations; - ResumeFile::save( - ResumeKey::new( - characters.clone(), - adj.clone(), - sequencer.clone(), - target.to_string() - ) - ); - - update_report_data(five_minute_iterations, &sequencer, &reporter_handler.five_min_progress); - five_minute_iterations = global_iterations; - time_keeper = Instant::now(); + if has_five_minutes_passed(time_keeper) { + let global_iterations = ITERATIONS.load(Ordering::SeqCst); + five_minute_iterations = global_iterations - five_minute_iterations; + ResumeFile::save(ResumeKey::new( + characters.clone(), + adj.clone(), + sequencer.clone(), + target.to_string(), + )); + + update_report_data( + five_minute_iterations, + &sequencer, + &reporter_handler.five_min_progress, + ); + five_minute_iterations = global_iterations; + time_keeper = Instant::now(); + } } - } - Ok(()) + Ok(()) } fn any_file_contents(dir: &TempDir, omit: &str) -> bool { - let work_dir = fs::read_dir(&dir).expect("Failure reading tempdir's contents."); - let mut work_iter = work_dir.into_iter(); - work_iter.any(|x| { - let entry = x.expect("Failure reading specific file in tempdir."); - - if path::Path::new(&entry.path()) != path::Path::new(&omit) { - if fs::File::open(&entry.path()). - expect("Could not open file for validity check in tempdir."). - bytes().count() > 1 { - true - } else { false } - } else { false } - }) + let work_dir = fs::read_dir(&dir).expect("Failure reading tempdir's contents."); + let mut work_iter = work_dir.into_iter(); + work_iter.any(|x| { + let entry = x.expect("Failure reading specific file in tempdir."); + + if path::Path::new(&entry.path()) != path::Path::new(&omit) { + if fs::File::open(&entry.path()) + .expect("Could not open file for validity check in tempdir.") + .bytes() + .count() + > 1 + { + true + } else { + false + } + } else { + false + } + }) } pub fn unzip_core_loop<'a>(work_load: WorkLoad) -> Result<(), Error> { - let WorkLoad( - characters, - max, - mut sequencer, - target, - adj, - chunk_size, - cluster_step, - reporter_handler, - cli_reporter - ) = work_load; - let mut time_keeper = Instant::now(); - let mut five_minute_iterations: usize = 0; - if let Ok(dir) = TempDir::new("abrute") { - let cwd = env::current_dir().unwrap(); - let working = path::Path::new(&dir.path().as_os_str()).join(&target); - fs::copy(&target, &working).unwrap(); - assert!(working.is_file()); - let target = working.to_str().unwrap(); + let WorkLoad( + characters, + max, + mut sequencer, + target, + adj, + chunk_size, + cluster_step, + reporter_handler, + cli_reporter, + ) = work_load; + let mut time_keeper = Instant::now(); + let mut five_minute_iterations: usize = 0; + if let Ok(dir) = TempDir::new("abrute") { + let cwd = env::current_dir().unwrap(); + let working = path::Path::new(&dir.path().as_os_str()).join(&target); + fs::copy(&target, &working).unwrap(); + assert!(working.is_file()); + let target = working.to_str().unwrap(); + + loop { + has_reached_end(&sequencer, max)?; + progress_report(&cli_reporter, &sequencer); + + let chunk = chunk_sequence( + &mut sequencer, + adj.clone(), + chunk_size + .clone() + .map_or(32, |s| s.parse::().ok().unwrap()), + cluster_step, + ); + let code: Mutex>> = Mutex::new(vec![]); + + chunk.par_iter().for_each(|ref value| { + let output = unzip_command(&value, &target); + + ITERATIONS.fetch_add(1, Ordering::SeqCst); + + if output.status.success() { + if any_file_contents(&dir, &target) { + fs::read_dir(&dir) + .expect("Failure reading tempdir's contents.") + .into_iter() + .for_each(|entry| { + let entry = + entry.expect("Failure reading specific file in tempdir."); + let file_name = entry.file_name(); + let dest_file = path::Path::new(&cwd).join(file_name); + + fs::copy(entry.path(), dest_file) + .expect("Failure copying file from tempdir."); + }); + let mut code_mutex = code.lock().unwrap(); + code_mutex.push(Ok(())); + SUCCESS.store(true, Ordering::SeqCst); + println!("Success!\nPassword is: {}", value); + } + } + }); + + let mut code = code.lock().unwrap(); + if !code.is_empty() { + ResumeFile::purge(); + return code.pop().unwrap(); + } - loop { - has_reached_end(&sequencer, max)?; - progress_report(&cli_reporter, &sequencer); - - let chunk = chunk_sequence( - &mut sequencer, - adj.clone(), - chunk_size.clone().map_or(32, |s| s.parse::().ok().unwrap()), - cluster_step - ); - let code: Mutex>> = Mutex::new(vec![]); - - chunk.par_iter().for_each(|ref value| - { - let output = unzip_command(&value, &target); - - ITERATIONS.fetch_add(1, Ordering::SeqCst); - - if output.status.success() { - if any_file_contents(&dir, &target) { - fs::read_dir(&dir). - expect("Failure reading tempdir's contents."). - into_iter(). - for_each( |entry| { - let entry = entry.expect("Failure reading specific file in tempdir."); - let file_name = entry.file_name(); - let dest_file = path::Path::new(&cwd).join(file_name); - - fs::copy(entry.path(), dest_file). - expect("Failure copying file from tempdir."); - }); - let mut code_mutex = code.lock().unwrap(); - code_mutex.push(Ok(())); - SUCCESS.store(true, Ordering::SeqCst); - println!("Success!\nPassword is: {}", value); + if has_five_minutes_passed(time_keeper) { + let global_iterations = ITERATIONS.load(Ordering::SeqCst); + five_minute_iterations = global_iterations - five_minute_iterations; + ResumeFile::save(ResumeKey::new( + characters.clone(), + adj.clone(), + sequencer.clone(), + target.to_string(), + )); + + update_report_data( + five_minute_iterations, + &sequencer, + &reporter_handler.five_min_progress, + ); + five_minute_iterations = global_iterations; + time_keeper = Instant::now(); } - } } - ); - - let mut code = code.lock().unwrap(); - if !code.is_empty() { - ResumeFile::purge(); - return code.pop().unwrap(); - } - - - if has_five_minutes_passed(time_keeper) { - let global_iterations = ITERATIONS.load(Ordering::SeqCst); - five_minute_iterations = global_iterations - five_minute_iterations; - ResumeFile::save( - ResumeKey::new( - characters.clone(), - adj.clone(), - sequencer.clone(), - target.to_string() - ) - ); - - update_report_data(five_minute_iterations, &sequencer, &reporter_handler.five_min_progress); - five_minute_iterations = global_iterations; - time_keeper = Instant::now(); - } + } else { + return Err(Error::FailedTempDir); } - } else { - return Err(Error::FailedTempDir); - } } diff --git a/src/main.rs b/src/main.rs index 3d897b1..43cb9d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,35 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -#![feature(try_from)] #![feature(libc)] extern crate digits; extern crate rayon; use digits::Digits; -mod web; mod model; +mod web; use model::report_data::ReportData; use model::work_load::WorkLoad; -mod resume; -mod result; -mod reporter; mod process_input; +mod reporter; +mod result; +mod resume; use process_input::*; mod validators; use validators::*; mod core; use core::*; -use std::io::{self, Write}; use result::Error; -use std::error::Error as StdError; +use std::io::{self, Write}; #[macro_use] extern crate clap; -use clap::{Arg, App}; +use clap::{Arg, Command}; extern crate serde_json; -use std::time::SystemTime; use std::sync::{Arc, Mutex}; +use std::time::SystemTime; extern crate num_cpus; extern crate tiny_http; #[macro_use] @@ -40,69 +38,39 @@ extern crate lazy_static; use std::thread; extern crate libc; use libc::pthread_cancel; -use std::os::unix::thread::{ - RawPthread, - JoinHandleExt -}; +use std::os::unix::thread::{JoinHandleExt, RawPthread}; -use std::sync::atomic::{ - AtomicUsize, - AtomicBool, - ATOMIC_USIZE_INIT, - ATOMIC_BOOL_INIT -}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; -static ITERATIONS: AtomicUsize = ATOMIC_USIZE_INIT; -static SUCCESS: AtomicBool = ATOMIC_BOOL_INIT; +static ITERATIONS: AtomicUsize = AtomicUsize::new(0); +static SUCCESS: AtomicBool = AtomicBool::new(false); fn run_app() -> Result<(), Error> { - let matches = App::new("abrute - AES Brute Force File Decryptor"). - version(&format!("v{}", crate_version!())[..]). - version_short("v"). - author(crate_authors!("\n")). - usage("abrute [OPTIONS] -- "). - arg(Arg::with_name("RANGE"). - required(true). - index(1) - ). - arg(Arg::with_name("CHARACTERS"). - required(true). - index(2) - ). - arg(Arg::with_name("adjacent"). - short("a"). - long("adjacent"). - takes_value(true) - ). - arg(Arg::with_name("start"). - short("s"). - long("start"). - takes_value(true) - ). - arg(Arg::with_name("zip"). - short("z"). - long("zip"). - takes_value(false) - ). - arg(Arg::with_name("chunk"). - short("c"). - long("chunk"). - takes_value(true) - ). - arg(Arg::with_name("cluster"). - long("cluster"). - takes_value(true) - ). - arg(Arg::with_name("reporter"). - short("r"). - long("reporter"). - takes_value(true) - ). - arg(Arg::with_name("TARGET"). - required(true). - last(true) - ). - template("\ + let matches = Command::new("abrute - AES Brute Force File Decryptor") + .version(&format!("v{}", crate_version!())[..]) + .author(crate_authors!("\n")) + .override_usage("abrute [OPTIONS] -- ") + .arg(Arg::new("RANGE").required(true).index(1)) + .arg(Arg::new("CHARACTERS").required(true).index(2)) + .arg( + Arg::new("adjacent") + .short('a') + .long("adjacent") + .takes_value(true), + ) + .arg(Arg::new("start").short('s').long("start").takes_value(true)) + .arg(Arg::new("zip").short('z').long("zip").takes_value(false)) + .arg(Arg::new("chunk").short('c').long("chunk").takes_value(true)) + .arg(Arg::new("cluster").long("cluster").takes_value(true)) + .arg( + Arg::new("reporter") + .short('r') + .long("reporter") + .takes_value(true), + ) + .arg(Arg::new("TARGET").required(true).last(true)) + .help_template( + "\ ------------------------------------------------------------- {bin} {version} ------------------------------------------------------------- @@ -133,162 +101,140 @@ fn run_app() -> Result<(), Error> { -v, --version Prints version information. ------------------------------------------------------------- -USE OF THIS BINARY FALLS UNDER THE MIT LICENSE (c) 2017-2018"). - get_matches(); - - if matches.is_present("zip") { - validate_unzip_executable()?; - } else { - validate_aescrpyt_executable()?; - } - - let (min, max) = derive_min_max( - matches.value_of("RANGE").unwrap() - )?; - - validate_start_string(&matches, max)?; - - let mapping = derive_character_base( - matches.value_of("CHARACTERS").unwrap() - ); - let resume_key_chars = mapping_to_characters(&mapping); - let mut sequencer = Digits::new( - mapping, - matches.value_of("start").unwrap_or("").to_string() - ); - sequencer.zero_fill(min as usize); +USE OF THIS BINARY FALLS UNDER THE MIT LICENSE (c) 2017-2018", + ) + .get_matches(); - let target = matches.value_of("TARGET").unwrap_or(""); - let adjacent = matches.value_of("adjacent"); + if matches.is_present("zip") { + validate_unzip_executable()?; + } else { + validate_aescrpyt_executable()?; + } - validate_and_prep_sequencer_adjacent(&mut sequencer, adjacent)?; - validate_file_exists(&target)?; + let (min, max) = derive_min_max(matches.value_of("RANGE").unwrap())?; - let chunk = matches.value_of("chunk"); - if matches.is_present("chunk") { - validate_chunk_input(&chunk.unwrap()[..])?; - } + validate_start_string(&matches, max)?; - let mut cluster_step: Option = None; - if matches.is_present("cluster") { - let (offset, step) = derive_cluster( - matches.value_of("cluster").unwrap() - )?; - cluster_step = Some(step); - let additive = sequencer.gen(offset as u64).pred_till_zero(); - sequencer.mut_add(additive); - } + let mapping = derive_character_base(matches.value_of("CHARACTERS").unwrap()); + let resume_key_chars = mapping_to_characters(&mapping); + let mut sequencer = Digits::new(mapping, matches.value_of("start").unwrap_or("").to_string()); + sequencer.zero_fill(min as usize); - let reporter = - verify_reporter_name( - matches. - value_of("reporter"). - unwrap_or("ticker"). - to_string() - ); + let target = matches.value_of("TARGET").unwrap_or(""); + let adjacent = matches.value_of("adjacent"); - // JSON URI - println!("JSON endpoint available on Port 3838"); - // END JSON URI + validate_and_prep_sequencer_adjacent(&mut sequencer, adjacent)?; + validate_file_exists(&target)?; - // Begin Resume Feature - let starting = sequencer.to_s(); - use ::resume::{ResumeKey,ResumeFile}; - let cli_key = ResumeKey::new( - resume_key_chars.clone(), - adjacent.map(str::to_string), - sequencer, - target.to_string(), - ); - let latest = cli_key.latest(ResumeFile::load()); - let sequencer = latest.start; - if starting != sequencer.to_s() { - println!("Resuming from last save point: {}", sequencer.to_s()); - } - // End Resume Feature - - // DATA for JSON web end point - let reporter_handler = ReportData { - cores: num_cpus::get() as u8, - chunk: chunk. - clone(). - unwrap_or(""). - parse::(). - unwrap_or(32), - cluster: { - if matches.is_present("cluster") { - Some( - derive_cluster( - matches.value_of("cluster").unwrap() - ).ok().unwrap() - ) - } else { None } - }, - character_set: resume_key_chars.clone(), - start_time: SystemTime::now(), - start_at: sequencer.to_s(), - adjacent_limit: adjacent.map(|ref s| - u8::from_str_radix(&s,10).ok().unwrap() - ), - five_min_progress: Arc::new( - Mutex::new((0, "".to_string())) - ), - }; + let chunk = matches.value_of("chunk"); + if matches.is_present("chunk") { + validate_chunk_input(&chunk.unwrap()[..])?; + } - let web_reporter = reporter_handler.clone(); - let web_runner = thread::spawn(move || { - web::host_data(&web_reporter) - }); + let mut cluster_step: Option = None; + if matches.is_present("cluster") { + let (offset, step) = derive_cluster(matches.value_of("cluster").unwrap())?; + cluster_step = Some(step); + let additive = sequencer.gen(offset as u64).pred_till_zero(); + sequencer.mut_add(additive); + } - let work_load = WorkLoad( - resume_key_chars, - max, - sequencer, - target.to_string(), - adjacent.map(str::to_string), - chunk.map(str::to_string), - cluster_step, - reporter_handler, - reporter - ); + let reporter = + verify_reporter_name(matches.value_of("reporter").unwrap_or("ticker").to_string()); + + // JSON URI + println!("JSON endpoint available on Port 3838"); + // END JSON URI + + // Begin Resume Feature + let starting = sequencer.to_s(); + use resume::{ResumeFile, ResumeKey}; + let cli_key = ResumeKey::new( + resume_key_chars.clone(), + adjacent.map(str::to_string), + sequencer, + target.to_string(), + ); + let latest = cli_key.latest(ResumeFile::load()); + let sequencer = latest.start; + if starting != sequencer.to_s() { + println!("Resuming from last save point: {}", sequencer.to_s()); + } + // End Resume Feature + + // DATA for JSON web end point + let reporter_handler = ReportData { + cores: num_cpus::get() as u8, + chunk: chunk.clone().unwrap_or("").parse::().unwrap_or(32), + cluster: { + if matches.is_present("cluster") { + Some( + derive_cluster(matches.value_of("cluster").unwrap()) + .ok() + .unwrap(), + ) + } else { + None + } + }, + character_set: resume_key_chars.clone(), + start_time: SystemTime::now(), + start_at: sequencer.to_s(), + adjacent_limit: adjacent.map(|ref s| u8::from_str_radix(&s, 10).ok().unwrap()), + five_min_progress: Arc::new(Mutex::new((0, "".to_string()))), + }; + + let web_reporter = reporter_handler.clone(); + let web_runner = thread::spawn(move || web::host_data(&web_reporter)); + + let work_load = WorkLoad( + resume_key_chars, + max, + sequencer, + target.to_string(), + adjacent.map(str::to_string), + chunk.map(str::to_string), + cluster_step, + reporter_handler, + reporter, + ); - let mtchs = matches.clone(); + let mtchs = matches.clone(); - let crypt_runner = thread::spawn(move || { - if mtchs.is_present("zip") { - unzip_core_loop(work_load) - } else { - aescrypt_core_loop(work_load) - } - }); + let crypt_runner = thread::spawn(move || { + if mtchs.is_present("zip") { + unzip_core_loop(work_load) + } else { + aescrypt_core_loop(work_load) + } + }); - let wr: RawPthread = web_runner.as_pthread_t(); + let wr: RawPthread = web_runner.as_pthread_t(); - let cr = crypt_runner.join().unwrap(); + let cr = crypt_runner.join().unwrap(); - unsafe { - pthread_cancel(wr); - } + unsafe { + pthread_cancel(wr); + } - cr + cr } fn main() { - ::std::process::exit( - match run_app() { - Ok(_) => { - println!("Exiting…"); - 0 - }, - Err(err) => { - writeln!( - io::stderr(), - "Error: {}\n{}\n\nUse `abrute -h` for a help menu.", - err, - err.description() - ).unwrap(); - 1 - } - } - ); + ::std::process::exit(match run_app() { + Ok(_) => { + println!("Exiting…"); + 0 + } + Err(err) => { + writeln!( + io::stderr(), + "Error: {}\n{}\n\nUse `abrute -h` for a help menu.", + err, + err.to_string() + ) + .unwrap(); + 1 + } + }); } diff --git a/src/model/cli_reporter.rs b/src/model/cli_reporter.rs index d3b88c7..a8f1975 100644 --- a/src/model/cli_reporter.rs +++ b/src/model/cli_reporter.rs @@ -1,25 +1,25 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use ::Digits; +use Digits; pub enum CliReporter { - TickerTape, - Spinner, - Benchmark, + TickerTape, + Spinner, + Benchmark, } impl CliReporter { - #[inline] - pub fn report(&self, data: &Digits) { - match *self { - ref _thingy @ CliReporter::TickerTape => ::reporter::ticker_tape::report(data), - ref _thingy @ CliReporter::Spinner => ::reporter::spinner::report(data), - ref _thingy @ CliReporter::Benchmark => ::reporter::benchmark::report(data), + #[inline] + pub fn report(&self, data: &Digits) { + match *self { + ref _thingy @ CliReporter::TickerTape => ::reporter::ticker_tape::report(data), + ref _thingy @ CliReporter::Spinner => ::reporter::spinner::report(data), + ref _thingy @ CliReporter::Benchmark => ::reporter::benchmark::report(data), + } } - } } diff --git a/src/model/mod.rs b/src/model/mod.rs index 1828777..af9e71b 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,10 +1,10 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -pub mod report_data; pub mod cli_reporter; +pub mod report_data; pub mod work_load; diff --git a/src/model/report_data.rs b/src/model/report_data.rs index d6c64b9..a731b53 100644 --- a/src/model/report_data.rs +++ b/src/model/report_data.rs @@ -1,5 +1,5 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be @@ -7,51 +7,56 @@ use std::time::SystemTime; extern crate serde; -use self::serde::ser::{Serialize, Serializer, SerializeStruct}; -use std::sync::{Arc, Mutex}; -use ::{ITERATIONS,SUCCESS}; -use std::sync::atomic::Ordering; +use self::serde::ser::{Serialize, SerializeStruct, Serializer}; use std::ops::Deref; +use std::sync::atomic::Ordering; +use std::sync::{Arc, Mutex}; +use {ITERATIONS, SUCCESS}; #[derive(Clone)] pub struct ReportData { - pub cores: u8, - pub chunk: usize, - pub cluster: Option<(usize,usize)>, - pub character_set: String, - pub start_time: SystemTime, - pub start_at: String, - pub adjacent_limit: Option, - pub five_min_progress: Arc> + pub cores: u8, + pub chunk: usize, + pub cluster: Option<(usize, usize)>, + pub character_set: String, + pub start_time: SystemTime, + pub start_at: String, + pub adjacent_limit: Option, + pub five_min_progress: Arc>, } impl Serialize for ReportData { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - - let mut struct_fields = 9; - if self.cluster.is_some() { struct_fields += 2; } - if self.adjacent_limit.is_some() { struct_fields += 1; } + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut struct_fields = 9; + if self.cluster.is_some() { + struct_fields += 2; + } + if self.adjacent_limit.is_some() { + struct_fields += 1; + } - let mut state = serializer.serialize_struct("ReportData", struct_fields)?; - state.serialize_field("cores", &self.cores)?; - state.serialize_field("chunk", &self.chunk)?; - if let Some((node, cluster_size)) = self.cluster { - state.serialize_field("cluster_node", &node)?; - state.serialize_field("cluster_size", &cluster_size)?; - } - state.serialize_field("character_set", &self.character_set)?; - state.serialize_field("start_time", &self.start_time)?; - state.serialize_field("start_at", &self.start_at)?; - if let Some(adj) = self.adjacent_limit { - state.serialize_field("adjacent_limit", &adj)?; + let mut state = serializer.serialize_struct("ReportData", struct_fields)?; + state.serialize_field("cores", &self.cores)?; + state.serialize_field("chunk", &self.chunk)?; + if let Some((node, cluster_size)) = self.cluster { + state.serialize_field("cluster_node", &node)?; + state.serialize_field("cluster_size", &cluster_size)?; + } + state.serialize_field("character_set", &self.character_set)?; + state.serialize_field("start_time", &self.start_time)?; + state.serialize_field("start_at", &self.start_at)?; + if let Some(adj) = self.adjacent_limit { + state.serialize_field("adjacent_limit", &adj)?; + } + state.serialize_field("iterations", &ITERATIONS.load(Ordering::SeqCst))?; + let getter = self.five_min_progress.lock().unwrap(); + let &(five_min_iters, ref last_string) = getter.deref(); + state.serialize_field("last_five_minute_iterations", &five_min_iters)?; + state.serialize_field("last_attempt", &last_string)?; + state.serialize_field("success", &SUCCESS.load(Ordering::SeqCst))?; + state.end() } - state.serialize_field("iterations", &ITERATIONS.load(Ordering::SeqCst))?; - let getter = self.five_min_progress.lock().unwrap(); - let &(five_min_iters, ref last_string) = getter.deref(); - state.serialize_field("last_five_minute_iterations", &five_min_iters)?; - state.serialize_field("last_attempt", &last_string)?; - state.serialize_field("success", &SUCCESS.load(Ordering::SeqCst))?; - state.end() - } } diff --git a/src/model/work_load.rs b/src/model/work_load.rs index 6e06e59..906df7c 100644 --- a/src/model/work_load.rs +++ b/src/model/work_load.rs @@ -1,22 +1,22 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use ::Digits; -use ::model::report_data::ReportData; -use ::model::cli_reporter::CliReporter; +use model::cli_reporter::CliReporter; +use model::report_data::ReportData; +use Digits; pub struct WorkLoad( - pub String, // characters: String, - pub usize, // max: usize, - pub Digits, // mut sequencer: Digits, - pub String, // target: String, - pub Option, // adj: Option - pub Option, // chunk: Option - pub Option, // cluster_step: Option<(usize,usize)> - pub ReportData, // cloned ReportData for web JSON results and other reporters - pub CliReporter, // cli Reporter chosen + pub String, // characters: String, + pub usize, // max: usize, + pub Digits, // mut sequencer: Digits, + pub String, // target: String, + pub Option, // adj: Option + pub Option, // chunk: Option + pub Option, // cluster_step: Option<(usize,usize)> + pub ReportData, // cloned ReportData for web JSON results and other reporters + pub CliReporter, // cli Reporter chosen ); diff --git a/src/process_input.rs b/src/process_input.rs index 4fc9268..26f21cf 100644 --- a/src/process_input.rs +++ b/src/process_input.rs @@ -1,69 +1,71 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use digits::BaseCustom; use super::result::Error; -use ::model::cli_reporter::CliReporter; +use digits::BaseCustom; +use model::cli_reporter::CliReporter; pub fn verify_reporter_name(rn: String) -> CliReporter { - match &rn[..] { - "spinner" => CliReporter::Spinner, - "benchmark" => CliReporter::Benchmark, - _ => CliReporter::TickerTape, - } + match &rn[..] { + "spinner" => CliReporter::Spinner, + "benchmark" => CliReporter::Benchmark, + _ => CliReporter::TickerTape, + } } pub fn derive_min_max(range: &str) -> Result<(usize, usize), Error> { - let rvals = range.split(':').collect::>(); - for item in &rvals { - if item.parse::().is_err() { - return Err(Error::InvalidRange); - } - } - let mut rivals = rvals.iter(); - let min = rivals.next().unwrap(); - let max = rivals.next(); - let min = min.parse::().unwrap(); - let get_max = || -> usize { - match max { - Some(v) => { v.parse::().unwrap() }, - _ => { min } + let rvals = range.split(':').collect::>(); + for item in &rvals { + if item.parse::().is_err() { + return Err(Error::InvalidRange); + } } - }; - Ok((min, get_max())) + let mut rivals = rvals.iter(); + let min = rivals.next().unwrap(); + let max = rivals.next(); + let min = min.parse::().unwrap(); + let get_max = || -> usize { + match max { + Some(v) => v.parse::().unwrap(), + _ => min, + } + }; + Ok((min, get_max())) } pub fn derive_cluster(range: &str) -> Result<(usize, usize), Error> { - let rvals = range.split(':').collect::>(); - if rvals.len() != 2 { return Err(Error::InvalidRange); } - for item in &rvals { - if item.parse::().is_err() { - return Err(Error::InvalidRange); + let rvals = range.split(':').collect::>(); + if rvals.len() != 2 { + return Err(Error::InvalidRange); } - } - let mut rivals = rvals.iter(); - let offset = rivals.next().unwrap(); - let cluster_size = rivals.next().unwrap(); - let offset = offset.parse::().unwrap(); - let cluster_size = cluster_size.parse::().unwrap(); - if offset > cluster_size || offset == 0 { - return Err(Error::InvalidRange); - } - Ok((offset, cluster_size)) + for item in &rvals { + if item.parse::().is_err() { + return Err(Error::InvalidRange); + } + } + let mut rivals = rvals.iter(); + let offset = rivals.next().unwrap(); + let cluster_size = rivals.next().unwrap(); + let offset = offset.parse::().unwrap(); + let cluster_size = cluster_size.parse::().unwrap(); + if offset > cluster_size || offset == 0 { + return Err(Error::InvalidRange); + } + Ok((offset, cluster_size)) } pub fn derive_character_base(characters: &str) -> BaseCustom { - BaseCustom::::new(characters.chars().collect()) + BaseCustom::::new(characters.chars().collect()) } pub fn mapping_to_characters(m: &BaseCustom) -> String { - let mut crs = String::new(); - for x in 0..m.base as usize { - crs.push_str(&m.gen(x as u64)[..]); - } - crs + let mut crs = String::new(); + for x in 0..m.base as usize { + crs.push_str(&m.gen(x as u64)[..]); + } + crs } diff --git a/src/reporter/benchmark.rs b/src/reporter/benchmark.rs index 05d0710..220a58d 100644 --- a/src/reporter/benchmark.rs +++ b/src/reporter/benchmark.rs @@ -1,17 +1,17 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use ::{Digits,ITERATIONS}; use std::collections::HashMap; -use std::sync::Mutex; -use std::sync::atomic::Ordering; -use std::time::Instant; use std::io; use std::io::Write; +use std::sync::atomic::Ordering; +use std::sync::Mutex; +use std::time::Instant; +use {Digits, ITERATIONS}; lazy_static! { // len => Iterations, Iteration Start, Start Instant (for Duration) @@ -22,51 +22,74 @@ lazy_static! { } pub fn report(data: &Digits) { - let len = data.length() as i32; - let mut hm = HASHMAP.lock().unwrap(); - if hm.is_empty() { - println!("Benchmark Results\nAttempt :: Category of Range:Iterations, Rating in IPS"); - hm.insert(len as u8, (0, 0, Instant::now())); - } + let len = data.length() as i32; + let mut hm = HASHMAP.lock().unwrap(); + if hm.is_empty() { + println!("Benchmark Results\nAttempt :: Category of Range:Iterations, Rating in IPS"); + hm.insert(len as u8, (0, 0, Instant::now())); + } - let reader = hm.clone(); + let reader = hm.clone(); - if hm.contains_key(&(len as u8)) { - let entry = hm.get_mut(&(len as u8)).unwrap(); - let &mut (_, start, duration) = entry; + if hm.contains_key(&(len as u8)) { + let entry = hm.get_mut(&(len as u8)).unwrap(); + let &mut (_, start, duration) = entry; - let iters = ITERATIONS.load(Ordering::SeqCst); - let iterated = iters - start.clone() as usize; + let iters = ITERATIONS.load(Ordering::SeqCst); + let iterated = iters - start.clone() as usize; - let min = reader.keys().min().unwrap(); - let max = reader.keys().max().unwrap(); - let start_instant = reader.get(min).unwrap().2; - let seconds = Instant::now().duration_since(start_instant).as_secs(); - let ips = if seconds == 0 { 0 } else { iters/seconds as usize }; - print!("\x1b[1000D{} :: Category: {}->{}:{}, Rating Total: {} IPS", data.to_s(), min, max, iterated, ips); + let min = reader.keys().min().unwrap(); + let max = reader.keys().max().unwrap(); + let start_instant = reader.get(min).unwrap().2; + let seconds = Instant::now().duration_since(start_instant).as_secs(); + let ips = if seconds == 0 { + 0 + } else { + iters / seconds as usize + }; + print!( + "\x1b[1000D{} :: Category: {}->{}:{}, Rating Total: {} IPS", + data.to_s(), + min, + max, + iterated, + ips + ); - *entry = (iterated as u64, start.clone(), duration.clone()); - } else { - // New Entry - let previous = len - 1; - let has_previous = hm.contains_key(&(previous as u8)); - let start_iteration = if has_previous { hm.get(&(previous as u8)).unwrap().0 } else { 0 }; + *entry = (iterated as u64, start.clone(), duration.clone()); + } else { + // New Entry + let previous = len - 1; + let has_previous = hm.contains_key(&(previous as u8)); + let start_iteration = if has_previous { + hm.get(&(previous as u8)).unwrap().0 + } else { + 0 + }; - let iters = ITERATIONS.load(Ordering::SeqCst); - let instant = Instant::now(); + let iters = ITERATIONS.load(Ordering::SeqCst); + let instant = Instant::now(); - hm.insert(len as u8, (start_iteration, iters as u64, instant)); + hm.insert(len as u8, (start_iteration, iters as u64, instant)); - if has_previous { - let iterations = - if hm.contains_key(&((previous) as u8)) { - hm.get(&((previous) as u8)).unwrap().0 as usize - } else { 0 }; - let start = hm.get(&(previous as u8)).unwrap().2; - let seconds = Instant::now().duration_since(start).as_secs(); - let ips = if seconds == 0 { 0 } else { iterations/(seconds as usize) }; - println!("\nRange: {}, Iterations: {}, Interim Rating: {} IPS", previous, iterations, ips); + if has_previous { + let iterations = if hm.contains_key(&((previous) as u8)) { + hm.get(&((previous) as u8)).unwrap().0 as usize + } else { + 0 + }; + let start = hm.get(&(previous as u8)).unwrap().2; + let seconds = Instant::now().duration_since(start).as_secs(); + let ips = if seconds == 0 { + 0 + } else { + iterations / (seconds as usize) + }; + println!( + "\nRange: {}, Iterations: {}, Interim Rating: {} IPS", + previous, iterations, ips + ); + } } - } - io::stdout().flush().unwrap(); + io::stdout().flush().unwrap(); } diff --git a/src/reporter/mod.rs b/src/reporter/mod.rs index 7070ee6..f1ccff4 100644 --- a/src/reporter/mod.rs +++ b/src/reporter/mod.rs @@ -1,10 +1,10 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -pub mod ticker_tape; -pub mod spinner; pub mod benchmark; +pub mod spinner; +pub mod ticker_tape; diff --git a/src/reporter/spinner.rs b/src/reporter/spinner.rs index e5abc63..f0e88b1 100644 --- a/src/reporter/spinner.rs +++ b/src/reporter/spinner.rs @@ -1,23 +1,23 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use ::{Digits,ITERATIONS}; -use std::sync::atomic::Ordering; use std::io::{self, Write}; +use std::sync::atomic::Ordering; +use {Digits, ITERATIONS}; -const SPINNER: [char; 10] = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏']; +const SPINNER: [char; 10] = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; pub fn report(data: &Digits) { - let global_iterations = ITERATIONS.load(Ordering::SeqCst); - print!( - "\x1b[1000D {} Iterations: {} String: {}", - SPINNER[global_iterations % 10], - global_iterations, - data.to_s() - ); - io::stdout().flush().unwrap(); + let global_iterations = ITERATIONS.load(Ordering::SeqCst); + print!( + "\x1b[1000D {} Iterations: {} String: {}", + SPINNER[global_iterations % 10], + global_iterations, + data.to_s() + ); + io::stdout().flush().unwrap(); } diff --git a/src/reporter/ticker_tape.rs b/src/reporter/ticker_tape.rs index 4e6b76b..711b799 100644 --- a/src/reporter/ticker_tape.rs +++ b/src/reporter/ticker_tape.rs @@ -1,14 +1,14 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. use std::io::{self, Write}; -use ::Digits; +use Digits; pub fn report(data: &Digits) { - print!("{}..", data.to_s()); - io::stdout().flush().unwrap(); + print!("{}..", data.to_s()); + io::stdout().flush().unwrap(); } diff --git a/src/result.rs b/src/result.rs index 2ebed36..a53bd55 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,115 +1,115 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use std::fmt; use std::error::Error as StdError; +use std::fmt; #[derive(Debug)] pub enum Error { - AescryptMissing, - FailedTempDir, - FileMissing, - InvalidAdjacentNumber, - InvalidCharacterSet, - InvalidChunkNumber, - InvalidRange, - InvalidStringLength, - PasswordNotFound, - MalformedResumeKey, - UnzipMissing, + AescryptMissing, + FailedTempDir, + FileMissing, + InvalidAdjacentNumber, + InvalidCharacterSet, + InvalidChunkNumber, + InvalidRange, + InvalidStringLength, + PasswordNotFound, + MalformedResumeKey, + UnzipMissing, } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::AescryptMissing => f.write_str("AescryptMissing" ), - Error::FailedTempDir => f.write_str("FailedTempDir" ), - Error::FileMissing => f.write_str("FileMissing" ), - Error::InvalidAdjacentNumber => f.write_str("InvalidAdjacentNumber"), - Error::InvalidCharacterSet => f.write_str("InvalidCharacterSet" ), - Error::InvalidChunkNumber => f.write_str("InvalidChunkNumber"), - Error::InvalidRange => f.write_str("InvalidRange" ), - Error::InvalidStringLength => f.write_str("InvalidStringLength" ), - Error::PasswordNotFound => f.write_str("PasswordNotFound" ), - Error::MalformedResumeKey => f.write_str("MalformedResumeKey" ), - Error::UnzipMissing => f.write_str("UnzipMissing" ), + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::AescryptMissing => f.write_str("AescryptMissing"), + Error::FailedTempDir => f.write_str("FailedTempDir"), + Error::FileMissing => f.write_str("FileMissing"), + Error::InvalidAdjacentNumber => f.write_str("InvalidAdjacentNumber"), + Error::InvalidCharacterSet => f.write_str("InvalidCharacterSet"), + Error::InvalidChunkNumber => f.write_str("InvalidChunkNumber"), + Error::InvalidRange => f.write_str("InvalidRange"), + Error::InvalidStringLength => f.write_str("InvalidStringLength"), + Error::PasswordNotFound => f.write_str("PasswordNotFound"), + Error::MalformedResumeKey => f.write_str("MalformedResumeKey"), + Error::UnzipMissing => f.write_str("UnzipMissing"), + } } - } } #[inline] fn aescrypt_missing() -> &'static str { - "aescrypt does not appear to be installed." + "aescrypt does not appear to be installed." } #[inline] fn failed_temp_dir() -> &'static str { - "Failed in creating a temp directory to work in." + "Failed in creating a temp directory to work in." } #[inline] fn file_missing() -> &'static str { - "The target file seems to be missing." + "The target file seems to be missing." } #[inline] fn invalid_adjacent_number() -> &'static str { - "Invalid number for adjacent input." + "Invalid number for adjacent input." } #[inline] fn invalid_character_set() -> &'static str { - "Invalid character set provided for start." + "Invalid character set provided for start." } #[inline] fn invalid_chunk_number() -> &'static str { - "Invalid number for chunk input." + "Invalid number for chunk input." } #[inline] fn invalid_range() -> &'static str { - "Invalid range input given." + "Invalid range input given." } #[inline] fn invalid_string_length() -> &'static str { - "Invalid string length for start given." + "Invalid string length for start given." } #[inline] fn password_not_found() -> &'static str { - "Password not found for given length and character set." + "Password not found for given length and character set." } #[inline] fn malformed_resume_key() -> &'static str { - "The input data was not formatted properly for creating ResumeKey." + "The input data was not formatted properly for creating ResumeKey." } #[inline] fn unzip_missing() -> &'static str { - "unzip does not appear to be installed." + "unzip does not appear to be installed." } impl StdError for Error { - fn description(&self) -> &str { - match *self { - Error::AescryptMissing => aescrypt_missing(), - Error::FailedTempDir => failed_temp_dir(), - Error::FileMissing => file_missing(), - Error::InvalidAdjacentNumber => invalid_adjacent_number(), - Error::InvalidCharacterSet => invalid_character_set(), - Error::InvalidChunkNumber => invalid_chunk_number(), - Error::InvalidRange => invalid_range(), - Error::InvalidStringLength => invalid_string_length(), - Error::PasswordNotFound => password_not_found(), - Error::MalformedResumeKey => malformed_resume_key(), - Error::UnzipMissing => unzip_missing(), + fn description(&self) -> &str { + match *self { + Error::AescryptMissing => aescrypt_missing(), + Error::FailedTempDir => failed_temp_dir(), + Error::FileMissing => file_missing(), + Error::InvalidAdjacentNumber => invalid_adjacent_number(), + Error::InvalidCharacterSet => invalid_character_set(), + Error::InvalidChunkNumber => invalid_chunk_number(), + Error::InvalidRange => invalid_range(), + Error::InvalidStringLength => invalid_string_length(), + Error::PasswordNotFound => password_not_found(), + Error::MalformedResumeKey => malformed_resume_key(), + Error::UnzipMissing => unzip_missing(), + } } - } } diff --git a/src/resume.rs b/src/resume.rs index 9ff631a..280c7d4 100644 --- a/src/resume.rs +++ b/src/resume.rs @@ -1,18 +1,18 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. +use result::Error::MalformedResumeKey; +use std::convert::TryFrom; +use std::fmt; use std::fmt::Display; use std::fs; +use std::fs::{File, OpenOptions}; +use std::io::{BufReader, Read, Write}; use std::path::Path; -use std::fs::{File,OpenOptions}; -use std::fmt; -use std::io::{Read,Write,BufReader}; -use std::convert::TryFrom; -use ::result::Error::MalformedResumeKey; extern crate array_tool; use self::array_tool::vec::Shift; extern crate digits; @@ -20,256 +20,324 @@ use self::digits::prelude::*; #[derive(Clone)] pub(crate) struct ResumeKeyDB { - rkeys: Vec, + rkeys: Vec, } impl ResumeKeyDB { - fn get(f: String) -> ResumeKeyDB { - let file = File::open(f); - assert!(file.is_ok()); - let mut buf_reader = BufReader::new(file.ok().unwrap()); - let mut contents = String::new(); - buf_reader.read_to_string(&mut contents).ok(); - - let mut db: Vec = vec![]; - contents. - split("\n\n"). - map(|s| s.to_string()). - filter(|s| !s.is_empty()). - for_each(|item| { - let rk = ResumeKey::try_from(item); - if let Ok(key) = rk { - db.push(key); - } - }); - ResumeKeyDB { rkeys: db } - } - - fn update(&mut self, o: ResumeKey) { - let latest = o.latest(self.clone()); - self.rkeys = self. - clone(). - rkeys. - into_iter(). - filter(|rk| rk.similarity(&latest) == Kind::Different). - collect(); - self.rkeys.push(latest); - } + fn get(f: String) -> ResumeKeyDB { + let file = File::open(f); + assert!(file.is_ok()); + let mut buf_reader = BufReader::new(file.ok().unwrap()); + let mut contents = String::new(); + buf_reader.read_to_string(&mut contents).ok(); + + let mut db: Vec = vec![]; + contents + .split("\n\n") + .map(|s| s.to_string()) + .filter(|s| !s.is_empty()) + .for_each(|item| { + let rk = ResumeKey::try_from(item); + if let Ok(key) = rk { + db.push(key); + } + }); + ResumeKeyDB { rkeys: db } + } + + fn update(&mut self, o: ResumeKey) { + let latest = o.latest(self.clone()); + self.rkeys = self + .clone() + .rkeys + .into_iter() + .filter(|rk| rk.similarity(&latest) == Kind::Different) + .collect(); + self.rkeys.push(latest); + } } -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub(crate) struct ResumeKey { - characters: String, - adjacent: Option, - pub(crate) start: Digits, - target: String, + characters: String, + adjacent: Option, + pub(crate) start: Digits, + target: String, } impl PartialEq for ResumeKey { - fn eq(&self, other: &ResumeKey) -> bool { - self.start == other.start - } + fn eq(&self, other: &ResumeKey) -> bool { + self.start == other.start + } } -#[derive(Debug,Eq,PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub enum Kind { - Same, - Similar, - Different, + Same, + Similar, + Different, } trait Similarity { - fn similarity(&self, other: &Self) -> Kind; + fn similarity(&self, other: &Self) -> Kind; } impl Similarity for ResumeKey { - fn similarity(&self, other: &ResumeKey) -> Kind { - if self.target != other.target || - self.characters != other.characters || - self.adjacent != other.adjacent { - return Kind::Different; - } + fn similarity(&self, other: &ResumeKey) -> Kind { + if self.target != other.target + || self.characters != other.characters + || self.adjacent != other.adjacent + { + return Kind::Different; + } - if self.start == other.start { Kind::Same } else { Kind::Similar } - } + if self.start == other.start { + Kind::Same + } else { + Kind::Similar + } + } } impl ResumeKey { - pub fn new(c: String,a: Option,s: Digits,t: String) -> ResumeKey { - ResumeKey { - characters: c, - adjacent: a, - start: s, - target: t, + pub fn new(c: String, a: Option, s: Digits, t: String) -> ResumeKey { + ResumeKey { + characters: c, + adjacent: a, + start: s, + target: t, + } + } + + pub(crate) fn latest(self, db: ResumeKeyDB) -> ResumeKey { + let mut keys: Vec = db + .rkeys + .into_iter() + .filter(|rk| rk.similarity(&self) != Kind::Different) + .collect(); + keys.push(self.clone()); + keys.into_iter() + .max_by(|ref a, ref b| a.start.partial_cmp(&b.start).unwrap()) + .unwrap_or(self) } - } - - pub(crate) fn latest(self, db: ResumeKeyDB) -> ResumeKey { - let mut keys: Vec = db. - rkeys. - into_iter(). - filter(|rk| rk.similarity(&self) != Kind::Different). - collect(); - keys.push(self.clone()); - keys. - into_iter(). - max_by(|ref a, ref b| a.start.partial_cmp(&b.start).unwrap()). - unwrap_or(self) - } } #[test] fn can_pick_latest_resume_value() { - let b = BaseCustom::::new("asdf".chars().collect()); - let aa = Digits::new(b.clone(), "aaaa".to_string()); - let ab = Digits::new(b.clone(), "ssss".to_string()); - let ac = Digits::new(b.clone(), "dddd".to_string()); - let ad = Digits::new(b.clone(), "ffff".to_string()); - - let ra = ResumeKey { characters: "asdf".to_string(), adjacent: None, start: aa, target: "thing".to_string() }; - let rb = ResumeKey { characters: "asdf".to_string(), adjacent: None, start: ab, target: "thing".to_string() }; - let rc = ResumeKey { characters: "asdf".to_string(), adjacent: None, start: ac, target: "thing".to_string() }; - let rd = ResumeKey { characters: "asdf".to_string(), adjacent: None, start: ad, target: "thing".to_string() }; + let b = BaseCustom::::new("asdf".chars().collect()); + let aa = Digits::new(b.clone(), "aaaa".to_string()); + let ab = Digits::new(b.clone(), "ssss".to_string()); + let ac = Digits::new(b.clone(), "dddd".to_string()); + let ad = Digits::new(b.clone(), "ffff".to_string()); + + let ra = ResumeKey { + characters: "asdf".to_string(), + adjacent: None, + start: aa, + target: "thing".to_string(), + }; + let rb = ResumeKey { + characters: "asdf".to_string(), + adjacent: None, + start: ab, + target: "thing".to_string(), + }; + let rc = ResumeKey { + characters: "asdf".to_string(), + adjacent: None, + start: ac, + target: "thing".to_string(), + }; + let rd = ResumeKey { + characters: "asdf".to_string(), + adjacent: None, + start: ad, + target: "thing".to_string(), + }; - let db = ResumeKeyDB { rkeys: vec![ra,rd,rc] }; + let db = ResumeKeyDB { + rkeys: vec![ra, rd, rc], + }; - assert_eq!(rb.latest(db).start.to_s(),"ffff"); + assert_eq!(rb.latest(db).start.to_s(), "ffff"); } impl TryFrom for ResumeKey { - type Error = ::result::Error; - fn try_from(s: String) -> Result { - let mut values: Vec = s.split("\n").map(|s| s.to_string()).filter(|s| !s.is_empty()).collect(); - let c = values.shift().ok_or_else(|| return MalformedResumeKey)?; - let a = values.shift().ok_or_else(|| return MalformedResumeKey).unwrap(); - let a = match a.parse::() { - Ok(_) => Some(a), - _ => None, - }; - Ok(ResumeKey { - characters: c.clone(), - adjacent: a, - start: Digits::new( - BaseCustom::::new(c.chars().collect()), - values.shift().ok_or_else(|| return MalformedResumeKey)? - ), - target: values.shift().ok_or_else(|| return MalformedResumeKey)?, - }) - } + type Error = ::result::Error; + fn try_from(s: String) -> Result { + let mut values: Vec = s + .split("\n") + .map(|s| s.to_string()) + .filter(|s| !s.is_empty()) + .collect(); + let c = values.shift().ok_or_else(|| return MalformedResumeKey)?; + let a = values + .shift() + .ok_or_else(|| return MalformedResumeKey) + .unwrap(); + let a = match a.parse::() { + Ok(_) => Some(a), + _ => None, + }; + Ok(ResumeKey { + characters: c.clone(), + adjacent: a, + start: Digits::new( + BaseCustom::::new(c.chars().collect()), + values.shift().ok_or_else(|| return MalformedResumeKey)?, + ), + target: values.shift().ok_or_else(|| return MalformedResumeKey)?, + }) + } } impl Display for ResumeKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let a: String; - match self.adjacent { - Some(ref v) => a = v.clone(), - _ => a = "None".to_string(), + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let a: String; + match self.adjacent { + Some(ref v) => a = v.clone(), + _ => a = "None".to_string(), + } + write!( + f, + "{}\n{}\n{}\n{}\n\n", + self.characters, + a, + self.start.to_s(), + self.target + ) } - write!(f, - "{}\n{}\n{}\n{}\n\n", - self.characters, - a, - self.start.to_s(), - self.target - ) - } } #[test] fn input_and_output_for_resume_works() { - let r = ResumeKey { - characters: String::from("asdf"), - adjacent: Some("1".to_string()), - start: Digits::new({BaseCustom::::new("asdf".chars().collect())}, String::from("aaaa")), - target: String::from("thing.aes") - }; - - let mut file = File::create(".example.res").ok().unwrap(); - file.write_all(&format!("{}", r).as_bytes()).ok(); - - let keys = ResumeKeyDB::get(".example.res".to_string()); - let k = keys.rkeys.iter().next(); - assert_eq!(Some(&r), k); - - let _ = fs::remove_file(".example.res"); - assert!(!Path::new(".example.res").exists(), "`.example.res` cleanup failed!"); + let r = ResumeKey { + characters: String::from("asdf"), + adjacent: Some("1".to_string()), + start: Digits::new( + BaseCustom::::new("asdf".chars().collect()), + String::from("aaaa"), + ), + target: String::from("thing.aes"), + }; + + let mut file = File::create(".example.res").ok().unwrap(); + file.write_all(&format!("{}", r).as_bytes()).ok(); + + let keys = ResumeKeyDB::get(".example.res".to_string()); + let k = keys.rkeys.iter().next(); + assert_eq!(Some(&r), k); + + let _ = fs::remove_file(".example.res"); + assert!( + !Path::new(".example.res").exists(), + "`.example.res` cleanup failed!" + ); } #[derive(Debug)] pub(crate) struct ResumeFile; impl ResumeFile { - pub(crate) fn save(rk: ResumeKey) { - let mut db = ResumeFile::load(); - db.update(rk); + pub(crate) fn save(rk: ResumeKey) { + let mut db = ResumeFile::load(); + db.update(rk); - let mut stringify = String::new(); - for key in db.rkeys.iter() { - stringify.push_str(&format!("{}", key)) - } + let mut stringify = String::new(); + for key in db.rkeys.iter() { + stringify.push_str(&format!("{}", key)) + } - let file = OpenOptions::new().write(true).create(true).open(".abrute"); - assert!(file.is_ok(), "Failed to create or open file `.abrute` for resuming work!"); + let file = OpenOptions::new().write(true).create(true).open(".abrute"); + assert!( + file.is_ok(), + "Failed to create or open file `.abrute` for resuming work!" + ); - if let Ok(mut f) = file { - f.write_all(stringify.as_bytes()).ok(); - let _ = f.sync_data(); - } + if let Ok(mut f) = file { + f.write_all(stringify.as_bytes()).ok(); + let _ = f.sync_data(); + } - ResumeFile::backup() - } - - fn backup() { - let file = ".abrute"; - let backup = ".abrute.bak"; - fs::copy(file, backup). - expect("Failed to backup `.abrute` to `.abrute.bak`!"); - } - - pub(crate) fn load() -> ResumeKeyDB { - let file = ".abrute"; - if Path::new(file).exists() { - let db = ResumeKeyDB::get(file.to_owned()); - if !db.rkeys.is_empty() { return db; } + ResumeFile::backup() } - let backup = ".abrute.bak"; - if Path::new(backup).exists() { - let db = ResumeKeyDB::get(file.to_owned()); - if !db.rkeys.is_empty() { return db; } + fn backup() { + let file = ".abrute"; + let backup = ".abrute.bak"; + fs::copy(file, backup).expect("Failed to backup `.abrute` to `.abrute.bak`!"); } - return ResumeKeyDB { rkeys: vec![] }; - } + pub(crate) fn load() -> ResumeKeyDB { + let file = ".abrute"; + if Path::new(file).exists() { + let db = ResumeKeyDB::get(file.to_owned()); + if !db.rkeys.is_empty() { + return db; + } + } + + let backup = ".abrute.bak"; + if Path::new(backup).exists() { + let db = ResumeKeyDB::get(file.to_owned()); + if !db.rkeys.is_empty() { + return db; + } + } - pub(crate) fn purge() { - let _ = fs::remove_file(".abrute"); - let _ = fs::remove_file(".abrute.bak"); - } + return ResumeKeyDB { rkeys: vec![] }; + } + + pub(crate) fn purge() { + let _ = fs::remove_file(".abrute"); + let _ = fs::remove_file(".abrute.bak"); + } } #[test] fn it_backup_system_works() { - let bc = BaseCustom::::new("asdf".chars().collect()); - let aa = Digits::new(bc.clone(), "aaaa".to_string()); - let ab = Digits::new(bc.clone(), "ssss".to_string()); - - let ra = ResumeKey { characters: "asdf".to_string(), adjacent: None, start: aa, target: "thing".to_string() }; - let rb = ResumeKey { characters: "asdf".to_string(), adjacent: None, start: ab, target: "thing".to_string() }; - - ResumeFile::save(ra.clone()); - ResumeFile::save(rb.clone()); - - assert!(Path::new(".abrute").exists(), "`.abrute` not found!"); - assert!(Path::new(".abrute.bak").exists(), "`.abrute.bak` not found!"); - - let loaded_db = ResumeFile::load(); - - assert!(!loaded_db.rkeys.contains(&ra), "`.abrute` backup contains first key backup!"); - assert!(loaded_db.rkeys.contains(&rb), "`.abrute` backup did not contain second key backup!"); - - ResumeFile::purge(); + let bc = BaseCustom::::new("asdf".chars().collect()); + let aa = Digits::new(bc.clone(), "aaaa".to_string()); + let ab = Digits::new(bc.clone(), "ssss".to_string()); + + let ra = ResumeKey { + characters: "asdf".to_string(), + adjacent: None, + start: aa, + target: "thing".to_string(), + }; + let rb = ResumeKey { + characters: "asdf".to_string(), + adjacent: None, + start: ab, + target: "thing".to_string(), + }; - assert!(!Path::new(".abrute").exists(), "`.abrute` cleanup failed!"); - assert!(!Path::new(".abrute.bak").exists(), "`.abrute.bak` cleanup failed!"); + ResumeFile::save(ra.clone()); + ResumeFile::save(rb.clone()); + + assert!(Path::new(".abrute").exists(), "`.abrute` not found!"); + assert!( + Path::new(".abrute.bak").exists(), + "`.abrute.bak` not found!" + ); + + let loaded_db = ResumeFile::load(); + + assert!( + !loaded_db.rkeys.contains(&ra), + "`.abrute` backup contains first key backup!" + ); + assert!( + loaded_db.rkeys.contains(&rb), + "`.abrute` backup did not contain second key backup!" + ); + + ResumeFile::purge(); + + assert!(!Path::new(".abrute").exists(), "`.abrute` cleanup failed!"); + assert!( + !Path::new(".abrute.bak").exists(), + "`.abrute.bak` cleanup failed!" + ); } diff --git a/src/validators.rs b/src/validators.rs index 2ded371..fecfb4d 100644 --- a/src/validators.rs +++ b/src/validators.rs @@ -1,101 +1,99 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use std::process::{Command,Stdio}; use super::result::Error; -use std::path::Path; -use digits::Digits; use clap; +use digits::Digits; +use std::path::Path; +use std::process::{Command, Stdio}; pub fn validate_adjacent_input(v: String) -> Result<(), Error> { - if v.parse::().is_ok() { return Ok(()); } - Err(Error::InvalidAdjacentNumber) + if v.parse::().is_ok() { + return Ok(()); + } + Err(Error::InvalidAdjacentNumber) } pub fn validate_chunk_input(v: &str) -> Result<(), Error> { - if v.parse::().is_ok() { return Ok(()); } - Err(Error::InvalidChunkNumber) + if v.parse::().is_ok() { + return Ok(()); + } + Err(Error::InvalidChunkNumber) } pub fn validate_start_string(matches: &clap::ArgMatches, max: usize) -> Result<(), Error> { - if let Some(s) = matches.value_of("start") { - if s.len() > max { - return Err(Error::InvalidStringLength); - } - - let chrctrs: Vec = matches. - value_of("CHARACTERS"). - unwrap(). - chars(). - collect(); - let mut itr = s.chars(); - loop { - match itr.next() { - Some(ref c) => { - if !chrctrs.contains(c) { - return Err(Error::InvalidCharacterSet); - } - }, - _ => break, - } + if let Some(s) = matches.value_of("start") { + if s.len() > max { + return Err(Error::InvalidStringLength); + } + + let chrctrs: Vec = matches.value_of("CHARACTERS").unwrap().chars().collect(); + let mut itr = s.chars(); + loop { + match itr.next() { + Some(ref c) => { + if !chrctrs.contains(c) { + return Err(Error::InvalidCharacterSet); + } + } + _ => break, + } + } } - } - Ok(()) + Ok(()) } pub fn validate_and_prep_sequencer_adjacent<'a>( - sequencer: &mut Digits, - adjacent: Option<&str> - ) -> Result<(), Error> { - - let seq_base = sequencer.base(); - - if let &Some(num) = &adjacent { - validate_adjacent_input(num.to_string())?; - if seq_base > 3 { - sequencer.prep_non_adjacent( - num.parse::().unwrap() - ); + sequencer: &mut Digits, + adjacent: Option<&str>, +) -> Result<(), Error> { + let seq_base = sequencer.base(); + + if let &Some(num) = &adjacent { + validate_adjacent_input(num.to_string())?; + if seq_base > 3 { + sequencer.prep_non_adjacent(num.parse::().unwrap()); + } } - } - Ok(()) + Ok(()) } pub fn validate_file_exists(target: &str) -> Result<(), Error> { - if !Path::new(target).exists() { - return Err(Error::FileMissing) - } - - Ok(()) + if !Path::new(target).exists() { + return Err(Error::FileMissing); + } + Ok(()) } pub fn validate_aescrpyt_executable() -> Result<(), Error> { - if Command::new("aescrypt"). - stdout(Stdio::null()). - stderr(Stdio::null()). - spawn(). - is_err() { - return Err(Error::AescryptMissing); - } + if Command::new("aescrypt") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .is_err() + { + return Err(Error::AescryptMissing); + } - Ok(()) + Ok(()) } pub fn validate_unzip_executable() -> Result<(), Error> { - if Command::new("unzip"). - stdout(Stdio::null()). - stderr(Stdio::null()). - spawn(). - is_err() { - return Err(Error::UnzipMissing); - } + if Command::new("unzip") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .is_err() + { + return Err(Error::UnzipMissing); + } - Ok(()) + Ok(()) } diff --git a/src/web.rs b/src/web.rs index a6a400b..b0f3d63 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,24 +1,22 @@ // Copyright 2017-2018 Daniel P. Clark & other abrute Developers -// +// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use tiny_http::{Server, Response}; +use tiny_http::{Response, Server}; extern crate serde; extern crate serde_json; -use ::model::report_data::*; +use model::report_data::*; pub fn host_data(web_reporter: &ReportData) { - let server = Server::http("0.0.0.0:3838").unwrap(); + let server = Server::http("0.0.0.0:3838").unwrap(); - for request in server.incoming_requests() { - let response = Response::from_string({ - serde_json::to_string(&web_reporter).unwrap_or("".to_string()) - }); - let _ = request.respond(response); - } + for request in server.incoming_requests() { + let response = Response::from_string({ + serde_json::to_string(&web_reporter).unwrap_or("".to_string()) + }); + let _ = request.respond(response); + } } - -