Skip to content

Commit

Permalink
#13 is completed, added new_with, added alloc feature, make crate no_…
Browse files Browse the repository at this point in the history
…std compatible
  • Loading branch information
jymchng committed Nov 27, 2023
1 parent ffae227 commit 10ab189
Show file tree
Hide file tree
Showing 19 changed files with 351 additions and 125 deletions.
24 changes: 0 additions & 24 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,6 @@ on:
- master

jobs:
clippy_solo:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Run tests
run: cargo clippy --all-features && cargo clippy

tests_solo:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Run tests
run: cargo test --all-features --no-fail-fast && cargo test

msrv_solo:
runs-on: ubuntu-latest
steps:
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ trybuild = "1.0.85"

[features]
cloneable-secret = []
alloc = ["zeroize/alloc"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--generate-link-to-definition", "--cfg", "docsrs"]
2 changes: 1 addition & 1 deletion scripts/check-all-features.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# Array of feature names
features=("cloneable-secret")
features=("cloneable-secret", "alloc")

# Calculate the total number of features
total_features=${#features[@]}
Expand Down
2 changes: 1 addition & 1 deletion scripts/clippy-all-features.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# Array of feature names
features=("cloneable-secret")
features=("cloneable-secret", "alloc")

# Calculate the total number of features
total_features=${#features[@]}
Expand Down
2 changes: 1 addition & 1 deletion scripts/tests-all-features.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# Array of feature names
features=("cloneable-secret")
features=("cloneable-secret", "alloc")

# Calculate the total number of features
total_features=${#features[@]}
Expand Down
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

#[cfg(feature = "alloc")]
extern crate alloc;

mod macros;
mod secret;

Expand Down
26 changes: 8 additions & 18 deletions src/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::{
ops::{Add, Deref, Drop},
};

use crate::traits::{ExposeSecret, SecretIntoInner};
use crate::traits::ExposeSecret;
use typenum::{IsLessOrEqual, Sum, True, Unsigned, U0, U1};
use zeroize::Zeroize;

Expand All @@ -29,6 +29,13 @@ where
pub const fn new(value: T) -> Self {
Self(ManuallyDrop::new(value), PhantomData)
}

pub fn new_with<ClosureType>(closure: ClosureType) -> Self
where
ClosureType: FnOnce() -> T,
{
Self(ManuallyDrop::new(closure()), PhantomData)
}
}

impl<
Expand Down Expand Up @@ -96,23 +103,6 @@ where
}
}

impl<T, MEC, EC> SecretIntoInner<T, MEC, EC> for Secret<T, MEC, EC>
where
T: Zeroize,
MEC: Unsigned,
EC: Unsigned + Add<U1> + IsLessOrEqual<MEC, Output = True>,
{
#[inline(always)]
fn into_inner(mut self) -> T {
// SAFETY: Since compile error prevents constructing a `Secret` with `EC` > `MEC`,
// `zeroize()` is only called when `Secret` is maximally exposed
// and it is not possible to call `expose_secret(...)`
// when `Secret` is maximally exposed to access **private** `self.0` field,
// therefore, this is safe.
unsafe { ManuallyDrop::take(&mut self.0) }
}
}

#[cfg(feature = "cloneable-secret")]
impl<T, MEC, EC> Clone for Secret<T, MEC, EC>
where
Expand Down
18 changes: 8 additions & 10 deletions src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use core::ops::Add;
use typenum::{IsLessOrEqual, Sum, True, Unsigned, U1};
use zeroize::Zeroize;

pub trait ExposeSecret<'max, T, MEC: Unsigned, EC: Unsigned>: Sized {
type Exposed<'brand>
Expand All @@ -19,15 +18,6 @@ pub trait ExposeSecret<'max, T, MEC: Unsigned, EC: Unsigned>: Sized {
Sum<EC, U1>: Unsigned + Add<U1> + IsLessOrEqual<MEC, Output = True>;
}

pub trait SecretIntoInner<T, MEC, EC>: Sized
where
T: Zeroize,
MEC: Unsigned,
EC: Unsigned + Add<U1> + IsLessOrEqual<MEC, Output = True>,
{
fn into_inner(self) -> T;
}

#[cfg(feature = "cloneable-secret")]
pub use self::cloneable_secret::CloneableSecret;

Expand All @@ -40,8 +30,16 @@ mod cloneable_secret {
pub trait CloneableSecret: Clone + Zeroize {}

impl<T: Clone + Zeroize, const N: usize> CloneableSecret for [T; N] {}

#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};

#[cfg(feature = "alloc")]
impl CloneableSecret for String {}

#[cfg(feature = "alloc")]
impl<T: Clone + Zeroize> CloneableSecret for Vec<T> {}

crate::impl_cloneable_secret_for_numbers!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
);
Expand Down
153 changes: 148 additions & 5 deletions tests/extern_bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ fn test_expose_secret_extern() {
}

