10 Commits
2.1.8 ... 2.1.9

Author SHA1 Message Date
pyro57000
b137e0c34d switched the cobalt strike command to be
.output instead of .status to prevent
it from locking you out of returning to the
main menu.
2025-03-12 12:52:02 -05:00
pyro57000
8a1dca30e1 added logic to copy the cobaltstrike
folder into your project directory
and an option to launch that cobaltstrike
instance within the distrobox of your project
this should help keep cobalt strike data separate
also took a stab at cleaning up the left over
folders in the upcomming files and notes directories
the files folder cleans up now, but the notes folder
still needs work.
2025-03-12 12:48:21 -05:00
pyro57000
854feb2e2a added install logic to configure distrobox
to not pull the container image always.
this should save space, and fix cloning on
universal blue distros.
2025-03-12 10:50:37 -05:00
pyro57000
bfa766a2c3 fixed the new folders not being created first 2025-03-12 09:56:54 -05:00
pyro57000
f7bdd0ad8a fixed promotion function to use the project name
folder as well!
2025-03-12 09:49:15 -05:00
pyro57000
16706f8f6d fixed some stuff with box creation. 2025-03-12 09:39:19 -05:00
pyro57000
b6ec849b36 added some ideas for future development 2025-03-06 12:22:54 -06:00
pyro57000
69f5a4bd78 added stopping the template box to ensure
that cloning operations works
2025-03-06 11:53:11 -06:00
pyro57000
cad1f9d51c removed one redundant line 2025-03-06 09:24:33 -06:00
pyro57000
837012d163 fixed note folder creation with new pentest option 2025-03-06 09:22:15 -06:00
6 changed files with 241 additions and 49 deletions

View File

@@ -3,11 +3,11 @@
2.) cracte hash cracking with current computer code. 2.) cracte hash cracking with current computer code.
3.) adapt new project code to searh the upcomming folder before prompting for a path.
4.) create code that moves projects to a "writing" state and folder. 4.) create code that moves projects to a "writing" state and folder.
5.) create code that tracks "current, upcomming, and writing" states, maybe automatic zipping of folders after writing is done? 5.) create code that tracks "current, upcomming, and writing" states, maybe automatic zipping of folders after writing is done?
upcoming and current are done, but need to add writing yet...
# Unplanned, but would be cool # Unplanned, but would be cool
1.) create a "server" and "Client" infrastructure that can help manage the distrobox clients and the main server 1.) create a "server" and "Client" infrastructure that can help manage the distrobox clients and the main server
@@ -18,6 +18,10 @@
4.) implement a function to execute those copied exploits. 4.) implement a function to execute those copied exploits.
5.) add a "client" model for compromised internal hosts, this would likely need to be a server from a networking perspective that listens on 127.0.0.1 and then have the main interface connect to that over a proxy to run jobs. a good starting point would be to run some of our enumeration commands and scripts and save the output to the notes directly.
6.) add the ability to interact with the cobalt strike beacons... would need to learn agressor script... what a pain...
# NOTE # NOTE
if you wish to contribute, please do! just fix a bug or implement any of the above features and make a pull request!! if you wish to contribute, please do! just fix a bug or implement any of the above features and make a pull request!!

View File

