Restrict vault.json permssion to owner and using random suffix for temp vault.json file (#8932)
* Move dedup retry logic to a separate function * Use random suffix temp vault filename and restrict permissions to owner
This commit is contained in:
parent
796d72f48e
commit
5ae8e8a9ca
@ -33,9 +33,33 @@ const IGNORED_FILES: &'static [&'static str] = &[
|
|||||||
"vault.json",
|
"vault.json",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Find a unique filename that does not exist using four-letter random suffix.
|
||||||
|
pub fn find_unique_filename_using_random_suffix(parent_path: &Path, original_filename: &str) -> io::Result<String> {
|
||||||
|
let mut path = parent_path.join(original_filename);
|
||||||
|
let mut deduped_filename = original_filename.to_string();
|
||||||
|
|
||||||
|
if path.exists() {
|
||||||
|
const MAX_RETRIES: usize = 500;
|
||||||
|
let mut retries = 0;
|
||||||
|
|
||||||
|
while path.exists() {
|
||||||
|
if retries >= MAX_RETRIES {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "Exceeded maximum retries when deduplicating filename."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let suffix = ::random::random_string(4);
|
||||||
|
deduped_filename = format!("{}-{}", original_filename, suffix);
|
||||||
|
path.set_file_name(&deduped_filename);
|
||||||
|
retries += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(deduped_filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
use libc;
|
use libc;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
|
||||||
@ -46,16 +70,18 @@ fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs:
|
|||||||
.open(file_path)
|
.open(file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
fs::OpenOptions::new()
|
fs::OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create_new(true)
|
.create_new(true)
|
||||||
.open(file_path)
|
.open(file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
use libc;
|
use libc;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
@ -67,8 +93,9 @@ fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::Fi
|
|||||||
Ok(file)
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
fs::File::create(file_path)
|
fs::File::create(file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,28 +204,12 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
|
|||||||
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
|
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
|
||||||
/// true, a random suffix is appended to the filename.
|
/// true, a random suffix is appended to the filename.
|
||||||
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
|
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
|
||||||
|
if dedup {
|
||||||
|
filename = find_unique_filename_using_random_suffix(&self.path, &filename)?;
|
||||||
|
}
|
||||||
|
|
||||||
// path to keyfile
|
// path to keyfile
|
||||||
let mut keyfile_path = self.path.join(filename.as_str());
|
let keyfile_path = self.path.join(filename.as_str());
|
||||||
|
|
||||||
// check for duplicate filename and append random suffix
|
|
||||||
if dedup && keyfile_path.exists() {
|
|
||||||
const MAX_RETRIES: usize = 500;
|
|
||||||
let mut retries = 0;
|
|
||||||
let mut deduped_filename = filename.clone();
|
|
||||||
|
|
||||||
while keyfile_path.exists() {
|
|
||||||
if retries >= MAX_RETRIES {
|
|
||||||
return Err(Error::Custom(format!("Exceeded maximum retries when deduplicating account filename.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
let suffix = ::random::random_string(4);
|
|
||||||
deduped_filename = format!("{}-{}", filename, suffix);
|
|
||||||
keyfile_path.set_file_name(&deduped_filename);
|
|
||||||
retries += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = deduped_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update account filename
|
// update account filename
|
||||||
let original_account = account.clone();
|
let original_account = account.clone();
|
||||||
|
@ -21,7 +21,7 @@ use {json, SafeAccount, Error};
|
|||||||
use crypto::Keccak256;
|
use crypto::Keccak256;
|
||||||
use super::super::account::Crypto;
|
use super::super::account::Crypto;
|
||||||
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
|
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
|
||||||
use super::disk::{DiskDirectory, KeyFileManager};
|
use super::disk::{self, DiskDirectory, KeyFileManager};
|
||||||
|
|
||||||
/// Name of vault metadata file
|
/// Name of vault metadata file
|
||||||
pub const VAULT_FILE_NAME: &'static str = "vault.json";
|
pub const VAULT_FILE_NAME: &'static str = "vault.json";
|
||||||
@ -237,14 +237,13 @@ fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result
|
|||||||
let password_hash = key.password.keccak256();
|
let password_hash = key.password.keccak256();
|
||||||
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?;
|
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?;
|
||||||
|
|
||||||
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
|
let vault_file_path = vault_dir_path.as_ref().join(VAULT_FILE_NAME);
|
||||||
vault_file_path.push(VAULT_FILE_NAME);
|
let temp_vault_file_name = disk::find_unique_filename_using_random_suffix(vault_dir_path.as_ref(), &VAULT_TEMP_FILE_NAME)?;
|
||||||
let mut temp_vault_file_path: PathBuf = vault_dir_path.as_ref().into();
|
let temp_vault_file_path = vault_dir_path.as_ref().join(&temp_vault_file_name);
|
||||||
temp_vault_file_path.push(VAULT_TEMP_FILE_NAME);
|
|
||||||
|
|
||||||
// this method is used to rewrite existing vault file
|
// this method is used to rewrite existing vault file
|
||||||
// => write to temporary file first, then rename temporary file to vault file
|
// => write to temporary file first, then rename temporary file to vault file
|
||||||
let mut vault_file = fs::File::create(&temp_vault_file_path)?;
|
let mut vault_file = disk::create_new_file_with_permissions_to_owner(&temp_vault_file_path)?;
|
||||||
let vault_file_contents = json::VaultFile {
|
let vault_file_contents = json::VaultFile {
|
||||||
crypto: crypto.into(),
|
crypto: crypto.into(),
|
||||||
meta: Some(meta.to_owned()),
|
meta: Some(meta.to_owned()),
|
||||||
|
Loading…
Reference in New Issue
Block a user