#[cfg(feature = "cloneable-secret")]
#[cfg(feature = "alloc")]
#[test]
fn test_secret_with_vec_and_clone() {
let secret_vec = vec!["MySecret".to_string()];
Expand Down Expand Up @@ -152,11 +153,153 @@ fn test_clone_1() {
}

#[test]
fn test_destruct_secret_1() {
use sosecrets_rs::traits::SecretIntoInner;
fn test_with_new() {
use std::env;
use zeroize::Zeroize;

let new_secret: Secret<_, U2> = Secret::new(69);
#[derive(Clone, Debug, PartialEq)]
struct SecretString(String);

impl Zeroize for SecretString {
fn zeroize(&mut self) {
self.0.zeroize();
}
}

let new_secret: Secret<SecretString, U5> = Secret::new_with(|| {
SecretString(
env::var("CARGO_TARGET_DIR")
.unwrap_or("MySecret".to_string())
.to_string(),
)
});

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);

let got_out_inner_value = new_secret.into_inner();
assert_eq!(got_out_inner_value, 69);
let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);
}

#[cfg(feature = "cloneable-secret")]
#[test]
fn test_with_new_cloneable_secret() {
use std::env;
use zeroize::Zeroize;

#[derive(Clone, Debug, PartialEq)]
struct SecretString(String);

impl Zeroize for SecretString {
fn zeroize(&mut self) {
self.0.zeroize();
}
}

let new_secret: Secret<SecretString, U5> = Secret::new_with(|| {
SecretString(
env::var("CARGO_TARGET_DIR")
.unwrap_or("MySecret".to_string())
.to_string(),
)
});

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);

let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);
}

#[cfg(feature = "alloc")]
#[test]
fn test_with_new_alloc() {
use std::env;
use zeroize::Zeroize;

#[derive(Clone, Debug, PartialEq)]
struct SecretString(String);

impl Zeroize for SecretString {
fn zeroize(&mut self) {
self.0.zeroize();
}
}

let new_secret: Secret<SecretString, U5> = Secret::new_with(|| {
SecretString(
env::var("CARGO_TARGET_DIR")
.unwrap_or("MySecret".to_string())
.to_string(),
)
});

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);

let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(
returned_value.inner,
SecretString(env::var("CARGO_TARGET_DIR").unwrap_or("MySecret".to_string()))
);
}
17 changes: 14 additions & 3 deletions tests/trybuild_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,26 @@ fn test_compile_fails() {
t.compile_fail("trybuild_tests/test_compile_fail_two.rs");
t.compile_fail("trybuild_tests/test_compile_fail_three.rs");

#[cfg(feature = "cloneable-secret")]
#[cfg(all(feature = "cloneable-secret", not(feature = "alloc")))]
t.compile_fail("trybuild_tests/test_compile_fail_four.rs");

#[cfg(feature = "cloneable-secret")]
#[cfg(all(feature = "cloneable-secret", not(feature = "alloc")))]
t.compile_fail("trybuild_tests/test_compile_fail_five.rs");

#[cfg(feature = "cloneable-secret")]
#[cfg(all(feature = "alloc", feature = "cloneable-secret"))]
t.compile_fail("trybuild_tests/test_compile_fail_six.rs");

// std env + alloc + no clone, no clone should error
#[cfg(all(feature = "alloc", not(feature = "cloneable-secret")))]
t.compile_fail("trybuild_tests/test_compile_fail_seven.rs");

// no_std env + alloc + extern crate alloc::vec::Vec in main()
#[cfg(all(feature = "alloc", not(feature = "cloneable-secret")))]
t.compile_fail("trybuild_tests/test_compile_fail_eight.rs");

#[cfg(feature = "cloneable-secret")]
t.pass("trybuild_tests/test_compile_pass_one.rs");

// no_std env + no alloc + no cloneable-secret should work
t.pass("trybuild_tests/test_compile_pass_two.rs");
}
37 changes: 37 additions & 0 deletions trybuild_tests/test_compile_fail_eight.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#![no_std]

mod common;

fn main() {
use common::UseSecret;
use sosecrets_rs::prelude::*;
use sosecrets_rs::traits::ExposeSecret;
use typenum::consts::U2;

#[cfg(feature = "alloc")]
extern crate std;

#[cfg(feature = "alloc")]
use std::{borrow::ToOwned, vec};

// try similar with vec
let secret_vec = vec!["MySecret".to_owned()];
let new_secret: Secret<_, U2, _> = Secret::new(secret_vec);
let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(returned_value.inner, vec!["MySecret".to_owned()]);

let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(returned_value.inner, vec!["MySecret".to_owned()]);

let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
let returned_value = UseSecret::new((*exposed_secret).to_owned());
returned_value
});
assert_eq!(returned_value.inner, vec!["MySecret".to_owned()]);
}
Loading

0 comments on commit 10ab189

Please sign in to comment.