@@ -1,9 +1,12 @@
use core::error;
use std::os::unix::thread::JoinHandleExt;
use std::process::Command;
use std::{path::PathBuf, process}; use std::{path::PathBuf, process};
use std::env; use std::env;
use std::fs; use std::fs;
use std::io::stdin; use std::io::stdin;
use std::io::Write; use std::io::Write;
use std::thread; use std::thread::{self, JoinHandle, Thread};
use std::time::Duration; use std::time::Duration;
use std::str::FromStr; use std::str::FromStr;
use crate::Project; use crate::Project;
@@ -72,6 +75,11 @@ pub fn project_inline_terminal(project: Project){
} }
pub fn make_box(project: &Project, tools_dir: &PathBuf, boxtemplate: &String, new: bool){ pub fn make_box(project: &Project, tools_dir: &PathBuf, boxtemplate: &String, new: bool){
println!("stopping template box to ensure we can clone it!");
let stop_result = Command::new("distrobox").arg("stop").arg("--root").arg(boxtemplate).status();
if stop_result.is_err(){
println!("error stopping template!");
}
if !new{ if !new{
let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox"); let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox");
let distrobox_rm_status = process::Command::new("distrobox-rm") let distrobox_rm_status = process::Command::new("distrobox-rm")
@@ -93,7 +101,7 @@ pub fn make_box(project: &Project, tools_dir: &PathBuf, boxtemplate: &String, ne
box_name_file.write_all(&box_name.as_bytes()).expect("error writing boxname to box file"); box_name_file.write_all(&box_name.as_bytes()).expect("error writing boxname to box file");
let pentest_volume = format!("{}:/pentest:rw", &project.files_folder.display()); let pentest_volume = format!("{}:/pentest:rw", &project.files_folder.display());
let toold_volume = format!("{}:/tools:rw", tools_dir.display()); let toold_volume = format!("{}:/tools:rw", tools_dir.display());
println!("distrobox create --root --init --unshare-all --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name); println!("distrobox create --root --init --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
let distrobox_result = process::Command::new("distrobox") let distrobox_result = process::Command::new("distrobox")
.arg("create") .arg("create")
.arg("--root") .arg("--root")
@@ -135,6 +143,66 @@ pub fn make_box(project: &Project, tools_dir: &PathBuf, boxtemplate: &String, ne
else{ else{
println!("ooof distrobox did not work.... try creating it yourself"); println!("ooof distrobox did not work.... try creating it yourself");
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, &toold_volume, &pentest_volume, &box_name); println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, &toold_volume, &pentest_volume, &box_name);
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name); println!("distrobox enter --root {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
} }
} }
pub fn clean_unused_boxes(projects: &Vec<Project>, boxtemplate: &String) -> Option<JoinHandle<()>>{
println!("starting template box: {}", boxtemplate);
let template_status = process::Command::new("distrobox").arg("enter").arg("--root").arg(boxtemplate).arg("--").arg("exit").status();
if template_status.is_err(){
let start_error = template_status.err().unwrap();
println!("OOOF issue starting template box, cancelling...");
println!("ERROR: {}", start_error);
return None;
}
println!("starting project boxes...");
for project in projects{
if project.stage.contains("current"){
let start_status = process::Command::new("distrobox").arg("enter").arg("--root").arg(&project.boxname).arg("--").arg("exit").status();
if start_status.is_err(){
let start_error = start_status.err().unwrap();
println!("OOOF issue starting {}, cancelling...", project.boxname);
println!("ERROR: {}", start_error);
return None;
}
}
}
println!("pruning unused containers...");
let handle = thread::spawn(move ||{
let spawn_result = process::Command::new("sudo").arg("podman").arg("system").arg("prune").arg("-a").arg("-f").output();
if spawn_result.is_err(){
let spawn_error = spawn_result.err().unwrap();
println!("oof trouble spawing prune command!, try manually");
println!("ERROR: {}", spawn_error);
}
println!("PRUNING COMPLETE!");
});
thread::sleep(Duration::from_secs(3));
println!("this will take some time, but its running on a different thread so you can continue working!");
return Some(handle);
}
pub fn launch_cobalt_strike(project: Project) -> Option<JoinHandle<()>>{
let handle = thread::spawn(move ||{
let mut cs_dir = PathBuf::new();
cs_dir.push(project.files_folder);
cs_dir.push("cobaltstrike/client");
let cd_res = env::set_current_dir(&cs_dir);
if cd_res.is_ok(){
let cobalt_strike_launch_result = Command::new("distrobox")
.arg("enter")
.arg("--root").arg(project.boxname)
.arg("--")
.arg("./cobaltstrike")
.output();
if cobalt_strike_launch_result.is_err(){
let error = cobalt_strike_launch_result.err().unwrap();
println!("error launching cobalt strike!");
println!("{}", error);
}
}
});
return Some(handle);
}

View File

@@ -9,6 +9,7 @@ use reqwest::blocking::get;
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
use std::process::exit; use std::process::exit;
use directories::UserDirs;
fn setup_folders(config_path: &PathBuf) -> (String, String, String, String, String, String, String, String, String){ fn setup_folders(config_path: &PathBuf) -> (String, String, String, String, String, String, String, String, String){
@@ -166,6 +167,71 @@ fn setup_folders(config_path: &PathBuf) -> (String, String, String, String, Stri
} }
fn configure_distrobox(){
let user_dirs_result = UserDirs::new();
let mut success = false;
let mut dbrcpath = PathBuf::new();
if user_dirs_result.is_some(){
let home = user_dirs_result.unwrap().home_dir().to_path_buf();
dbrcpath.push(home);
dbrcpath.push(".distroboxrc");
let box_config_string_result = fs::read_to_string("/usr/etc/distrobox/distrobox.conf");
if box_config_string_result.is_err(){
println!("error reading distrobox config file");
}
else{
let box_rc_file_res = fs::File::create(&dbrcpath);
if box_rc_file_res.is_err(){
println!("error creating {}", &dbrcpath.display());
}
else{
let mut box_rc_file = box_rc_file_res.unwrap();
let box_config_string = box_config_string_result.unwrap();
let box_config_lines: Vec<&str> = box_config_string.split("\n").collect();
let mut line_write_result = true;
while line_write_result{
for line in &box_config_lines{
let mut _outline = String::new();
if line.contains("container_always_pull"){
_outline = "container_always_pull=\"0\"".to_owned();
}
else{
_outline = line.to_string();
}
let box_rc_file_result = box_rc_file.write(_outline.as_bytes());
if box_rc_file_result.is_ok(){
box_rc_file_result.unwrap();
line_write_result = true;
}
else{
line_write_result = false;
}
}
if line_write_result == false{
success = false;
break;
}
else{
success = true;
break;
}
}
}
}
}
if success == false{
println!("Error getting user dirs!");
println!("distrobox config failed, please follow the following instructions...");
print!("
copy the distrobox config file to your home folder with the name .distroboxrc
cp /usr/etc/distrobox/distrobox.conf ~/.distroboxrc
Then edit the file to change the line container_always_pull=\"1\" to container_always_pull=\"0\"
");
}
}
pub fn install(config_path: &PathBuf){ pub fn install(config_path: &PathBuf){
let mut _terminal_commands = HashMap::from([ let mut _terminal_commands = HashMap::from([
@@ -284,5 +350,6 @@ Do you have a distrobox set up to function as your template for all new projects
- [ ] Service - [ ] Service
- [ ] Service! - [ ] Service!
- [ ] Serviceyear!").expect("error writing password spray template"); - [ ] Serviceyear!").expect("error writing password spray template");
configure_distrobox();
std::process::exit(0); std::process::exit(0);
} }

View File

@@ -37,6 +37,7 @@ fn get_active_project(projects: &Vec<Project>) -> &Project{
pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String, cracking_rig: String, rockyou: String, rule: String, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, password_spray_file: &PathBuf){ pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String, cracking_rig: String, rockyou: String, rule: String, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, password_spray_file: &PathBuf){
let mut loopize = true; let mut loopize = true;
let mut new_id = next_project_id(&config_path); let mut new_id = next_project_id(&config_path);
let mut threads = Vec::new();
loop { loop {
let active_project = get_active_project(&projects); let active_project = get_active_project(&projects);
let mut response = String::new(); let mut response = String::new();
@@ -124,18 +125,20 @@ Year: {}
9. ) promote project from upcoming to current 9. ) promote project from upcoming to current
10.) Open A New Terminal in Current Active Project 10.) Open A New Terminal in Current Active Project
11.) Open A Terminal In this windows for the current active project 11.) Open A Terminal In this windows for the current active project
12.) re-create the distrobox for the current active project 12.) open current project's cobalt strike
13.) Open Project Files Folder In Dolphin 13.) re-create the distrobox for the current active project
14.) Open Project Notes Folder In Dolphin 14.) Open Project Files Folder In Dolphin
15.) generate userpass file from your obsidian notes 15.) Open Project Notes Folder In Dolphin
16.) run pyro's initail enum script on a nessus csv for the current project 16.) generate userpass file from your obsidian notes
17.) Print Project Info For Report 17.) run pyro's initail enum script on a nessus csv for the current project
18.) Build host discovery cmd command from scope in notes 18.) Print Project Info For Report
19.) build portscan command from scope in notes 19.) Build host discovery cmd command from scope in notes
20.) Stop All Distroboxes 20.) build portscan command from scope in notes
21.) Password Spray (will print password to spray, and wait the obervation window time) 21.) Stop All Distroboxes
22.) crack password hashes on your cracking rig 22.) Password Spray (will print password to spray, and wait the obervation window time)
23.) Quit Application 23.) crack password hashes on your cracking rig
24.) prune unused distroboxes (free up system storage)
25.) Quit Application
\n",&base_files.display(), &upcoming_files.display(), active_project.customer, active_project.project_name, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, terminal, season, year); \n",&base_files.display(), &upcoming_files.display(), active_project.customer, active_project.project_name, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, terminal, season, year);
std::io::stdin().read_line(&mut response).expect("error getting menu input"); std::io::stdin().read_line(&mut response).expect("error getting menu input");
clear().expect("error clearing screen"); clear().expect("error clearing screen");
@@ -154,18 +157,20 @@ Year: {}
"9" => project_controls::promote_project(&mut projects, &config_path, base_files, base_notes, tools_dir, &boxtemplate), "9" => project_controls::promote_project(&mut projects, &config_path, base_files, base_notes, tools_dir, &boxtemplate),
"10" => box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()), "10" => box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()),
"11" => box_controls::project_inline_terminal(active_project.clone()), "11" => box_controls::project_inline_terminal(active_project.clone()),
"12" => box_controls::make_box(&active_project, &tools_dir, &boxtemplate, false), "12" => {let cs_thread = box_controls::launch_cobalt_strike(active_project.clone()); if cs_thread.is_some(){threads.push(cs_thread.unwrap());}},
"13" => info_controls::open_in_dolphin("files", active_project.clone()), "13" => box_controls::make_box(&active_project, &tools_dir, &boxtemplate, false),
"14" => info_controls::open_in_dolphin("notes", active_project.clone()), "14" => info_controls::open_in_dolphin("files", active_project.clone()),
"15" => info_controls::generate_userpass(&active_project), "15" => info_controls::open_in_dolphin("notes", active_project.clone()),
"16" => info_controls::run_initial_enum(&active_project), "16" => info_controls::generate_userpass(&active_project),
"17" => info_controls::print_report_information(active_project.clone()), "17" => info_controls::run_initial_enum(&active_project),
"18" => info_controls::build_cmd_for_host_discovery(&active_project), "18" => info_controls::print_report_information(active_project.clone()),
"19" => info_controls::build_cs_portscan_cmd(&active_project), "19" => info_controls::build_cmd_for_host_discovery(&active_project),
"20" => box_controls::stop_all_boxes(&projects), "20" => info_controls::build_cs_portscan_cmd(&active_project),
"21" => info_controls::password_spray_help(&active_project, season, lseason, year, &tools_dir, &config_path), "21" => box_controls::stop_all_boxes(&projects),
"22" => info_controls::crack_hashes(&cracking_rig, &active_project, &terminal, &rockyou, &rule), "22" => info_controls::password_spray_help(&active_project, season, lseason, year, &tools_dir, &config_path),
"23" => {project_controls::save_projects(&projects, &config_path); "23" => info_controls::crack_hashes(&cracking_rig, &active_project, &terminal, &rockyou, &rule),
"24" => {let prune_thread = box_controls::clean_unused_boxes(&projects, &boxtemplate); if prune_thread.is_some(){threads.push(prune_thread.unwrap());}},
"25" => {project_controls::save_projects(&projects, &config_path);
let mut stop = String::new(); let mut stop = String::new();
println!("stop all boxes?\ny/n"); println!("stop all boxes?\ny/n");
std::io::stdin().read_line(&mut stop).unwrap(); std::io::stdin().read_line(&mut stop).unwrap();
@@ -182,4 +187,7 @@ Year: {}
let mut enter = String::new(); let mut enter = String::new();
std::io::stdin().read_line(&mut enter).unwrap(); std::io::stdin().read_line(&mut enter).unwrap();
} }
for thread in threads{
thread.join().unwrap();
}
} }

