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; use serde::Serialize;
15use crate::verbs::Verbs;
16
17#[derive(Serialize)]
19pub struct Me {
20 pub username: String,
21 pub file_path: PathBuf,
22 pub data: Option<String>,
23 pub verbs: Verbs,
24}
25
26impl Me {
27 pub fn from_username_unchecked(username: &str) -> Self {
29 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
30 let file_path = PathBuf::from(format!("{}/.this/me/{}.me", home_dir, username));
31 Me {
32 username: username.to_string(),
33 file_path,
34 data: None,
35 verbs: Verbs::new(),
36 }
37 }
38
39 pub fn delete(username: &str, hash: &str) -> std::io::Result<()> {
40 let me = Me::from_username_unchecked(username);
41
42 if !me.file_path.exists() {
43 return Err(std::io::Error::new(
44 std::io::ErrorKind::NotFound,
45 format!("❌ Identity '{}' does not exist.", username),
46 ));
47 }
48
49 let contents = fs::read(&me.file_path)?;
50 let decrypted = me.decrypt(&contents, hash);
51
52 match decrypted {
53 Ok(_) => {
54 fs::remove_file(&me.file_path)?;
55 println!("🗑️ Identity '{}' deleted.", username);
56 Ok(())
57 }
58 Err(_) => Err(std::io::Error::new(
59 std::io::ErrorKind::PermissionDenied,
60 "❌ Invalid password. Deletion aborted.",
61 )),
62 }
63 }
64
65 pub fn new(username: &str, hash: &str) -> std::io::Result<Self> {
67 validate_username(username)?;
68 validate_hash(hash)?;
69 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
70 let file_path = PathBuf::from(format!("{}/.this/me/{}.me", home_dir, username));
71 if file_path.exists() {
72 return Err(std::io::Error::new(
73 std::io::ErrorKind::AlreadyExists,
74 format!("❌ Identity '{}' already exists.", username),
75 ));
76 }
77 Ok(Me {
78 username: username.to_string(),
79 file_path,
80 data: None,
81 verbs: Verbs::new(),
82 })
83 }
84
85 pub fn encrypt(&self, plaintext: &str, hash: &str) -> std::io::Result<Vec<u8>> {
87 validate_hash(hash)?;
88 let key_hash = Sha256::digest(hash.as_bytes());
89 let key = Key::<Aes256Gcm>::from_slice(&key_hash);
90 let cipher = Aes256Gcm::new(key);
91 let nonce_bytes: [u8; 12] = rand::random();
92 let nonce = Nonce::from_slice(&nonce_bytes);
93 let ciphertext = cipher.encrypt(nonce, plaintext.as_bytes())
94 .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Encryption failed"))?;
95
96 let mut result = nonce_bytes.to_vec();
97 result.extend(ciphertext);
98 Ok(result)
99 }
100
101 pub fn decrypt(&self, data: &[u8], hash: &str) -> Result<String, ()> {
103 if validate_hash(hash).is_err() {
104 return Err(());
105 }
106 if data.len() < 12 {
107 return Err(());
108 }
109
110 let key_hash = Sha256::digest(hash.as_bytes());
111 let key = Key::<Aes256Gcm>::from_slice(&key_hash);
112 let cipher = Aes256Gcm::new(key);
113 let (nonce_bytes, ciphertext) = data.split_at(12);
114 let nonce = Nonce::from_slice(nonce_bytes);
115 let decrypted = cipher.decrypt(nonce, ciphertext).map_err(|_| ())?;
116 String::from_utf8(decrypted).map_err(|_| ())
117 }
118
119 pub fn list() -> std::io::Result<Vec<String>> {
121 validate_setup(false)?;
122 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
123 let dir_path = PathBuf::from(format!("{}/.this/me", home_dir));
124
125 if !dir_path.exists() {
126 return Ok(vec![]);
127 }
128
129 let mut identities = vec![];
130 for entry in fs::read_dir(dir_path)? {
131 let entry = entry?;
132 if let Some(name) = entry.file_name().to_str() {
133 if name.ends_with(".me") {
134 identities.push(name.trim_end_matches(".me").to_string());
135 }
136 }
137 }
138
139 Ok(identities)
140 }
141
142 pub fn display(username: &str, hash: &str) -> std::io::Result<String> {
144 validate_username(username)?;
145 validate_hash(hash)?;
146 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
147 let file_path = PathBuf::from(format!("{}/.this/me/{}.me", home_dir, username));
148 if !file_path.exists() {
149 return Err(std::io::Error::new(
150 std::io::ErrorKind::NotFound,
151 format!("❌ Identity '{}' does not exist.", username),
152 ));
153 }
154
155 let contents = fs::read(&file_path)?;
156 let me_temp = Me::from_username_unchecked(username);
157 let decrypted = me_temp.decrypt(&contents, hash)
158 .map_err(|_| std::io::Error::new(std::io::ErrorKind::PermissionDenied, "❌ Invalid password."))?;
159
160 Ok(decrypted)
161 }
162
163
164 pub fn change_hash(&self, old_hash: &str, new_hash: &str) -> std::io::Result<()> {
166 validate_hash(new_hash)?;
167
168 let contents = fs::read(&self.file_path)?;
169 let decrypted = self.decrypt(&contents, old_hash)
170 .map_err(|_| std::io::Error::new(std::io::ErrorKind::PermissionDenied, "❌ Old password incorrect."))?;
171
172 let encrypted = self.encrypt(&decrypted, new_hash)?;
173 let mut file = File::create(&self.file_path)?;
174 file.write_all(&encrypted)?;
175 println!("🔐 Password for '{}' successfully updated.", self.username);
176 Ok(())
177 }
178
179 pub fn save(&self, hash: &str) -> std::io::Result<()> {
181 validate_hash(hash)?;
182 let data = serde_json::to_string(&self).map_err(|_| {
183 std::io::Error::new(std::io::ErrorKind::Other, "❌ Failed to serialize identity")
184 })?;
185 let encrypted = self.encrypt(&data, hash)?;
186 fs::create_dir_all(self.file_path.parent().unwrap())?;
187 let mut file = File::create(&self.file_path)?;
188 file.write_all(&encrypted)?;
189 println!("✅ Identity '{}' saved.", self.username);
190 Ok(())
191 }
192
193 pub fn have(&mut self, key: &str, value: &str) -> std::io::Result<()> {
194 self.verbs.have(key, value)
195 }
196
197 pub fn be(&mut self, key: &str, value: &str) -> std::io::Result<()> {
198 self.verbs.be(key, value)
199 }
200
201 pub fn at(&mut self, key: &str, value: &str) -> std::io::Result<()> {
202 self.verbs.at(key, value)
203 }
204
205 pub fn relate(&mut self, key: &str, value: &str) -> std::io::Result<()> {
206 self.verbs.relate(key, value)
207 }
208
209 pub fn react(&mut self, key: &str, value: &str) -> std::io::Result<()> {
210 self.verbs.react(key, value)
211 }
212
213 pub fn say(&mut self, key: &str, value: &str) -> std::io::Result<()> {
214 self.verbs.say(key, value)
215 }
216
217 pub fn load(username: &str, hash: &str) -> std::io::Result<Self> {
219 validate_username(username)?;
220 validate_hash(hash)?;
221 let home_dir = env::var("HOME").unwrap_or_else(|_| ".".to_string());
222 let file_path = PathBuf::from(format!("{}/.this/me/{}.me", home_dir, username));
223 if !file_path.exists() {
224 return Err(std::io::Error::new(
225 std::io::ErrorKind::NotFound,
226 format!("❌ Identity '{}' does not exist.", username),
227 ));
228 }
229 Ok(Me {
230 username: username.to_string(),
231 file_path,
232 data: None,
233 verbs: Verbs::new(),
234 })
235 }
236}