mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-30 21:59:36 +02:00
chore: update documentation
This commit is contained in:
104 files changed
+4875
-222
No files matched your search
@@ -2,6 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Key derivation used to turn the user password into the key that encrypts a snapshot.
|
||||
//!
|
||||
//! Only available when the **kdf** Cargo feature is enabled, which is the case by default.
|
||||
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use std::path::Path;
|
||||
@@ -10,12 +14,21 @@ use std::path::Path;
|
||||
/// This is a current limitation of Stronghold.
|
||||
const HASH_LENGTH: usize = 32;
|
||||
|
||||
/// Password hashing functions that can be used as the key derivation function of
|
||||
/// [`Builder::new`](crate::Builder::new).
|
||||
pub struct KeyDerivation {}
|
||||
|
||||
impl KeyDerivation {
|
||||
/// Will create a key from [`password`] and a generated salt.
|
||||
/// Salt will be generated to file [`salt_path`] or taken from it
|
||||
/// if file already exists
|
||||
/// Hashes `password` with Argon2 using the salt stored in `salt_path`, returning the
|
||||
/// 32 bytes key used to encrypt a snapshot.
|
||||
///
|
||||
/// The salt is read from `salt_path` when that file already exists, otherwise a new
|
||||
/// random salt is generated and written to it.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when the salt file cannot be read or written, when its contents are not
|
||||
/// 32 bytes long, or when hashing the password fails.
|
||||
pub fn argon2(password: &str, salt_path: &Path) -> Vec<u8> {
|
||||
let mut salt = [0u8; HASH_LENGTH];
|
||||
create_or_get_salt(&mut salt, salt_path);
|
||||
|
||||
@@ -108,8 +108,13 @@ impl From<Slip10DeriveInputDto> for Slip10DeriveInput {
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of a key pair handled by the plugin procedures.
|
||||
///
|
||||
/// Deserialized from the strings `ed25519` and `x25519`, ignoring case.
|
||||
pub enum KeyType {
|
||||
/// The Ed25519 signature scheme.
|
||||
Ed25519,
|
||||
/// The X25519 key exchange scheme.
|
||||
X25519,
|
||||
}
|
||||
|
||||
@@ -423,11 +428,34 @@ enum PasswordHashFunctionKind {
|
||||
Custom(Box<PasswordHashFn>),
|
||||
}
|
||||
|
||||
/// Builder for the stronghold plugin.
|
||||
///
|
||||
/// It defines how the password sent by the frontend is hashed into the key that
|
||||
/// encrypts the snapshot file.
|
||||
pub struct Builder {
|
||||
password_hash_function: PasswordHashFunctionKind,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Initializes [`Self`] with a custom password hash function.
|
||||
///
|
||||
/// The function is called with the password sent by the frontend and must return the
|
||||
/// key used to encrypt the snapshot, which must be 32 bytes long.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// fn init<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::Builder<R> {
|
||||
/// builder.plugin(
|
||||
/// tauri_plugin_stronghold::Builder::new(|_password| {
|
||||
/// // hash the password with a secure algorithm such as argon2 or blake2b
|
||||
/// // and return the resulting 32 bytes hash
|
||||
/// unimplemented!()
|
||||
/// })
|
||||
/// .build(),
|
||||
/// )
|
||||
/// }
|
||||
/// ```
|
||||
pub fn new<F: Fn(&str) -> Vec<u8> + Send + Sync + 'static>(password_hash_function: F) -> Self {
|
||||
Self {
|
||||
password_hash_function: PasswordHashFunctionKind::Custom(Box::new(
|
||||
@@ -442,16 +470,19 @@ impl Builder {
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri::Manager;
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
///
|
||||
/// fn init<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::Builder<R> {
|
||||
/// builder.setup(|app| {
|
||||
/// let salt_path = app
|
||||
/// .path()
|
||||
/// .app_local_data_dir()
|
||||
/// .expect("could not resolve app local data path")
|
||||
/// .join("salt.txt");
|
||||
/// app.handle().plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
|
||||
/// app.handle()
|
||||
/// .plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "kdf")]
|
||||
pub fn with_argon2(salt_path: &std::path::Path) -> Self {
|
||||
@@ -460,6 +491,8 @@ impl Builder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the plugin, registering the password hash function and the commands used
|
||||
/// by the JavaScript guest bindings.
|
||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||
let password_hash_function = self.password_hash_function;
|
||||
|
||||
|
||||
@@ -2,22 +2,35 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Types to load, modify and persist an [IOTA Stronghold](https://github.com/iotaledger/stronghold.rs)
|
||||
//! snapshot file.
|
||||
|
||||
use std::{convert::TryFrom, ops::Deref, path::Path};
|
||||
|
||||
use iota_stronghold::{KeyProvider, SnapshotPath};
|
||||
use serde::{Serialize, Serializer};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
/// Alias for a [`std::result::Result`] with the error type [`Error`].
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Errors returned by the stronghold plugin.
|
||||
///
|
||||
/// Serialized as the error message string when returned to the frontend.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// No stronghold was initialized for the given snapshot path.
|
||||
#[error("stronghold not initialized")]
|
||||
StrongholdNotInitialized,
|
||||
/// An error from the underlying Stronghold client, e.g. when loading a snapshot
|
||||
/// with the wrong password or when addressing a client that does not exist.
|
||||
#[error(transparent)]
|
||||
Stronghold(#[from] iota_stronghold::ClientError),
|
||||
/// An error from the Stronghold secure memory implementation, e.g. when the
|
||||
/// password hash is not a key size Stronghold accepts.
|
||||
#[error(transparent)]
|
||||
Memory(#[from] iota_stronghold::MemoryError),
|
||||
/// A Stronghold procedure (key generation, key derivation, signing, ...) failed.
|
||||
#[error(transparent)]
|
||||
Procedure(#[from] iota_stronghold::procedures::ProcedureError),
|
||||
}
|
||||
@@ -31,6 +44,10 @@ impl Serialize for Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// A Stronghold instance bound to a snapshot file and to the key it is encrypted with.
|
||||
///
|
||||
/// Dereferences to the underlying [`iota_stronghold::Stronghold`], so all of its client
|
||||
/// and vault operations are available on this type.
|
||||
pub struct Stronghold {
|
||||
inner: iota_stronghold::Stronghold,
|
||||
path: SnapshotPath,
|
||||
@@ -38,6 +55,18 @@ pub struct Stronghold {
|
||||
}
|
||||
|
||||
impl Stronghold {
|
||||
/// Creates a Stronghold instance for the snapshot file at `path`, encrypted with
|
||||
/// `password` as the key.
|
||||
///
|
||||
/// When the file already exists its snapshot is loaded, which requires `password` to
|
||||
/// be the key it was encrypted with. Otherwise an empty instance is created and
|
||||
/// nothing is written to disk until [`Self::save`] is called.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Error::Memory`] when `password` is not a key size Stronghold accepts
|
||||
/// (it must be 32 bytes long) and [`Error::Stronghold`] when an existing snapshot
|
||||
/// cannot be loaded with it.
|
||||
pub fn new<P: AsRef<Path>>(path: P, password: Vec<u8>) -> Result<Self> {
|
||||
let path = SnapshotPath::from_path(path);
|
||||
let stronghold = iota_stronghold::Stronghold::default();
|
||||
@@ -52,12 +81,15 @@ impl Stronghold {
|
||||
})
|
||||
}
|
||||
|
||||
/// Writes the state of all clients to the snapshot file, encrypted with the key
|
||||
/// this instance was created with.
|
||||
pub fn save(&self) -> Result<()> {
|
||||
self.inner
|
||||
.commit_with_keyprovider(&self.path, &self.keyprovider)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying [`iota_stronghold::Stronghold`] instance.
|
||||
pub fn inner(&self) -> &iota_stronghold::Stronghold {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user