From a19c1e53c62f71641192a4765c2e9a59cf81e42e Mon Sep 17 00:00:00 2001 From: lordofwizard Date: Mon, 4 Sep 2023 21:03:14 +0530 Subject: [PATCH] basic template ready --- .gitignore | 1 + Cargo.lock | 7 ++ Cargo.toml | 8 +++ passwords.txt | 0 src/main.rs | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 198 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 passwords.txt create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a33b0cf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rusty_vault" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7772356 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rusty_vault" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/passwords.txt b/passwords.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fd685a8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,182 @@ +use std::fs::{File, OpenOptions}; +use std::io::{self, BufRead, BufReader, Write}; +use std::path::Path; +use std::vec::Vec; + +struct PasswordEntry { + username: String, + password: String, + website: String, +} + +impl PasswordEntry { + fn new(username: &str, password: &str, website: &str) -> PasswordEntry { + PasswordEntry { + username: username.to_string(), + password: password.to_string(), + website: website.to_string(), + } + } + + fn to_string(&self) -> String { + format!("Username: {}\nPassword: {}\nWebsite: {}\n", self.username, self.password, self.website) + } +} + +fn main() -> io::Result<()> { + let authenticated = authenticate_user(); + + if !authenticated { + println!("Authentication failed. Exiting."); + return Ok(()); + } + + let mut password_entries: Vec = load_passwords()?; + + loop { + println!("Password Manager Menu:"); + println!("1. Add Entry"); + println!("2. List Entries"); + println!("3. Quit"); + + let mut choice = String::new(); + io::stdin().read_line(&mut choice)?; + + match choice.trim() { + "1" => { + let username = prompt("Username: "); + let password = prompt("Password: "); + let website = prompt("Website: "); + + let entry = PasswordEntry::new(&username, &password, &website); + password_entries.push(entry); + + println!("Entry added successfully."); + } + "2" => { + list_passwords(&password_entries)?; + } + "3" => { + save_passwords(&password_entries)?; + println!("Goodbye!"); + break; + } + _ => println!("Invalid choice."), + } + } + + Ok(()) +} + +fn authenticate_user() -> bool { + println!("Please enter your credentials to authenticate:"); + let expected_credentials = load_first_line_from_file("passwords.txt"); + + if let Some(credentials) = expected_credentials { + let entered_username = prompt("Username: "); + let entered_password = prompt("Password: "); + return credentials == format!("{}:{}", entered_username, entered_password); + } + + false +} + +fn load_first_line_from_file(file_path: &str) -> Option { + let path = Path::new(file_path); + let file = match File::open(path) { + Ok(file) => file, + Err(_) => return None, + }; + + let mut reader = BufReader::new(file); + let mut first_line = String::new(); + reader.read_line(&mut first_line).ok()?; + + Some(first_line.trim().to_string()) +} + +fn prompt(prompt: &str) -> String { + print!("{}", prompt); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + + input.trim().to_string() +} + +fn load_passwords() -> io::Result> { + let path = Path::new("passwords.txt"); + let file = match File::open(path) { + Ok(file) => file, + Err(_) => { + // If the file does not exist, return an empty Vec. + return Ok(Vec::new()); + } + }; + + let reader = BufReader::new(file); + let mut password_entries: Vec = Vec::new(); + let mut current_entry = PasswordEntry { + username: String::new(), + password: String::new(), + website: String::new(), + }; + + let mut skip_first_line = true; + + for line in reader.lines() { + let line = line.unwrap().trim().to_string(); + + if skip_first_line { + skip_first_line = false; + continue; + } + + if line.is_empty() { + // Empty line indicates the end of an entry. + if !current_entry.username.is_empty() { + password_entries.push(current_entry); + current_entry = PasswordEntry::new("", "", ""); + } + } else { + let parts: Vec<&str> = line.splitn(2, ": ").collect(); + if parts.len() == 2 { + match parts[0] { + "Username" => current_entry.username = parts[1].to_string(), + "Password" => current_entry.password = parts[1].to_string(), + "Website" => current_entry.website = parts[1].to_string(), + _ => (), + } + } + } + } + + if !current_entry.username.is_empty() { + password_entries.push(current_entry); + } + + Ok(password_entries) +} + +fn save_passwords(entries: &Vec) -> io::Result<()> { + let path = Path::new("passwords.txt"); + let mut file = OpenOptions::new().write(true).truncate(true).create(true).open(path)?; + + for entry in entries { + file.write_all(entry.to_string().as_bytes())?; + file.write_all(b"\n")?; // Separate entries with newlines + } + + Ok(()) +} + +fn list_passwords(entries: &Vec) -> io::Result<()> { + println!("Password Entries:"); + + for entry in entries { + println!("{}", entry.to_string()); + } + + Ok(()) +}