mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Key storage (file)
This commit is contained in:
160
src/system/keys/filestorage.rs
Normal file
160
src/system/keys/filestorage.rs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
//! ## FileStorage
|
||||||
|
//!
|
||||||
|
//! `filestorage` provides an implementation of the `KeyStorage` trait using a file
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com
|
||||||
|
*
|
||||||
|
* This file is part of "TermSCP"
|
||||||
|
*
|
||||||
|
* TermSCP is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* TermSCP is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with TermSCP. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::{KeyStorage, KeyStorageError};
|
||||||
|
|
||||||
|
use std::fs::{OpenOptions, Permissions};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
/// ## FileStorage
|
||||||
|
///
|
||||||
|
/// File storage is an implementation o the `KeyStorage` which uses a file to store the key
|
||||||
|
pub struct FileStorage {
|
||||||
|
dir_path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileStorage {
|
||||||
|
/// ### new
|
||||||
|
///
|
||||||
|
/// Instantiates a new `FileStorage`
|
||||||
|
pub fn new(dir_path: &Path) -> Self {
|
||||||
|
FileStorage {
|
||||||
|
dir_path: PathBuf::from(dir_path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### make_file_path
|
||||||
|
///
|
||||||
|
/// Make file path for key file from `dir_path` and the application id
|
||||||
|
fn make_file_path(&self, storage_id: &str) -> PathBuf {
|
||||||
|
let mut p: PathBuf = self.dir_path.clone();
|
||||||
|
let file_name = format!(".{}.key", storage_id);
|
||||||
|
p.push(file_name);
|
||||||
|
p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyStorage for FileStorage {
|
||||||
|
/// ### get_key
|
||||||
|
///
|
||||||
|
/// Retrieve key from the key storage.
|
||||||
|
/// The key might be acccess through an identifier, which identifies
|
||||||
|
/// the key in the storage
|
||||||
|
fn get_key(&self, storage_id: &str) -> Result<String, KeyStorageError> {
|
||||||
|
let key_file: PathBuf = self.make_file_path(storage_id);
|
||||||
|
// Check if file exists
|
||||||
|
if !key_file.exists() {
|
||||||
|
return Err(KeyStorageError::NoSuchKey);
|
||||||
|
}
|
||||||
|
// Read key from file
|
||||||
|
match OpenOptions::new().read(true).open(key_file.as_path()) {
|
||||||
|
Ok(mut file) => {
|
||||||
|
let mut key: String = String::new();
|
||||||
|
match file.read_to_string(&mut key) {
|
||||||
|
Ok(_) => Ok(key),
|
||||||
|
Err(_) => Err(KeyStorageError::Io),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Err(KeyStorageError::Io),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### set_key
|
||||||
|
///
|
||||||
|
/// Set the key into the key storage
|
||||||
|
fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError> {
|
||||||
|
let key_file: PathBuf = self.make_file_path(storage_id);
|
||||||
|
// Write key
|
||||||
|
match OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(key_file.as_path())
|
||||||
|
{
|
||||||
|
Ok(mut file) => {
|
||||||
|
// Write key to file
|
||||||
|
if let Err(_) = file.write_all(key.as_bytes()) {
|
||||||
|
return Err(KeyStorageError::Io);
|
||||||
|
}
|
||||||
|
// Set file to readonly
|
||||||
|
let mut permissions: Permissions = file.metadata().unwrap().permissions();
|
||||||
|
permissions.set_readonly(true);
|
||||||
|
let _ = file.set_permissions(permissions);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(KeyStorageError::Io),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// is_supported
|
||||||
|
///
|
||||||
|
/// Returns whether the key storage is supported on the host system
|
||||||
|
fn is_supported(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_keys_filestorage_make_dir() {
|
||||||
|
let storage: FileStorage = FileStorage::new(&Path::new("/tmp/"));
|
||||||
|
assert_eq!(
|
||||||
|
storage.make_file_path("bookmarks").as_path(),
|
||||||
|
Path::new("/tmp/.bookmarks.key")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_keys_filestorage_ok() {
|
||||||
|
let key_dir: tempfile::TempDir =
|
||||||
|
tempfile::TempDir::new().expect("Could not create tempdir");
|
||||||
|
let storage: FileStorage = FileStorage::new(key_dir.path());
|
||||||
|
let app_name: &str = "termscp";
|
||||||
|
let secret: &str = "Th15-15/My-Супер-Секрет";
|
||||||
|
// Secret should not exist
|
||||||
|
assert_eq!(
|
||||||
|
storage.get_key(app_name).err().unwrap(),
|
||||||
|
KeyStorageError::NoSuchKey
|
||||||
|
);
|
||||||
|
// Write secret
|
||||||
|
assert!(storage.set_key(app_name, secret).is_ok());
|
||||||
|
// Get secret
|
||||||
|
assert_eq!(storage.get_key(app_name).ok().unwrap().as_str(), secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_keys_filestorage_err() {
|
||||||
|
let bad_dir: &Path = Path::new("/piro/poro/pero/");
|
||||||
|
let storage: FileStorage = FileStorage::new(bad_dir);
|
||||||
|
let app_name: &str = "termscp";
|
||||||
|
let secret: &str = "Th15-15/My-Супер-Секрет";
|
||||||
|
assert!(storage.set_key(app_name, secret).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/system/keys/mod.rs
Normal file
72
src/system/keys/mod.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
//! ## KeyStorage
|
||||||
|
//!
|
||||||
|
//! `keystorage` provides the trait to manipulate to a KeyStorage
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com
|
||||||
|
*
|
||||||
|
* This file is part of "TermSCP"
|
||||||
|
*
|
||||||
|
* TermSCP is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* TermSCP is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with TermSCP. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Storages
|
||||||
|
pub mod filestorage;
|
||||||
|
|
||||||
|
/// ## KeyStorageError
|
||||||
|
///
|
||||||
|
/// defines the error type for the `KeyStorage`
|
||||||
|
#[derive(PartialEq, std::fmt::Debug)]
|
||||||
|
pub enum KeyStorageError {
|
||||||
|
BadKey,
|
||||||
|
Io,
|
||||||
|
NoSuchKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for KeyStorageError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let err: String = String::from(match &self {
|
||||||
|
KeyStorageError::BadKey => "Bad key syntax",
|
||||||
|
KeyStorageError::Io => "Input/Output error",
|
||||||
|
KeyStorageError::NoSuchKey => "No such key",
|
||||||
|
});
|
||||||
|
write!(f, "{}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## KeyStorage
|
||||||
|
///
|
||||||
|
/// this traits provides the methods to communicate and interact with the key storage.
|
||||||
|
pub trait KeyStorage {
|
||||||
|
|
||||||
|
/// ### get_key
|
||||||
|
///
|
||||||
|
/// Retrieve key from the key storage.
|
||||||
|
/// The key might be acccess through an identifier, which identifies
|
||||||
|
/// the key in the storage
|
||||||
|
fn get_key(&self, storage_id: &str) -> Result<String, KeyStorageError>;
|
||||||
|
|
||||||
|
/// ### set_key
|
||||||
|
///
|
||||||
|
/// Set the key into the key storage
|
||||||
|
fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError>;
|
||||||
|
|
||||||
|
/// is_supported
|
||||||
|
///
|
||||||
|
/// Returns whether the key storage is supported on the host system
|
||||||
|
fn is_supported(&self) -> bool;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,4 +27,5 @@
|
|||||||
pub mod bookmarks_client;
|
pub mod bookmarks_client;
|
||||||
pub mod config_client;
|
pub mod config_client;
|
||||||
pub mod environment;
|
pub mod environment;
|
||||||
|
pub(crate) mod keys;
|
||||||
pub mod sshkey_storage;
|
pub mod sshkey_storage;
|
||||||
|
|||||||
Reference in New Issue
Block a user