Crates.io | sosecrets-rs |
lib.rs | sosecrets-rs |
version | 0.2.6 |
source | src |
created_at | 2024-01-27 18:45:28.422558 |
updated_at | 2024-07-18 17:36:24.746999 |
description | A simple `Secret` wrapper type that reveals the secret at most `MEC: typenum::Unsigned` times with compile time guarantees. |
homepage | |
repository | https://github.com/jymchng/sosecrets-rs |
max_upload_size | |
id | 1116902 |
size | 65,776 |
Secrets Management crate with
It is similar to the secrecy
crate but with type level and compile-time guarantees that the Secret<T, MEC, EC>
value is not ’exposed’ more than MEC
number of times and is only exposed under a well-defined lexical scope.
It makes use of the typenum
crate for all its compile-time guarantees.
Secret
values can be cloned if the underlying type, T
, implements the CloneableSecret
trait.Secret
values if the underlying type, T
, implements the DebugSecret
trait.use sosecrets_rs::{
prelude::*,
traits::ExposeSecret,
};
use typenum::U2;
// Define a secret with a maximum exposure count of 2
let secret = Secret::<_, U2>::new("my_secret_value".to_string());
// Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
let (next_secret, exposed_value) = secret.expose_secret(|exposed_secret| {
// `exposed_secret` is only 'available' from the next line -------
assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); // ^
// Perform operations with the exposed value |
// ... v
// to this line... -----------------------------------------------
});
// Expose the secret again and perform some operations with the exposed value; secret has been exposed twice: `EC` = 2, `MEC` = 2;
let (next_secret, exposed_value) = next_secret.expose_secret(|exposed_secret| {
assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
// Perform operations with the exposed value
// ...
});
Try to expose the secret again and perform some operations with the exposed value; secret has been exposed the third time: EC
= 3, MEC
= 2;
The following is uncompilable.
let (next_secret, exposed_value) = next_secret.expose_secret(|exposed_secret| {
assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
// Perform operations with the exposed value
// ...
});
It is impossible to return the value (e.g. exposed_secret
in the example above) passed into the closure, out of the closure.
The following is uncompilable.
let (next_secret, exposed_value) = next_secret.expose_secret(|exposed_secret| {
assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
// Perform operations with the exposed value
// ...
exposed_secret // impossible to return `exposed_secret` here
});
Note: If T
is Copy
, then the above will compile successfully and expose_secret(...)
method will return a copy of exposed T
.
use sosecrets_rs::{
prelude::*,
// Note, for runtime checks, you have to use the `RTExposeSecret` trait instead.
runtime::traits::RTExposeSecret,
};
use typenum::U2;
// Define a secret with a maximum exposure count of 2
let secret = RTSecret::<_, U2>::new("my_secret_value".to_string());
// Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
let exposed_value = secret.expose_secret(|exposed_secret| {
// `exposed_secret` is only 'available' from the next line -------
assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); // ^
// Perform operations with the exposed value |
// ... v
// to this line... -----------------------------------------------
});
// Expose the secret again and perform some operations with the exposed value; secret has been exposed twice: `EC` = 2, `MEC` = 2;
let exposed_value = secret.expose_secret(|exposed_secret| {
assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
// Perform operations with the exposed value
// ...
});
Try to expose the secret again and perform some operations with the exposed value; secret has been exposed the third time: EC
= 3, MEC
= 2;
.expose_secret(...)
method will then panic
with the message:
`RTSecret\` has already been exposed for 2 times, the maximum number it is allowed to be exposed for is 2 times."
# use sosecrets_rs::{
# prelude::*,
# // Note, for runtime checks, you have to use the `RTExposeSecret` trait instead.
# runtime::traits::RTExposeSecret,
# };
# use typenum::U2;
#
# // Define a secret with a maximum exposure count of 2
# let secret = RTSecret::<_, U2>::new("my_secret_value".to_string());
#
# // Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
# let exposed_value = secret.expose_secret(|exposed_secret| {
# // `exposed_secret` is only 'available' from the next line -------
# assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); // ^
# // Perform operations with the exposed value |
# // ... v
# // to this line... -----------------------------------------------
# });
#
# // Expose the secret again and perform some operations with the exposed value; secret has been exposed twice: `EC` = 2, `MEC` = 2;
# let exposed_value = secret.expose_secret(|exposed_secret| {
# assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
# // Perform operations with the exposed value
# // ...
# });
let exposed_value = secret.expose_secret(|exposed_secret| {
assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
// Perform operations with the exposed value
// ...
});
Note: You can use the non-panicking variant of the method expose_secret(...)
which is named as try_expose_secret(...)
.
try_expose_secret(...)
returns a Result::Err
if the exposure count is larger than what is maximally allowed.
It is impossible to return the value (e.g. exposed_secret
in the example above) passed into the closure, out of the closure, unless T
is Copy
. The following is uncompilable.
let exposed_value = secret.expose_secret(|exposed_secret| {
assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
// Perform operations with the exposed value
// ...
exposed_secret // impossible to return `exposed_secret` here
});
secrecy
crateYou can use the SecrecySecret
type as a substitute for the Secret<T>
in secrecy
crate.
use sosecrets_rs::{
prelude::*,
// Note, for runtime checks, you have to use the `RTExposeSecret` trait instead.
runtime::traits::RTExposeSecret,
};
// Define a secret with NO maximum exposure count
let secret = SecrecySecret::new("my_secret_value".to_string());
// Expose the secret and perform some operations with the exposed value as many times as you like.
for _ in 0..=1_000_000 {
let exposed_value = secret.expose_secret(|exposed_secret| {
// `exposed_secret` is only 'available' from the next line -------
assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); // ^
// Perform operations with the exposed value |
// ... v
// to this line... -----------------------------------------------
});
}
See more in the examples directory.
To enable features, you can include them in your Cargo.toml
:
[dependencies]
sosecrets-rs = { version = "x.x.x", features = ["zeroize", "cloneable-secret", "debug-secret"] }
prelude
: Module for easily importing common items.runtime
: Module for RTSecret<T>
, SecrecySecret
and RTExposeSecret
.ExposeSecret
: Trait for safely exposing secrets with a limited exposure count at compile time.RTExposeSecret
: Trait for safely exposing secrets with a limited exposure count at runtime time.CloneableSecret
: Trait for cloneable secrets.DebugSecret
: Trait for debuggable secrets.For example, if the feature "cloneable-secret"
is enabled, then you can 'clone' the secret.
Example:
#[cfg(all(feature = "cloneable-secret", feature = "alloc"))]
// Need to enable feature = "alloc" because `String` requires feature = "alloc".
{
use sosecrets_rs::{
prelude::*,
traits::{CloneableSecret, ExposeSecret},
};
use typenum::U2;
// Define a secret with a maximum exposure count of 2
let secret = Secret::<_, U2>::new("my_secret_value".to_string());
// Clone the secret
let secret2 = secret.clone();
// Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
let (next_secret, exposed_value) = secret.expose_secret(move |exposed_secret| {
// `exposed_secret` is only 'available' from the next line --------------------------^
let (next_secret2, exposed_value2) = secret2.expose_secret(|exposed_secret2| { // |
assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); // |
assert_eq!(&*exposed_secret2.as_str(), "my_secret_value"); // |
assert_eq!(&*exposed_secret2.as_str(), &*exposed_secret.as_str()); // |
// Perform operations with the exposed value |
// ... |
// to this line... ---------------------------------------------------------------v
});
});
}
The crate currently requires Rust 1.70. I have no intent on increasing the compiler version requirement of this crate beyond this. However, this is only guaranteed within a given minor version number.
Run
bash scripts/tests-all-features.sh
Licensed under
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the MIT license, without any additional terms or conditions.
ExposeSecret
[Rust Forum, Rust Playground] trait and its trait method, expose_secret(...)
[Rust Forum, Rust Playground].invariant
lifetime.impl_choose_int!()
on Rust Forum. The macro helps to implement the trait ChooseMinimallyRepresentableUInt
for all type-level unsigned integers provided by the typenum
crate that are representable from 1 bit to 64 bits at the type level.