1use std::collections::HashMap;
2use std::env;
3use std::fs;
4use std::io::{Read, Write};
5use std::os::unix::fs::PermissionsExt;
6use std::path::PathBuf;
7use std::str::from_utf8;
8
9use ansible_vault::{decrypt_vault, encrypt_vault};
10use fernet::Fernet;
11
12use base64::{engine::general_purpose, Engine as _};
13use passwords::analyzer;
14use passwords::scorer;
15use serde_json::json;
16
17use crate::errors::KeyFileError;
18use crate::keypair::Keypair;
19use crate::utils;
20
21use sodiumoxide::crypto::pwhash;
22use sodiumoxide::crypto::secretbox;
23
24const NACL_SALT: &[u8] = b"\x13q\x83\xdf\xf1Z\t\xbc\x9c\x90\xb5Q\x879\xe9\xb1";
25const LEGACY_SALT: &[u8] = b"Iguesscyborgslikemyselfhaveatendencytobeparanoidaboutourorigins";
26
27pub fn serialized_keypair_to_keyfile_data(keypair: &Keypair) -> Result<Vec<u8>, KeyFileError> {
34 let mut data: HashMap<&str, serde_json::Value> = HashMap::new();
35
36 if let Ok(Some(public_key)) = keypair.public_key() {
38 let public_key_str = hex::encode(&public_key);
39 data.insert("accountId", json!(format!("0x{}", public_key_str)));
40 data.insert("publicKey", json!(format!("0x{}", public_key_str)));
41 }
42 if let Ok(Some(private_key)) = keypair.private_key() {
43 let private_key_str = hex::encode(&private_key);
44 data.insert("privateKey", json!(format!("0x{}", private_key_str)));
45 }
46
47 if let Some(mnemonic) = keypair.mnemonic() {
49 data.insert("secretPhrase", json!(mnemonic.to_string()));
50 }
51
52 if let Some(seed_hex) = keypair.seed_hex() {
54 let seed_hex_str = match from_utf8(&seed_hex) {
55 Ok(s) => s.to_string(),
56 Err(_) => hex::encode(seed_hex),
57 };
58 data.insert("secretSeed", json!(format!("0x{}", seed_hex_str)));
59 }
60
61 if let Some(ss58_address) = keypair.ss58_address() {
62 data.insert("ss58Address", json!(ss58_address.to_string()));
63 }
64
65 let json_data = serde_json::to_string(&data)
67 .map_err(|e| KeyFileError::SerializationError(format!("Serialization error: {}", e)))?;
68 Ok(json_data.into_bytes())
69}
70
71pub fn deserialize_keypair_from_keyfile_data(keyfile_data: &[u8]) -> Result<Keypair, KeyFileError> {
80 let decoded = from_utf8(keyfile_data).map_err(|_| {
82 KeyFileError::DeserializationError("Failed to decode keyfile data.".to_string())
83 })?;
84
85 let keyfile_dict: HashMap<String, Option<String>> =
87 serde_json::from_str(decoded).map_err(|_| {
88 KeyFileError::DeserializationError("Failed to parse keyfile data.".to_string())
89 })?;
90
91 let secret_seed = keyfile_dict.get("secretSeed").and_then(|v| v.clone());
93 let secret_phrase = keyfile_dict.get("secretPhrase").and_then(|v| v.clone());
94 let private_key = keyfile_dict.get("privateKey").and_then(|v| v.clone());
95 let ss58_address = keyfile_dict.get("ss58Address").and_then(|v| v.clone());
96
97 if let Some(secret_phrase) = secret_phrase {
99 Keypair::create_from_mnemonic(secret_phrase.as_str()).map_err(|e| KeyFileError::Generic(e))
100 } else if let Some(seed) = secret_seed {
101 let seed = seed.trim_start_matches("0x");
103 let seed_bytes = hex::decode(seed).map_err(|e| KeyFileError::Generic(e.to_string()))?;
104 Keypair::create_from_seed(seed_bytes).map_err(|e| KeyFileError::Generic(e))
105 } else if let Some(private_key) = private_key {
106 let key = private_key.trim_start_matches("0x");
108 Keypair::create_from_private_key(key).map_err(|e| KeyFileError::Generic(e))
109 } else if let Some(ss58) = ss58_address {
110 Keypair::new(Some(ss58.clone()), None, None, 42, None, 1)
111 .map_err(|e| KeyFileError::Generic(e.to_string()))
112 } else {
113 Err(KeyFileError::Generic(
114 "Keypair could not be created from keyfile data.".to_string(),
115 ))
116 }
117}
118
119pub fn validate_password(password: &str) -> Result<bool, KeyFileError> {
126 if password.is_empty() {
128 return Ok(false);
129 }
130
131 let min_length = 6;
133 let min_score = 20.0; let analyzed = analyzer::analyze(password);
137 let score = scorer::score(&analyzed);
138
139 if password.len() >= min_length && score >= min_score {
141 let password_verification_response =
143 utils::prompt_password("Retype your password: ".to_string())
144 .expect("Failed to read the password.");
145
146 let password_verification = password_verification_response.trim();
148
149 if password == password_verification {
150 Ok(true)
151 } else {
152 utils::print("Passwords do not match.\n".to_string());
153 Ok(false)
154 }
155 } else {
156 utils::print("Password not strong enough. Try increasing the length of the password or the password complexity.\n".to_string());
157 Ok(false)
158 }
159}
160
161pub fn ask_password(validation_required: bool) -> Result<String, KeyFileError> {
168 let mut valid = false;
169 let mut password = utils::prompt_password("Enter your password: ".to_string());
170
171 if validation_required {
172 while !valid {
173 if let Some(ref pwd) = password {
174 valid = validate_password(&pwd)?;
175 if !valid {
176 password = utils::prompt_password("Enter your password again: ".to_string());
177 }
178 } else {
179 valid = true
180 }
181 }
182 }
183
184 Ok(password.unwrap_or("".to_string()).trim().to_string())
185}
186
187pub fn keyfile_data_is_encrypted_nacl(keyfile_data: &[u8]) -> bool {
194 keyfile_data.starts_with(b"$NACL")
195}
196
197pub fn keyfile_data_is_encrypted_ansible(keyfile_data: &[u8]) -> bool {
204 keyfile_data.starts_with(b"$ANSIBLE_VAULT")
205}
206
207pub fn keyfile_data_is_encrypted_legacy(keyfile_data: &[u8]) -> bool {
214 keyfile_data.starts_with(b"gAAAAA")
215}
216
217pub fn keyfile_data_is_encrypted(keyfile_data: &[u8]) -> bool {
224 let nacl = keyfile_data_is_encrypted_nacl(keyfile_data);
225 let ansible = keyfile_data_is_encrypted_ansible(keyfile_data);
226 let legacy = keyfile_data_is_encrypted_legacy(keyfile_data);
227 nacl || ansible || legacy
228}
229
230pub fn keyfile_data_encryption_method(keyfile_data: &[u8]) -> String {
237 if keyfile_data_is_encrypted_nacl(keyfile_data) {
238 "NaCl"
239 } else if keyfile_data_is_encrypted_ansible(keyfile_data) {
240 "Ansible Vault"
241 } else if keyfile_data_is_encrypted_legacy(keyfile_data) {
242 "legacy"
243 } else {
244 "unknown"
245 }
246 .to_string()
247}
248
249pub fn legacy_encrypt_keyfile_data(
257 keyfile_data: &[u8],
258 password: Option<String>,
259) -> Result<Vec<u8>, KeyFileError> {
260 let password = password.unwrap_or_else(||
261 ask_password(true).unwrap());
263
264 utils::print(
265 ":exclamation_mark: Encrypting key with legacy encryption method...\n".to_string(),
266 );
267
268 let encrypted_data = encrypt_vault(keyfile_data, password.as_str())
270 .map_err(|err| KeyFileError::EncryptionError(format!("{}", err)))?;
271
272 Ok(encrypted_data.into_bytes())
273}
274
275pub fn get_password_from_environment(env_var_name: String) -> Result<Option<String>, KeyFileError> {
282 match env::var(&env_var_name) {
283 Ok(encrypted_password_base64) => {
284 let encrypted_password = general_purpose::STANDARD
285 .decode(&encrypted_password_base64)
286 .map_err(|_| KeyFileError::Base64DecodeError("Invalid Base64".to_string()))?;
287 let decrypted_password = decrypt_password(&encrypted_password, &env_var_name);
288 Ok(Some(decrypted_password))
289 }
290 Err(_) => Ok(None),
291 }
292}
293
294fn derive_key(password: &[u8]) -> secretbox::Key {
296 let nacl_salt = pwhash::argon2i13::Salt::from_slice(NACL_SALT).expect("Invalid NACL_SALT.");
297 let mut key = secretbox::Key([0; secretbox::KEYBYTES]);
298 pwhash::argon2i13::derive_key(
299 &mut key.0,
300 password,
301 &nacl_salt,
302 pwhash::argon2i13::OPSLIMIT_SENSITIVE,
303 pwhash::argon2i13::MEMLIMIT_SENSITIVE,
304 )
305 .expect("Failed to derive key for NaCl decryption.");
306 key
307}
308
309pub fn encrypt_keyfile_data(
317 keyfile_data: &[u8],
318 password: Option<String>,
319) -> Result<Vec<u8>, KeyFileError> {
320 let password = match password {
322 Some(pwd) => pwd,
323 None => ask_password(true)?,
324 };
325
326 utils::print("Encrypting...\n".to_string());
327
328 let key = derive_key(password.as_bytes());
330
331 let nonce = secretbox::gen_nonce();
333 let encrypted_data = secretbox::seal(keyfile_data, &nonce, &key);
334
335 let mut result = b"$NACL".to_vec();
337 result.extend_from_slice(&nonce.0);
338 result.extend_from_slice(&encrypted_data);
339
340 Ok(result)
341}
342
343pub fn decrypt_keyfile_data(
352 keyfile_data: &[u8],
353 password: Option<String>,
354 password_env_var: Option<String>,
355) -> Result<Vec<u8>, KeyFileError> {
356 fn nacl_decrypt(keyfile_data: &[u8], key: &secretbox::Key) -> Result<Vec<u8>, KeyFileError> {
358 let data = &keyfile_data[5..]; let nonce = secretbox::Nonce::from_slice(&data[0..secretbox::NONCEBYTES]).ok_or(
360 KeyFileError::InvalidEncryption("Invalid nonce.".to_string()),
361 )?;
362 let ciphertext = &data[secretbox::NONCEBYTES..];
363 secretbox::open(ciphertext, &nonce, key).map_err(|_| {
364 KeyFileError::DecryptionError("Wrong password for nacl decryption.".to_string())
365 })
366 }
367 fn legacy_decrypt(password: &str, keyfile_data: &[u8]) -> Result<Vec<u8>, KeyFileError> {
369 let kdf = pbkdf2::pbkdf2_hmac::<sha2::Sha256>;
370 let mut key = vec![0; 32];
371 kdf(password.as_bytes(), LEGACY_SALT, 10000000, &mut key);
372
373 let fernet_key = Fernet::generate_key();
374 let fernet = Fernet::new(&fernet_key).unwrap();
375 let keyfile_data_str = from_utf8(keyfile_data)
376 .map_err(|e| KeyFileError::DeserializationError(e.to_string()))?;
377 fernet.decrypt(keyfile_data_str).map_err(|_| {
378 KeyFileError::DecryptionError("Wrong password for legacy decryption.".to_string())
379 })
380 }
381
382 let mut password = password;
383
384 if let Some(env_var_name_) = password_env_var {
386 if password.is_none() {
387 password = get_password_from_environment(env_var_name_)?;
388 }
389 }
390
391 if password.is_none() {
393 password = Some(ask_password(false)?);
394 }
395
396 let password = password.unwrap();
397
398 utils::print("Decrypting...\n".to_string());
399 if keyfile_data_is_encrypted_nacl(keyfile_data) {
401 let key = derive_key(password.as_bytes());
402 let decrypted_data = nacl_decrypt(keyfile_data, &key).map_err(|_| {
403 KeyFileError::DecryptionError("Wrong password for decryption.".to_string())
404 })?;
405 return Ok(decrypted_data);
406 }
407
408 if keyfile_data_is_encrypted_ansible(keyfile_data) {
410 let decrypted_data = decrypt_vault(keyfile_data, password.as_str()).map_err(|_| {
411 KeyFileError::DecryptionError("Wrong password for decryption.".to_string())
412 })?;
413 return Ok(decrypted_data);
414 }
415
416 if keyfile_data_is_encrypted_legacy(keyfile_data) {
418 let decrypted_data = legacy_decrypt(&password, keyfile_data).map_err(|_| {
419 KeyFileError::DecryptionError("Wrong password for decryption.".to_string())
420 })?;
421 return Ok(decrypted_data);
422 }
423
424 Err(KeyFileError::InvalidEncryption(
426 "Invalid or unknown encryption method.".to_string(),
427 ))
428}
429
430fn confirm_prompt(question: &str) -> bool {
431 let choice = utils::prompt(format!("{} (y/N): ", question)).expect("Failed to read input.");
432 choice.trim().to_lowercase() == "y"
433}
434
435fn expand_tilde(path: &str) -> String {
436 if path.starts_with("~/") {
437 if let Some(home_dir) = dirs::home_dir() {
438 return path.replacen('~', home_dir.to_str().unwrap(), 1);
439 }
440 }
441 path.to_string()
442}
443
444fn encrypt_password(key: &str, value: &str) -> Vec<u8> {
446 let key_bytes = key.as_bytes();
447 value
448 .as_bytes()
449 .iter()
450 .enumerate()
451 .map(|(i, &c)| c ^ key_bytes[i % key_bytes.len()])
452 .collect()
453}
454
455fn decrypt_password(data: &[u8], key: &str) -> String {
457 let key_bytes = key.as_bytes();
458 let decrypted_bytes: Vec<u8> = data
459 .iter()
460 .enumerate()
461 .map(|(i, &c)| c ^ key_bytes[i % key_bytes.len()])
462 .collect();
463 String::from_utf8(decrypted_bytes).unwrap_or_else(|_| String::new())
464}
465
466#[derive(Clone)]
467pub struct Keyfile {
468 pub path: String,
469 _path: PathBuf,
470 name: String,
471 should_save_to_env: bool,
472}
473impl std::fmt::Display for Keyfile {
474 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
475 match self.__str__() {
476 Ok(s) => write!(f, "{}", s),
477 Err(e) => write!(f, "Error displaying keyfile: {}", e),
478 }
479 }
480}
481
482impl Keyfile {
483 pub fn new(
492 path: String,
493 name: Option<String>,
494 should_save_to_env: bool,
495 ) -> Result<Self, KeyFileError> {
496 let expanded_path: PathBuf = PathBuf::from(expand_tilde(&path));
497 let name = name.unwrap_or_else(|| "Keyfile".to_string());
498 Ok(Keyfile {
499 path,
500 _path: expanded_path,
501 name,
502 should_save_to_env,
503 })
504 }
505
506 #[allow(clippy::bool_comparison)]
507 fn __str__(&self) -> Result<String, KeyFileError> {
508 if self.exists_on_device()? != true {
509 Ok(format!("keyfile (empty, {})>", self.path))
510 } else if self.is_encrypted()? {
511 let encryption_method = self._read_keyfile_data_from_file()?;
512 Ok(format!(
513 "Keyfile ({:?} encrypted, {})>",
514 encryption_method, self.path
515 ))
516 } else {
517 Ok(format!("keyfile (decrypted, {})>", self.path))
518 }
519 }
520
521 fn __repr__(&self) -> Result<String, KeyFileError> {
522 self.__str__()
523 }
524
525 pub fn get_keypair(&self, password: Option<String>) -> Result<Keypair, KeyFileError> {
532 let keyfile_data = self._read_keyfile_data_from_file()?;
534
535 let decrypted_keyfile_data = if keyfile_data_is_encrypted(&keyfile_data) {
537 decrypt_keyfile_data(&keyfile_data, password, Some(self.env_var_name()?))?
538 } else {
539 keyfile_data
540 };
541
542 deserialize_keypair_from_keyfile_data(&decrypted_keyfile_data)
544 }
545
546 pub fn get_name(&self) -> Result<String, KeyFileError> {
548 Ok(self.name.clone())
549 }
550
551 pub fn get_path(&self) -> Result<String, KeyFileError> {
553 Ok(self.path.clone())
554 }
555
556 pub fn data(&self) -> Result<Vec<u8>, KeyFileError> {
558 self._read_keyfile_data_from_file()
559 }
560
561 pub fn keyfile_data(&self) -> Result<Vec<u8>, KeyFileError> {
563 self._read_keyfile_data_from_file()
564 }
565
566 pub fn env_var_name(&self) -> Result<String, KeyFileError> {
568 let path = &self
569 .path
570 .replace(std::path::MAIN_SEPARATOR, "_")
571 .replace('.', "_");
572 Ok(format!("BT_PW_{}", path.to_uppercase()))
573 }
574
575 pub fn set_keypair(
583 &self,
584 keypair: Keypair,
585 encrypt: bool,
586 overwrite: bool,
587 password: Option<String>,
588 ) -> Result<(), KeyFileError> {
589 self.make_dirs()?;
590
591 let keyfile_data = serialized_keypair_to_keyfile_data(&keypair)?;
592
593 let final_keyfile_data = if encrypt {
594 let encrypted_data = encrypt_keyfile_data(&keyfile_data, password.clone())?;
595
596 if self.should_save_to_env {
598 self.save_password_to_env(password.clone())?;
599 }
600
601 encrypted_data
602 } else {
603 keyfile_data
604 };
605
606 self._write_keyfile_data_to_file(&final_keyfile_data, overwrite)?;
607
608 Ok(())
609 }
610
611 pub fn make_dirs(&self) -> Result<(), KeyFileError> {
613 if let Some(directory) = self._path.parent() {
614 if !directory.exists() {
616 fs::create_dir_all(directory)
618 .map_err(|e| KeyFileError::DirectoryCreation(e.to_string()))?;
619 }
620 }
621 Ok(())
622 }
623
624 pub fn exists_on_device(&self) -> Result<bool, KeyFileError> {
629 Ok(self._path.exists())
630 }
631
632 pub fn is_readable(&self) -> Result<bool, KeyFileError> {
634 if !self.exists_on_device()? {
636 return Ok(false);
637 }
638
639 let metadata = fs::metadata(&self._path).map_err(|e| {
641 KeyFileError::MetadataError(format!("Failed to get metadata for file: {}.", e))
642 })?;
643
644 let permissions = metadata.permissions();
646 let readable = permissions.mode() & 0o444 != 0; Ok(readable)
649 }
650
651 pub fn is_writable(&self) -> Result<bool, KeyFileError> {
656 if !self.exists_on_device()? {
658 return Ok(false);
659 }
660
661 let metadata = fs::metadata(&self._path).map_err(|e| {
663 KeyFileError::MetadataError(format!("Failed to get metadata for file: {}", e))
664 })?;
665
666 let permissions = metadata.permissions();
668 let writable = permissions.mode() & 0o222 != 0; Ok(writable)
671 }
672
673 pub fn is_encrypted(&self) -> Result<bool, KeyFileError> {
678 if !self.exists_on_device()? {
680 return Ok(false);
681 }
682
683 if !self.is_readable()? {
685 return Ok(false);
686 }
687
688 let keyfile_data = self._read_keyfile_data_from_file()?;
690
691 let is_encrypted = keyfile_data_is_encrypted(&keyfile_data);
693
694 Ok(is_encrypted)
695 }
696
697 pub fn _may_overwrite(&self) -> bool {
699 let choice = utils::prompt(format!(
700 "File {} already exists. Overwrite? (y/N) ",
701 self.path
702 ))
703 .expect("Failed to read input.");
704
705 choice.trim().to_lowercase() == "y"
706 }
707
708 pub fn check_and_update_encryption(
716 &self,
717 print_result: bool,
718 no_prompt: bool,
719 ) -> Result<bool, KeyFileError> {
720 if !self.exists_on_device()? {
721 if print_result {
722 utils::print(format!("Keyfile '{}' does not exist.\n", self.path));
723 }
724 return Ok(false);
725 }
726
727 if !self.is_readable()? {
728 if print_result {
729 utils::print(format!("Keyfile '{}' is not readable.\n", self.path));
730 }
731 return Ok(false);
732 }
733
734 if !self.is_writable()? {
735 if print_result {
736 utils::print(format!("Keyfile '{}' is not writable.\n", self.path));
737 }
738 return Ok(false);
739 }
740
741 let update_keyfile = false;
742 if !no_prompt {
743 let keyfile_data = self._read_keyfile_data_from_file()?;
745
746 if keyfile_data_is_encrypted(&keyfile_data)
748 && !keyfile_data_is_encrypted_nacl(&keyfile_data)
749 {
750 utils::print("You may update the keyfile to improve security...\n".to_string());
751
752 if update_keyfile == confirm_prompt("Update keyfile?") {
754 let mut stored_mnemonic = false;
755
756 while !stored_mnemonic {
758 utils::print(
759 "Please store your mnemonic in case an error occurs...\n".to_string(),
760 );
761 if confirm_prompt("Have you stored the mnemonic?") {
762 stored_mnemonic = true;
763 } else if !confirm_prompt("Retry and continue keyfile update?") {
764 return Ok(false);
765 }
766 }
767
768 let mut decrypted_keyfile_data: Option<Vec<u8>> = None;
770 let mut password: Option<String> = None;
771 while decrypted_keyfile_data.is_none() {
772 let pwd = ask_password(false)?;
773 password = Some(pwd.clone());
774
775 match decrypt_keyfile_data(
776 &keyfile_data,
777 Some(pwd),
778 Some(self.env_var_name()?),
779 ) {
780 Ok(decrypted_data) => {
781 decrypted_keyfile_data = Some(decrypted_data);
782 }
783 Err(_) => {
784 if !confirm_prompt("Invalid password, retry?") {
785 return Ok(false);
786 }
787 }
788 }
789 }
790
791 if let Some(password) = password {
793 if let Some(decrypted_data) = decrypted_keyfile_data {
794 let encrypted_keyfile_data =
795 encrypt_keyfile_data(&decrypted_data, Some(password))?;
796 self._write_keyfile_data_to_file(&encrypted_keyfile_data, true)?;
797 }
798 }
799 }
800 }
801 }
802
803 if print_result || update_keyfile {
804 let keyfile_data = self._read_keyfile_data_from_file()?;
806
807 return if !keyfile_data_is_encrypted(&keyfile_data) {
808 if print_result {
809 utils::print("Keyfile is not encrypted.\n".to_string());
810 }
811 Ok(false)
812 } else if keyfile_data_is_encrypted_nacl(&keyfile_data) {
813 if print_result {
814 utils::print("Keyfile is updated.\n".to_string());
815 }
816 Ok(true)
817 } else {
818 if print_result {
819 utils::print("Keyfile is outdated, please update using 'btcli'.\n".to_string());
820 }
821 Ok(false)
822 };
823 }
824 Ok(false)
825 }
826
827 pub fn encrypt(&self, mut password: Option<String>) -> Result<(), KeyFileError> {
832 if !self.exists_on_device()? {
834 return Err(KeyFileError::FileNotFound(format!(
835 "Keyfile at: {} does not exist",
836 self.path
837 )));
838 }
839
840 if !self.is_readable()? {
841 return Err(KeyFileError::NotReadable(format!(
842 "Keyfile at: {} is not readable",
843 self.path
844 )));
845 }
846
847 if !self.is_writable()? {
848 return Err(KeyFileError::NotWritable(format!(
849 "Keyfile at: {} is not writable",
850 self.path
851 )));
852 }
853
854 let keyfile_data = self._read_keyfile_data_from_file()?;
856
857 let final_data = if !keyfile_data_is_encrypted(&keyfile_data) {
858 let as_keypair = deserialize_keypair_from_keyfile_data(&keyfile_data)?;
859 let serialized_data = serialized_keypair_to_keyfile_data(&as_keypair)?;
860
861 if password.is_none() {
863 password = get_password_from_environment(self.env_var_name()?)?;
864 }
865
866 let encrypted_keyfile_data = encrypt_keyfile_data(&serialized_data, password.clone())?;
867
868 if self.should_save_to_env {
869 self.save_password_to_env(password.clone())?;
870 }
871
872 encrypted_keyfile_data
873 } else {
874 keyfile_data
875 };
876
877 self._write_keyfile_data_to_file(&final_data, true)?;
879
880 Ok(())
881 }
882
883 pub fn decrypt(&self, password: Option<String>) -> Result<(), KeyFileError> {
888 if !self.exists_on_device()? {
890 return Err(KeyFileError::FileNotFound(format!(
891 "Keyfile at: {} does not exist.",
892 self.path
893 )));
894 }
895 if !self.is_readable()? {
896 return Err(KeyFileError::NotReadable(format!(
897 "Keyfile at: {} is not readable.",
898 self.path
899 )));
900 }
901 if !self.is_writable()? {
902 return Err(KeyFileError::NotWritable(format!(
903 "Keyfile at: {} is not writable.",
904 self.path
905 )));
906 }
907
908 let keyfile_data = self._read_keyfile_data_from_file()?;
910
911 let decrypted_data = if keyfile_data_is_encrypted(&keyfile_data) {
912 decrypt_keyfile_data(&keyfile_data, password, Some(self.env_var_name()?))?
913 } else {
914 keyfile_data
915 };
916
917 let as_keypair = deserialize_keypair_from_keyfile_data(&decrypted_data)?;
918
919 let serialized_data = serialized_keypair_to_keyfile_data(&as_keypair)?;
920 self._write_keyfile_data_to_file(&serialized_data, true)?;
921 Ok(())
922 }
923
924 pub fn _read_keyfile_data_from_file(&self) -> Result<Vec<u8>, KeyFileError> {
931 if !self.exists_on_device()? {
933 return Err(KeyFileError::FileNotFound(format!(
934 "Keyfile at: {} does not exist.",
935 self.path
936 )));
937 }
938
939 if !self.is_readable()? {
941 return Err(KeyFileError::NotReadable(format!(
942 "Keyfile at: {} is not readable.",
943 self.path
944 )));
945 }
946
947 let mut file = fs::File::open(&self._path)
949 .map_err(|e| KeyFileError::FileOpen(format!("Failed to open file: {}.", e)))?;
950 let mut data_vec = Vec::new();
951 file.read_to_end(&mut data_vec)
952 .map_err(|e| KeyFileError::FileRead(format!("Failed to read file: {}.", e)))?;
953
954 Ok(data_vec)
955 }
956
957 pub fn _write_keyfile_data_to_file(
963 &self,
964 keyfile_data: &[u8],
965 overwrite: bool,
966 ) -> Result<(), KeyFileError> {
967 if self.exists_on_device()? && !overwrite && !self._may_overwrite() {
969 return Err(KeyFileError::NotWritable(format!(
970 "Keyfile at: {} is not writable",
971 self.path
972 )));
973 }
974
975 let mut keyfile = fs::OpenOptions::new()
976 .write(true)
977 .create(true)
978 .truncate(true) .open(&self._path)
980 .map_err(|e| KeyFileError::FileOpen(format!("Failed to open file: {}.", e)))?;
981
982 keyfile
984 .write_all(keyfile_data)
985 .map_err(|e| KeyFileError::FileWrite(format!("Failed to write to file: {}.", e)))?;
986
987 let mut permissions = fs::metadata(&self._path)
989 .map_err(|e| {
990 KeyFileError::MetadataError(format!("Failed to get metadata for file: {}.", e))
991 })?
992 .permissions();
993 permissions.set_mode(0o600); fs::set_permissions(&self._path, permissions).map_err(|e| {
995 KeyFileError::PermissionError(format!("Failed to set permissions: {}.", e))
996 })?;
997 Ok(())
998 }
999
1000 pub fn save_password_to_env(&self, password: Option<String>) -> Result<String, KeyFileError> {
1007 let password = match password {
1009 Some(pwd) => pwd,
1010 None => match ask_password(true) {
1011 Ok(pwd) => pwd,
1012 Err(e) => {
1013 utils::print(format!("Error asking password: {:?}.\n", e));
1014 return Ok("".to_string());
1015 }
1016 },
1017 };
1018 let env_var_name = self.env_var_name()?;
1020 let encrypted_password = encrypt_password(&env_var_name, &password);
1022 let encrypted_password_base64 = general_purpose::STANDARD.encode(&encrypted_password);
1023 env::set_var(&env_var_name, &encrypted_password_base64);
1025 Ok(encrypted_password_base64)
1026 }
1027
1028 pub fn remove_password_from_env(&self) -> Result<bool, KeyFileError> {
1030 let env_var_name = self.env_var_name()?;
1031
1032 if env::var(&env_var_name).is_ok() {
1033 env::remove_var(&env_var_name);
1034 let message = format!("Environment variable '{}' removed.\n", env_var_name);
1035 utils::print(message);
1036 Ok(true)
1037 } else {
1038 let message = format!("Environment variable '{}' does not exist.\n", env_var_name);
1039 utils::print(message);
1040 Ok(false)
1041 }
1042 }
1043}