mirror of
				https://github.com/002Hub/IPass.git
				synced 2025-10-31 18:09:47 +01:00 
			
		
		
		
	Compare commits
	
		
			8 Commits
		
	
	
		
			v0.4.0-pre
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 0419033d81 | ||
|  | 145d9edff1 | ||
|  | ffd49c2819 | ||
|  | 65ac1332b6 | ||
| 38a39f3d54 | |||
|  | 9a9a3c6654 | ||
|  | 3a80459b1c | ||
|  | f3c0b89bdf | 
							
								
								
									
										7
									
								
								.deepsource.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.deepsource.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| version = 1 | ||||
| 
 | ||||
| [[analyzers]] | ||||
| name = "rust" | ||||
| 
 | ||||
|   [analyzers.meta] | ||||
|   msrv = "stable" | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -4,3 +4,4 @@ comp.sh | ||||
| report.json | ||||
| *.ipass | ||||
| *.ipassx | ||||
| library/* | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| [submodule "library"] | ||||
| 	path = library | ||||
| 	url = https://github.com/002Hub/IPass-library | ||||
							
								
								
									
										1092
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1092
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,18 +1,13 @@ | ||||
| [package] | ||||
| name = "ipass" | ||||
| version = "0.4.0" | ||||
| version = "0.4.3" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| home = "0.5.4" | ||||
| rpassword = "7.2" | ||||
| rand = { features = ["std"], default-features = false, version = "0.8.5" } | ||||
| aes-gcm = { features = ["alloc", "aes"], default-features = false, version = "0.10.1" } | ||||
| sha2 = { default-features = false, version = "0.10.6" } | ||||
| hex = "0.4.3" | ||||
| brotli = { features = ["std"], default-features = false, version = "3.3.4" } | ||||
| ip_lib = { path = "library/" } | ||||
| 
 | ||||
| [profile.release] | ||||
| opt-level = 'z'     # Optimize for size | ||||
|  | ||||
							
								
								
									
										2
									
								
								build.rs
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								build.rs
									
									
									
									
									
								
							| @ -1,3 +1,5 @@ | ||||
| fn main() { | ||||
|     if std::env::consts::OS == "windows" { | ||||
|         println!("cargo:rustc-link-arg=.res"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								library
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								library
									
									
									
									
									
										Submodule
									
								
							| @ -0,0 +1 @@ | ||||
| Subproject commit 29f6a59b1fed936be05c4c512a4c4fc20d73429d | ||||
							
								
								
									
										113
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -3,17 +3,16 @@ | ||||
| 
 | ||||
| //! IPass Password Manager
 | ||||
| 
 | ||||
| extern crate ip_lib; | ||||
| 
 | ||||
| use std::collections::HashMap; | ||||
| use std::io::Write; | ||||
| use rand::rngs::OsRng; | ||||
| use rand::RngCore; | ||||
| mod utils; | ||||
| 
 | ||||
| fn main() { | ||||
|     let version = option_env!("CARGO_PKG_VERSION").unwrap_or("x.x.x"); | ||||
|     println!("IPass v{}\n", version); | ||||
| 
 | ||||
|     let args = utils::get_args(); | ||||
|     let args = ip_lib::get_args(); | ||||
| 
 | ||||
|     if args.len() < 2 { | ||||
|         help_message(&args); | ||||
| @ -22,15 +21,16 @@ fn main() { | ||||
| 
 | ||||
|     let mode: &str = &args[1].trim().to_lowercase().to_owned(); | ||||
| 
 | ||||
|     let sync_file_loc = utils::get_home_folder_str()+"/.sync.ipass"; | ||||
|     let sync_file_loc = ip_lib::get_home_folder_str()+"/.sync.ipass"; | ||||
|     let sync_file_path = std::path::Path::new(&sync_file_loc); | ||||
| 
 | ||||
|     let sync_enabled = sync_file_path.clone().exists(); | ||||
|     let sync_loc: String; | ||||
| 
 | ||||
|     if sync_enabled { | ||||
|         // println!("Sync enabled, syncing...");
 | ||||
|         sync_loc = std::fs::read_to_string(sync_file_path).expect("Should have been able to read the sync file"); | ||||
|         utils::import_file(&sync_loc); | ||||
|         ip_lib::import_file(&sync_loc); | ||||
|     } else { | ||||
|         sync_loc = "".to_string(); //sync is disabled, no location needed
 | ||||
|     } | ||||
| @ -52,12 +52,17 @@ fn main() { | ||||
|         _ => help_message(&args), | ||||
|     } | ||||
|     if sync_enabled { | ||||
|         utils::export_file(&sync_loc); | ||||
|         ip_lib::export_file(&sync_loc); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn ask_for_pw() -> String { | ||||
|     let output = rpassword::prompt_password("Please enter the master password: ").unwrap(); | ||||
|     return output.replace(|c| matches!(c, '\n' | '\r'), ""); | ||||
| } | ||||
| 
 | ||||
| fn version_help(version: &str) { | ||||
|     let mut data = version.split("."); | ||||
|     let mut data = version.split('.'); | ||||
|     print!("Major {} ", data.next().unwrap()); | ||||
|     print!("Sub {} ", data.next().unwrap()); | ||||
|     println!("Bugfix {}", data.next().unwrap()); | ||||
| @ -130,17 +135,21 @@ fn help_message(args: &Vec<String>) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if help_messages.contains_key(&args[2]) { | ||||
|         println!("{} {}", &args[2], &help_messages[&args[2]]) 
 | ||||
|     } else { | ||||
|         println!("Unknown option {}",&args[2]) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn list() { | ||||
|     let mut paths: std::fs::ReadDir = std::fs::read_dir(utils::get_ipass_folder()).unwrap(); | ||||
|     let mut paths = ip_lib::get_entries(); | ||||
|     
 | ||||
|     let mut has_entry:bool = false; | ||||
| 
 | ||||
|     println!("Total entries: {}\n", paths.count()); | ||||
| 
 | ||||
|     paths = std::fs::read_dir(utils::get_ipass_folder()).unwrap(); | ||||
|     paths = ip_lib::get_entries(); | ||||
| 
 | ||||
|     for path in paths { | ||||
|         has_entry = true; | ||||
| @ -167,17 +176,7 @@ fn add(args: &Vec<String>) { | ||||
|     if args.len() > 4 { | ||||
|         pw = username+";"+args[4].trim(); | ||||
|     } else { | ||||
|         let alphabet: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!\"$%&/()=?{[]}\\,.-;:_><|+*#'"; | ||||
|         let alph_len: usize = alphabet.chars().count(); | ||||
|         let char_set:Vec<char> = alphabet.chars().collect(); | ||||
|         let mut chars_index: Vec<u8> = vec![0;20]; | ||||
|         OsRng.fill_bytes(&mut chars_index); | ||||
|         let mut chars: String = String::new(); | ||||
| 
 | ||||
|         for index in chars_index { | ||||
|             // println!("{} - {} - {}",index,(index as usize)%(alph_len-1),alph_len);
 | ||||
|             chars += &char_set[(index as usize)%(alph_len-1)].to_string(); | ||||
|         } | ||||
|         let chars = ip_lib::random_password(); | ||||
|         pw = username+";"+chars.as_str(); | ||||
| 
 | ||||
|         println!("Using auto generated password"); | ||||
| @ -186,7 +185,7 @@ fn add(args: &Vec<String>) { | ||||
|     } | ||||
| 
 | ||||
|     println!("Adding password for {}",args[2]); | ||||
|     let succeeded: bool = utils::create_entry(&args[2], pw); | ||||
|     let succeeded: bool = ip_lib::create_entry(&args[2], pw, ask_for_pw()); | ||||
|     if !succeeded { | ||||
|         println!("You already have an entry with that name! Did you mean to use \"edit\"?"); | ||||
|         return; | ||||
| @ -201,11 +200,11 @@ fn get(args: &Vec<String>) { | ||||
|         return; | ||||
|     } | ||||
|     let name: &String = &args[2]; | ||||
|     let filepath = &(utils::get_ipass_folder()+name+".ipass"); | ||||
|     let filepath = &(ip_lib::get_ipass_folder()+name+".ipass"); | ||||
|     if std::path::Path::new(filepath).exists() { | ||||
|         println!("Getting entry"); | ||||
|         let entry: String = utils::get_entry(name); | ||||
|         let mut data = entry.split(";"); | ||||
|         let entry: String = ip_lib::get_entry(name, ask_for_pw()).expect("Failed to get entry"); | ||||
|         let mut data = entry.split(';'); | ||||
|         println!("Username: '{}' Password: '{}'",data.next().unwrap(),data.next().unwrap()); | ||||
|     } else { | ||||
|         println!("No such entry!"); | ||||
| @ -219,16 +218,16 @@ fn changepw(args: &Vec<String>) { | ||||
|         println!("Invalid usage of \"changepw\""); | ||||
|         return; | ||||
|     } | ||||
|     let filepath = &(utils::get_ipass_folder()+&args[2]+".ipass"); | ||||
|     let filepath = &(ip_lib::get_ipass_folder()+&args[2]+".ipass"); | ||||
|     if std::path::Path::new(filepath).exists() { | ||||
|         let output: String; | ||||
|         let mut output: String = String::default(); | ||||
|         if args.len() != 4 { | ||||
|             output = rpassword::prompt_password("Please enter the new password: ").unwrap(); | ||||
|         } else { | ||||
|             output = args[3].clone(); | ||||
|             output.clone_from(&args[3]); | ||||
|         } | ||||
| 
 | ||||
|         utils::edit_password(&args[2], output); | ||||
|         ip_lib::edit_password(&args[2], output, ask_for_pw()); | ||||
| 
 | ||||
|         println!("Changed Password of {}!", args[2]); | ||||
|     } else { | ||||
| @ -242,16 +241,16 @@ fn changeuser(args: &Vec<String>) { | ||||
|         println!("Invalid usage of \"changeuser\""); | ||||
|         return; | ||||
|     } | ||||
|     let filepath = &(utils::get_ipass_folder()+&args[2]+".ipass"); | ||||
|     let filepath = &(ip_lib::get_ipass_folder()+&args[2]+".ipass"); | ||||
|     if std::path::Path::new(filepath).exists() { | ||||
|         let output: String; | ||||
|         let mut output: String = String::default(); | ||||
|         if args.len() != 4 { | ||||
|             output = utils::prompt_answer("Enter new Username: ".to_string()); | ||||
|             output = ip_lib::prompt_answer("Enter new Username: ".to_string()); | ||||
|         } else { | ||||
|             output = args[3].clone(); | ||||
|             output.clone_from(&args[3]); | ||||
|         } | ||||
|         
 | ||||
|         utils::edit_username(&args[2], output); | ||||
|         ip_lib::edit_username(&args[2], output, ask_for_pw()); | ||||
| 
 | ||||
|         println!("Changed Username of {}!", args[2]); | ||||
|     } else { | ||||
| @ -265,9 +264,9 @@ fn rename(args: &Vec<String>) { | ||||
|         println!("Invalid usage of \"rename\""); | ||||
|         return; | ||||
|     } | ||||
|     let filepath = &(utils::get_ipass_folder()+&args[2]+".ipass"); | ||||
|     let filepath = &(ip_lib::get_ipass_folder()+&args[2]+".ipass"); | ||||
|     if std::path::Path::new(filepath).exists() { | ||||
|         utils::rename(&args[2],&args[3]); | ||||
|         ip_lib::rename(&args[2],&args[3], ask_for_pw()); | ||||
|         println!("Renamed {} to {}", args[2], args[3]); | ||||
|     } else { | ||||
|         println!("No such file"); | ||||
| @ -281,9 +280,9 @@ fn remove(args: &Vec<String>) { | ||||
|         return; | ||||
|     } | ||||
|     let name = &args[2]; | ||||
|     let filepath = &(utils::get_ipass_folder()+name+".ipass"); | ||||
|     let filepath = &(ip_lib::get_ipass_folder()+name+".ipass"); | ||||
|     if std::path::Path::new(filepath).exists() { | ||||
|     if utils::prompt_answer(format!("Are you sure you want to delete {}? [y/N] ", name)) == "y" { | ||||
|     if ip_lib::prompt_answer(format!("Are you sure you want to delete {}? [y/N] ", name)) == "y" { | ||||
|         std::fs::remove_file(filepath).unwrap(); | ||||
|         println!("Removed entry \"{}\"", name); | ||||
|     } else { | ||||
| @ -297,16 +296,16 @@ fn remove(args: &Vec<String>) { | ||||
| 
 | ||||
| fn import(args: &Vec<String>) { | ||||
|     //! arguments: program import {location}
 | ||||
|     let mut location = utils::get_home_folder_str(); | ||||
|     let mut location = ip_lib::get_home_folder_str(); | ||||
|     if args.len() == 3 { | ||||
|         location = args[2].clone(); | ||||
|         location.clone_from(&args[2]); | ||||
|     } else { | ||||
|         if utils::prompt_answer(format!("No location specified, defaulting to {} continue? [Y/n] ", location.clone())) == "n" { | ||||
|         if ip_lib::prompt_answer(format!("No location specified, defaulting to {} continue? [Y/n] ", location.clone())) == "n" { | ||||
|             println!("Operation cancelled"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     if utils::import_file(&location) { | ||||
|     if ip_lib::import_file(&location) { | ||||
|         println!("Imported all entries!"); | ||||
|     } else { | ||||
|         println!("No such file found!"); | ||||
| @ -316,16 +315,16 @@ fn import(args: &Vec<String>) { | ||||
| 
 | ||||
| fn export(args: &Vec<String>) { | ||||
|     //! arguments: program export {location}
 | ||||
|     let mut location = utils::get_home_folder_str(); | ||||
|     let mut location = ip_lib::get_home_folder_str(); | ||||
|     if args.len() == 3 { | ||||
|         location = args[2].clone(); | ||||
|         location.clone_from(&args[2]); | ||||
|     } else { | ||||
|         if utils::prompt_answer(format!("No location specified, defaulting to {} continue? [Y/n] ", location.clone())) == "n" { | ||||
|         if ip_lib::prompt_answer(format!("No location specified, defaulting to {} continue? [Y/n] ", location.clone())) == "n" { | ||||
|             println!("Operation cancelled"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     if utils::export_file(&location) { | ||||
|     if ip_lib::export_file(&location) { | ||||
|         println!("Saved at: '{}/export.ipassx'", location); | ||||
|     } else { | ||||
|         println!("Failed saving at '{}/export.ipassx' does it exist?",location); | ||||
| @ -333,16 +332,16 @@ fn export(args: &Vec<String>) { | ||||
| } | ||||
| 
 | ||||
| fn clear() { | ||||
|     if utils::prompt_answer("Are you sure you want to clear everything? [y/N] ".to_string()) != "y" { | ||||
|     if ip_lib::prompt_answer("Are you sure you want to clear everything? [y/N] ".to_string()) != "y" { | ||||
|         println!("operation cancelled!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     let paths = std::fs::read_dir(utils::get_ipass_folder()).unwrap(); | ||||
|     let paths = std::fs::read_dir(ip_lib::get_ipass_folder()).unwrap(); | ||||
| 
 | ||||
|     for path in paths { | ||||
|         if let Ok(p) = path { | ||||
|             std::fs::remove_file(utils::get_ipass_folder()+"/"+p.file_name().into_string().unwrap().as_str()).unwrap(); | ||||
|             std::fs::remove_file(ip_lib::get_ipass_folder()+"/"+p.file_name().into_string().unwrap().as_str()).unwrap(); | ||||
|         } | ||||
|     } | ||||
|     println!("Cleared all entries!"); | ||||
| @ -360,22 +359,22 @@ fn sync(args: &Vec<String>) { | ||||
| 
 | ||||
|     match arg.as_str() { | ||||
|         "on" => { | ||||
|             let location: String; | ||||
|             let mut location: String = String::default(); | ||||
| 
 | ||||
|             if args.len() < 4 { | ||||
|                 location = utils::prompt_answer("No location specified, please provide the location of the file you want to sync: ".to_string()); | ||||
|                 location = ip_lib::prompt_answer_nolower("No location specified, please provide the location of the file you want to sync: ".to_string()); | ||||
|             } else { | ||||
|                 location = args[3].clone(); | ||||
|                 location.clone_from(&args[3]); | ||||
|             } | ||||
| 
 | ||||
|             let mut sync_file = std::fs::File::create(utils::get_home_folder_str()+"/.sync.ipass").expect("could not open sync file"); | ||||
|             let mut sync_file = std::fs::File::create(ip_lib::get_home_folder_str()+"/.sync.ipass").expect("could not open sync file"); | ||||
|             sync_file.write(location.as_bytes()).expect("could not write to sync file"); | ||||
| 
 | ||||
|             if !utils::export_file(&location) { | ||||
|             if !ip_lib::export_file(&location) { | ||||
|                 eprintln!("Test sync error, make sure you specified a valid folder!"); | ||||
|             } else { | ||||
|                 println!("Sync is now Enabled!"); | ||||
|                 println!("Sync file: {}",location); | ||||
|                 println!("Sync file: {}\\export.ipassx",location); | ||||
|             } | ||||
| 
 | ||||
|             
 | ||||
| @ -384,14 +383,14 @@ fn sync(args: &Vec<String>) { | ||||
|         }, | ||||
|         "off" => { | ||||
| 
 | ||||
|             let sync_file_loc = utils::get_home_folder_str()+"/.sync.ipass"; | ||||
|             let sync_file_loc = ip_lib::get_home_folder_str()+"/.sync.ipass"; | ||||
|             let sync_file_path = std::path::Path::new(&sync_file_loc); | ||||
| 
 | ||||
|             let sync_enabled = sync_file_path.clone().exists(); | ||||
| 
 | ||||
|             if sync_enabled { | ||||
| 
 | ||||
|                 std::fs::remove_file(utils::get_home_folder_str()+"/.sync.ipass").expect("could not disable sync, is it already disabled?"); | ||||
|                 std::fs::remove_file(ip_lib::get_home_folder_str()+"/.sync.ipass").expect("could not disable sync, is it already disabled?"); | ||||
| 
 | ||||
|                 println!("Sync is now Disabled!"); | ||||
|             } else { | ||||
|  | ||||
							
								
								
									
										257
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
						
						
									
										257
									
								
								src/utils.rs
									
									
									
									
									
								
							| @ -1,257 +0,0 @@ | ||||
| use std::io::{Read, Write}; | ||||
| use aes_gcm::{ | ||||
|     aead::{Aead, KeyInit}, | ||||
|     Aes256Gcm, Nonce | ||||
| }; | ||||
| use sha2::{Sha256, Digest}; | ||||
| 
 | ||||
| pub fn get_args() -> Vec<String> { | ||||
|     std::env::args().collect() // [0] = file path; [n>0] = argument
 | ||||
| } | ||||
| 
 | ||||
| pub fn import_file(location:&String) -> bool { | ||||
|     if std::path::Path::new(&(location.clone()+"/export.ipassx")).exists() { | ||||
|         let mut reader = brotli::Decompressor::new( | ||||
|             std::fs::File::open(location.clone()+"/export.ipassx").unwrap(), | ||||
|             4096, // buffer size
 | ||||
|         ); | ||||
|         let mut content: String = String::new(); | ||||
|         let mut buf = [0u8; 4096]; | ||||
|         loop { | ||||
|             match reader.read(&mut buf[..]) { | ||||
|                 Err(e) => { | ||||
|                     if let std::io::ErrorKind::Interrupted = e.kind() { | ||||
|                         continue; | ||||
|                     } | ||||
|                     panic!("{}", e); | ||||
|                 } | ||||
|                 Ok(size) => { | ||||
|                     if size == 0 { | ||||
|                         break; | ||||
|                     } | ||||
|                     content += &std::str::from_utf8(&buf[..size]).unwrap(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let lines = content.lines(); | ||||
|         let mut name = ""; | ||||
|         for i in lines { | ||||
|             if name == "" { | ||||
|                 name = i; | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             let mut file = std::fs::File::create(format!("{}/{}.ipass",get_ipass_folder(), name)).unwrap(); | ||||
|             file.write_all(i.as_bytes()).unwrap(); | ||||
|             name = ""; | ||||
|         } | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn export_file(location:&String) -> bool { | ||||
|     let mut collected_data: String = String::new(); | ||||
| 
 | ||||
|     let paths = std::fs::read_dir(get_ipass_folder()).unwrap(); | ||||
| 
 | ||||
|     for p in paths { | ||||
|         if let Ok(path) = p { | ||||
|             let content = &mut std::fs::read_to_string(get_ipass_folder()+&path.file_name().into_string().unwrap()).expect("Should have been able to read the file"); | ||||
|             collected_data += format!("{}\n{}\n", path.file_name().into_string().unwrap().replace(".ipass", ""),content).as_str(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if let Ok(file) = std::fs::File::create(location.clone()+"/export.ipassx") { | ||||
|         let mut writer = brotli::CompressorWriter::new( | ||||
|             file, | ||||
|             4096, | ||||
|             11, | ||||
|             22); | ||||
|         
 | ||||
|         match writer.write_all(collected_data.as_bytes()) { | ||||
|             Err(e) => panic!("{}", e), | ||||
|             Ok(_) => {}, | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn vecu8_to_string(vec: Vec<u8>) -> String { | ||||
|     let mut do_print_warning = false; | ||||
|     let mut out: String = String::new(); | ||||
|     for ind in vec { | ||||
|         if let Ok(a) = std::str::from_utf8(&[ind]) { | ||||
|             out += a; | ||||
|         } else { | ||||
|             do_print_warning = true; | ||||
|             eprintln!("[WARNING] malformed character {}",ind); | ||||
|             let mut temp_vec: Vec<u8> = Vec::new(); | ||||
|             temp_vec.insert(0,ind%128); | ||||
|             out += vecu8_to_string(temp_vec).as_str(); | ||||
|         } | ||||
|     } | ||||
|     if do_print_warning { | ||||
|         println!("[WARNING] Output may be corrupt"); | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| fn encrypt_pass(nonce_arg:String, pass: String,mpw: String) -> String { | ||||
|     let mut nonce_argument = String::new(); | ||||
|     if nonce_arg.len() < 12 { | ||||
|         nonce_argument = nonce_arg.clone() + &" ".repeat(12-nonce_arg.len()); | ||||
|     } | ||||
|     if nonce_arg.len() > 12 { | ||||
|         nonce_argument = nonce_arg[0..12].to_string(); | ||||
|     } | ||||
| 
 | ||||
|     let mut nonce_hasher = Sha256::new(); | ||||
|     nonce_hasher.update(nonce_argument.as_bytes()); | ||||
| 
 | ||||
|     let nonce_final = &nonce_hasher.finalize()[0..12]; | ||||
| 
 | ||||
| 
 | ||||
|     let mut hasher = Sha256::new(); | ||||
|     hasher.update(mpw.as_bytes()); | ||||
| 
 | ||||
|     let master_pw = &hasher.finalize(); | ||||
| 
 | ||||
|     let cipher = Aes256Gcm::new(master_pw); | ||||
|     let nonce = Nonce::from_slice(nonce_final); // 96-bits; unique per message
 | ||||
|     let ciphertext = cipher.encrypt(nonce, pass.as_ref()).unwrap(); | ||||
|     return hex::encode(ciphertext); | ||||
| } | ||||
| 
 | ||||
| fn decrypt_pass(nonce_arg:String, pass: Vec<u8>,mpw: String) -> String { | ||||
|     let mut nonce_argument = String::new(); | ||||
|     if nonce_arg.len() < 12 { | ||||
|         nonce_argument = nonce_arg.clone() + &" ".repeat(12-nonce_arg.len()); | ||||
|     } | ||||
|     if nonce_arg.len() > 12 { | ||||
|         nonce_argument = nonce_arg[0..12].to_string(); | ||||
|     } | ||||
| 
 | ||||
|     let mut nonce_hasher = Sha256::new(); | ||||
|     nonce_hasher.update(nonce_argument.as_bytes()); | ||||
| 
 | ||||
|     let nonce_final = &nonce_hasher.finalize()[0..12]; | ||||
| 
 | ||||
|     let mut hasher = Sha256::new(); | ||||
|     hasher.update(mpw.as_bytes()); | ||||
| 
 | ||||
|     let master_pw = &hasher.finalize(); | ||||
|     let cipher = Aes256Gcm::new(master_pw); | ||||
|     let nonce = Nonce::from_slice(nonce_final); // 96-bits; unique per message
 | ||||
| 
 | ||||
|     let plaintext = cipher.decrypt(nonce, pass.as_ref()); | ||||
|     match plaintext { | ||||
|         Ok(res) => { | ||||
|             return vecu8_to_string(res); | ||||
|         } | ||||
|         Err(_) => { | ||||
|             eprintln!("[ERROR] Error decrypting data, check your master password"); | ||||
|             std::process::exit(1); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn get_home_folder_str() -> String { | ||||
|     match home::home_dir() { | ||||
|         Some(path) => { | ||||
|             let p = path.to_str(); | ||||
|             match p { | ||||
|                 Some(pa) => return pa.to_owned(), | ||||
|                 None => return "".to_owned(), | ||||
|             } | ||||
|         }, | ||||
|         None => return "".to_owned(), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn get_ipass_folder() -> String { | ||||
|     let path = get_home_folder_str()+"/.IPass/"; | ||||
|     std::fs::create_dir_all(&path).unwrap(); | ||||
|     return path; | ||||
| } | ||||
| 
 | ||||
| pub fn create_entry(name: &String, pw: String) -> bool { | ||||
|     if std::path::Path::new(&(get_ipass_folder()+name+".ipass")).exists() { | ||||
|         return false; | ||||
|     } | ||||
|     let mpw = ask_for_pw(); | ||||
|     // println!("{pw}");
 | ||||
|     let pw = encrypt_pass(name.to_owned(), pw,mpw); | ||||
|     let mut file = std::fs::File::create(get_ipass_folder()+name+".ipass").unwrap(); | ||||
|     file.write_all(pw.as_bytes()).unwrap(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| fn read_entry(name:&String,mpw:String) -> String { | ||||
|     let content = &mut std::fs::read_to_string(get_ipass_folder()+name+".ipass").expect("Should have been able to read the file"); | ||||
|     return decrypt_pass(name.to_owned(),hex::decode(content).unwrap(),mpw).to_owned(); | ||||
| } | ||||
| 
 | ||||
| pub fn get_entry(name:&String) -> String { | ||||
|     let mpw = ask_for_pw(); | ||||
|     return read_entry(name,mpw); | ||||
| } | ||||
| 
 | ||||
| pub fn edit_password(name:&String, password:String) { | ||||
|     let mpw = ask_for_pw(); | ||||
|     let entry = read_entry(name, mpw.clone()); | ||||
|     // println!("entry: {entry}");
 | ||||
|     let mut parts = entry.split(";"); | ||||
|     let username = parts.next().unwrap().to_string(); | ||||
|     let _old_password = parts.next().unwrap(); | ||||
|     let data = encrypt_pass(name.to_owned(), username+";"+password.as_str(),mpw); | ||||
|     let mut file = std::fs::File::create(get_ipass_folder()+name+".ipass").unwrap(); | ||||
|     file.write_all(data.as_bytes()).unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub fn edit_username(name:&String, username: String) { | ||||
|     let mpw = ask_for_pw(); | ||||
|     let entry = read_entry(name, mpw.clone()); | ||||
|     // println!("entry: {entry}");
 | ||||
|     let mut parts = entry.split(";"); | ||||
|     let _old_username = parts.next().unwrap(); | ||||
|     let password = parts.next().unwrap(); | ||||
|     let data = encrypt_pass(name.to_owned(), username+";"+password,mpw); | ||||
|     let mut file = std::fs::File::create(get_ipass_folder()+name+".ipass").unwrap(); | ||||
|     file.write_all(data.as_bytes()).unwrap(); | ||||
| } | ||||
| 
 | ||||
| fn ask_for_pw() -> String { | ||||
|     let output = rpassword::prompt_password("Please enter the master password: ").unwrap(); | ||||
|     return output.replace("\n", "").replace("\r",""); | ||||
| } | ||||
| 
 | ||||
| pub fn prompt_answer(toprint: String) -> String { | ||||
|     print!("{toprint}"); | ||||
|     std::io::stdout().flush().unwrap(); | ||||
|     let mut choice = String::new(); | ||||
|     std::io::stdin().read_line(&mut choice).expect("Failed to read choice"); | ||||
| 
 | ||||
|     return choice.trim().to_lowercase(); | ||||
| } | ||||
| 
 | ||||
| pub fn rename(name: &String, new_name: &String) { | ||||
|     if !std::path::Path::new(&(get_ipass_folder()+name+".ipass")).exists() { | ||||
|         return; | ||||
|     } | ||||
|     if std::path::Path::new(&(get_ipass_folder()+new_name+".ipass")).exists() { | ||||
|         return; | ||||
|     } | ||||
|     let content = &mut std::fs::read_to_string(get_ipass_folder()+name+".ipass").expect("Should have been able to read the file"); | ||||
|     let mpw = ask_for_pw(); | ||||
|     let mut pw = decrypt_pass(name.to_owned(),hex::decode(content).unwrap(),mpw.clone()).to_owned(); | ||||
| 
 | ||||
|     pw = encrypt_pass(new_name.to_owned(), pw,mpw); | ||||
|     let mut file = std::fs::File::create(get_ipass_folder()+new_name+".ipass").unwrap(); | ||||
|     file.write_all(pw.as_bytes()).unwrap(); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user