View File

@@ -4,10 +4,12 @@ use std::io::stdin;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
use std::process::Command;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use std::str::FromStr; use std::str::FromStr;
use crate::get_user_input;
use fs_extra::file;
use crate::Project; use crate::Project;
use crate::box_controls::make_box; use crate::box_controls::make_box;
@@ -365,6 +367,8 @@ pub fn promote_project(projects: &mut Vec<Project>, config_path: &PathBuf, proje
let mut new_notes_dir = notes_dir.clone(); let mut new_notes_dir = notes_dir.clone();
new_files_dir.push(&promoted_project.customer); new_files_dir.push(&promoted_project.customer);
new_notes_dir.push(&promoted_project.customer); new_notes_dir.push(&promoted_project.customer);
fs::create_dir_all(&new_files_dir).unwrap();
fs::create_dir_all(&new_notes_dir).unwrap();
let folder_move_success = process::Command::new("mv") let folder_move_success = process::Command::new("mv")
.arg("-i") .arg("-i")
.arg(&project.files_folder) .arg(&project.files_folder)
@@ -377,19 +381,58 @@ pub fn promote_project(projects: &mut Vec<Project>, config_path: &PathBuf, proje
.status().expect("unable to call the system mv command"); .status().expect("unable to call the system mv command");
if folder_move_success.success(){ if folder_move_success.success(){
println!("we copied the project folder correctly!!"); println!("we copied the project folder correctly!!");
let mut remove_folder = PathBuf::new();
remove_folder.push(&project.files_folder);
remove_folder.pop();
let remove_files_res = fs::remove_dir_all(remove_folder);
if remove_files_res.is_err(){
println!("error removing the original files folder form the upcomming folder, manual cleanup required");
}
else{
remove_files_res.unwrap();
println!("upcoming files folder cleanup successful!");
}
} }
else{ else{
println!("failed to copy the project folder, try to move it manually!"); println!("failed to copy the project folder, try to move it manually!");
} }
if note_move_success.success(){ if note_move_success.success(){
println!("we copied the notes folder correctly!!"); println!("we copied the notes folder correctly!!");
let mut remove_folder = PathBuf::new();
remove_folder.push(&project.files_folder);
remove_folder.pop();
let remove_notes_res = fs::remove_dir_all(remove_folder);
if remove_notes_res.is_err(){
println!("error removing the original notes folder form the upcomming folder, manual cleanup required");
}
else{
remove_notes_res.unwrap();
println!("upcoming notes folder cleanup successful!");
}
} }
else{ else{
println!("failed to copy the notes folder, try to move it manually!"); println!("failed to copy the notes folder, try to move it manually!");
} }
new_files_dir.push(&promoted_project.project_name);
new_notes_dir.push(&promoted_project.project_name);
promoted_project.files_folder = new_files_dir; promoted_project.files_folder = new_files_dir;
promoted_project.notes_folder = new_notes_dir; promoted_project.notes_folder = new_notes_dir;
promoted_project.stage = "current".to_owned(); promoted_project.stage = "current".to_owned();
let cs_response = get_user_input("will you need to be using cobalt strike for this project?");
if cs_response.to_lowercase().contains("y"){
let cs_path = get_user_input("path to your current cobalt strike directory?");
let copy_result = Command::new("cp").arg("-R").arg(&cs_path).arg(&promoted_project.files_folder).status();
if copy_result.is_err(){
println!("oof we had an error copying... you'll have to copy this manually");
}
else{
let copy_exit = copy_result.unwrap();
if copy_exit.success() == false{
println!("oof we had an error copying... you'll have to copy this manually");
println!("run cp -R {} {}", &cs_path, &promoted_project.files_folder.display());
}
}
}
thread::sleep(Duration::from_secs(3)); thread::sleep(Duration::from_secs(3));
make_box(&promoted_project, tools_dir, boxtemplate, true); make_box(&promoted_project, tools_dir, boxtemplate, true);
projects_to_save.push(promoted_project); projects_to_save.push(promoted_project);

View File

@@ -34,12 +34,17 @@ fn create_note_file(path: &PathBuf) -> Option<File>{
fn external(passtemp: &PathBuf, project: &Project){ fn external(passtemp: &PathBuf, project: &Project){
// using a pathbuf to create files. // using a pathbuf to create files.
let mut notes_path = project.notes_folder.clone(); let mut notes_path = project.notes_folder.clone();
notes_path.push("general.md"); let file_creation_res = fs::create_dir_all(&notes_path);
let general_notes_result = fs::File::create(&notes_path); if file_creation_res.is_err(){
if general_notes_result.is_err(){ let error = file_creation_res.err().unwrap();
println!("oof we ran into issues making the general notes! try to creat manually!"); println!("error creating notes folder! {}", error);
} }
else{ else{
file_creation_res.unwrap();
}
notes_path.push("general.md");
let general_notes_result = create_note_file(&notes_path);
if general_notes_result.is_some(){
let mut general_notes = general_notes_result.unwrap(); let mut general_notes = general_notes_result.unwrap();
// for tagging // for tagging
let project_type = "External"; let project_type = "External";
@@ -86,11 +91,8 @@ Planning call notes:
} }
notes_path.pop(); notes_path.pop();
notes_path.push("attacks.md"); notes_path.push("attacks.md");
let attack_notes_result = fs::File::create(&notes_path); let attack_notes_result = create_note_file(&notes_path);
if attack_notes_result.is_err(){ if attack_notes_result.is_some(){
println!("oof we ran into issues making the general notes! try to creat manually!");
}
else {
let mut attack_notes = attack_notes_result.unwrap(); let mut attack_notes = attack_notes_result.unwrap();
writeln!(&mut attack_notes, "#{} #{} #attack", project.customer, "external").expect("error writing tags on attack notes"); writeln!(&mut attack_notes, "#{} #{} #attack", project.customer, "external").expect("error writing tags on attack notes");
write!(&mut attack_notes," write!(&mut attack_notes,"
@@ -124,21 +126,15 @@ passwords tried:
} }
notes_path.pop(); notes_path.pop();
notes_path.push("host_notes.md"); notes_path.push("host_notes.md");
let host_notes_result = fs::File::create(&notes_path); let host_notes_result = create_note_file(&notes_path);
if host_notes_result.is_err(){ if host_notes_result.is_some(){
println!("error creating host notes, try manually!");
}
else{
let mut host_notes = host_notes_result.unwrap(); let mut host_notes = host_notes_result.unwrap();
writeln!(&mut host_notes, "##{} #{} #host_notes", project.customer, "external").expect("error writing tag lin in host notes"); writeln!(&mut host_notes, "##{} #{} #host_notes", project.customer, "external").expect("error writing tag lin in host notes");
} }
notes_path.pop(); notes_path.pop();
notes_path.push("findings.md"); notes_path.push("findings.md");
let findings_notes_result = fs::File::create(notes_path); let findings_notes_result = create_note_file(&notes_path);
if findings_notes_result.is_err(){ if findings_notes_result.is_some(){
println!("error creating host findings file, try manually!");
}
else{
let mut finding_notes = findings_notes_result.unwrap(); let mut finding_notes = findings_notes_result.unwrap();
writeln!(&mut finding_notes, "#{} #{} #findings", project.customer, "external").expect("error writing tag line on findings"); writeln!(&mut finding_notes, "#{} #{} #findings", project.customer, "external").expect("error writing tag line on findings");
} }
@@ -335,6 +331,12 @@ pub fn start_pentest(config_path: &PathBuf, projects: &mut Vec<Project>, id: i32
project_files.push(&project_name); project_files.push(&project_name);
project_notes.push(&customer_name); project_notes.push(&customer_name);
project_notes.push(&project_name); project_notes.push(&project_name);
println!("Files: {}\nNotes: {}\n\n", project_files.display(), project_notes.display());
let confirm_response = get_user_input("does this look ok?");
if confirm_response.to_lowercase().contains("n"){
println!("oof sorry");
return;
}
let mut working = project_files.clone(); let mut working = project_files.clone();
create_project_folder(&mut working, "working"); create_project_folder(&mut working, "working");
create_project_folder(&mut working, "writing"); create_project_folder(&mut working, "writing");