1use crate::utils::setup::validate_setup;
2use crate::utils::validate_input::validate_username;
3use crate::utils::validate_input::validate_hash;
4use std::fs::File;
5use std::io::Write;
6use std::path::PathBuf;
7use std::env;
8use std::fs;
9
10use aes_gcm::{Aes256Gcm, Key, Nonce}; use aes_gcm::aead::{Aead, KeyInit};
12use sha2::{Sha256, Digest};
13use serde_json; pub struct Me {
17 pub username: String,
18 pub file_path: PathBuf,
19 pub data: Option<String>,
20}
21
22impl Me {
23 pub fn from_username_unchecked(username: &str) -> Self {
25 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
26 let file_path = PathBuf::from(format!("{}/.this/me/{}.me", home_dir, username));
27 Me {
28 username: username.to_string(),
29 file_path,
30 data: None,
31 }
32 }
33
34 pub fn delete(username: &str, hash: &str) -> std::io::Result<()> {
35 let me = Me::from_username_unchecked(username);
36
37 if !me.file_path.exists() {
38 return Err(std::io::Error::new(
39 std::io::ErrorKind::NotFound,
40 format!("❌ Identity '{}' does not exist.", username),
41 ));
42 }
43
44 let contents = fs::read(&me.file_path)?;
45 let decrypted = me.decrypt(&contents, hash);
46
47 match decrypted {
48 Ok(_) => {
49 fs::remove_file(&me.file_path)?;
50 println!("🗑️ Identity '{}' deleted.", username);
51 Ok(())
52 }
53 Err(_) => Err(std::io::Error::new(
54 std::io::ErrorKind::PermissionDenied,
55 "❌ Invalid password. Deletion aborted.",
56 )),
57 }
58 }
59
60 pub fn new(username: &str) -> std::io::Result<Self> {
62 match validate_username(username) {
63 Ok(_) => {
64 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
65 let file_path = PathBuf::from(format!("{}/.this/me/{}.me", home_dir, username));
66 Ok(Me {
67 username: username.to_string(),
68 file_path,
69 data: None,
70 })
71 }
72 Err(e) => {
73 eprintln!("❌ Error validating username: {}", e);
74 Err(std::io::Error::new(
75 std::io::ErrorKind::InvalidInput,
76 format!("❌ Error validating username: {}", e),
77 ))
78 }
79 }
80 }
81
82 pub fn create(username: &str, hash: &str) -> std::io::Result<Self> {
84 let me = Me::new(username)?;
85 validate_setup(false)?;
86
87 validate_hash(hash)?;
88 if me.file_path.exists() {
89 return Err(std::io::Error::new(
90 std::io::ErrorKind::AlreadyExists,
91 format!("❌ Identity '{}' already exists.", username),
92 ));
93 }
94
95 let data = format!(r#"{{"identity":{{"username":"{}"}}}}"#, username);
96 let encrypted = me.encrypt(&data, hash)?;
97 fs::create_dir_all(me.file_path.parent().unwrap())?;
98 let mut file = File::create(&me.file_path)?;
99 file.write_all(&encrypted)?;
100 Ok(me)
101 }
102
103
104 pub fn encrypt(&self, plaintext: &str, hash: &str) -> std::io::Result<Vec<u8>> {
106 validate_hash(hash)?;
107 let key_hash = Sha256::digest(hash.as_bytes());
108 let key = Key::<Aes256Gcm>::from_slice(&key_hash);
109 let cipher = Aes256Gcm::new(key);
110 let nonce_bytes: [u8; 12] = rand::random();
111 let nonce = Nonce::from_slice(&nonce_bytes);
112 let ciphertext = cipher.encrypt(nonce, plaintext.as_bytes())
113 .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Encryption failed"))?;
114
115 let mut result = nonce_bytes.to_vec();
116 result.extend(ciphertext);
117 Ok(result)
118 }
119
120 pub fn decrypt(&self, data: &[u8], hash: &str) -> Result<String, ()> {
122 if validate_hash(hash).is_err() {
123 return Err(());
124 }
125 if data.len() < 12 {
126 return Err(());
127 }
128
129 let key_hash = Sha256::digest(hash.as_bytes());
130 let key = Key::<Aes256Gcm>::from_slice(&key_hash);
131 let cipher = Aes256Gcm::new(key);
132 let (nonce_bytes, ciphertext) = data.split_at(12);
133 let nonce = Nonce::from_slice(nonce_bytes);
134 let decrypted = cipher.decrypt(nonce, ciphertext).map_err(|_| ())?;
135 String::from_utf8(decrypted).map_err(|_| ())
136 }
137
138 pub fn list() -> std::io::Result<Vec<String>> {
140 validate_setup(false)?;
141 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
142 let dir_path = PathBuf::from(format!("{}/.this/me", home_dir));
143
144 if !dir_path.exists() {
145 return Ok(vec![]);
146 }
147
148 let mut identities = vec![];
149 for entry in fs::read_dir(dir_path)? {
150 let entry = entry?;
151 if let Some(name) = entry.file_name().to_str() {
152 if name.ends_with(".me") {
153 identities.push(name.trim_end_matches(".me").to_string());
154 }
155 }
156 }
157
158 Ok(identities)
159 }
160
161 pub fn show(&self, password: &str) -> std::io::Result<()> {
163 validate_setup(false)?;
164 let contents = fs::read(&self.file_path)?;
165 let json = self.decrypt(&contents, password).map_err(|_| {
166 std::io::Error::new(std::io::ErrorKind::InvalidData, "❌ Failed to decrypt. Wrong password?")
167 })?;
168
169 match serde_json::from_str::<serde_json::Value>(&json) {
170 Ok(parsed) => {
171 println!("{}", serde_json::to_string_pretty(&parsed)?);
172 }
173 Err(_) => {
174 println!("{}", json);
175 }
176 }
177
178 Ok(())
179 }
180
181 pub fn change_hash(&self, old_hash: &str, new_hash: &str) -> std::io::Result<()> {
183 validate_hash(new_hash)?;
184
185 let contents = fs::read(&self.file_path)?;
186 let decrypted = self.decrypt(&contents, old_hash)
187 .map_err(|_| std::io::Error::new(std::io::ErrorKind::PermissionDenied, "❌ Old password incorrect."))?;
188
189 let encrypted = self.encrypt(&decrypted, new_hash)?;
190 let mut file = File::create(&self.file_path)?;
191 file.write_all(&encrypted)?;
192 println!("🔐 Password for '{}' successfully updated.", self.username);
193 Ok(())
194 }
195}