Skip to content

Commit

Permalink
HexTokenTransformer (#50)
Browse files Browse the repository at this point in the history
* HexTokenTransformer
  • Loading branch information
evgeniy-r committed Apr 23, 2021
1 parent ad75245 commit 6692afb
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
### 🚀 Added
- `hex_token` rule (`HexTokenTransformer`) [#50](https://github.com/datanymizer/datanymizer/pull/50)
([@evgeniy-r](https://github.com/evgeniy-r))
- Configuration options for transformation SQL conditions [#45](https://github.com/datanymizer/datanymizer/pull/45)
([@evgeniy-r](https://github.com/evgeniy-r))
- Configuration options for dump query conditions and limit [#47](https://github.com/datanymizer/datanymizer/pull/47)
Expand Down
2 changes: 1 addition & 1 deletion datanymizer_dumper/src/postgres/dumper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl Dumper for PgDumper {

// In transaction
let mut tr = connection.transaction()?;
for (ind, (table, _weidth)) in tables.iter().enumerate() {
for (ind, (table, _weight)) in tables.iter().enumerate() {
self.debug(format!(
"[{} / {}] Prepare to dump table: {}",
ind + 1,
Expand Down
4 changes: 4 additions & 0 deletions datanymizer_engine/src/transformers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub use number::RandomNumberTransformer;
mod datetime;
pub use datetime::RandomDateTimeTransformer;

mod token;
pub use token::HexTokenTransformer;

mod fk;
pub use fk::sql_value::AsSqlValue;
pub use fk::*;
Expand Down Expand Up @@ -75,6 +78,7 @@ define_transformers_enum![
("random_num", RandomNum, RandomNumberTransformer),
("password", Password, PasswordTransformer),
("datetime", DateTime, RandomDateTimeTransformer),
("hex_token", HexToken, HexTokenTransformer),

("city", City, CityTransformer),
("city_prefix", CityPrefix, CityPrefixTransformer),
Expand Down
107 changes: 107 additions & 0 deletions datanymizer_engine/src/transformers/token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use crate::transformer::{TransformContext, TransformResult, TransformResultHelper, Transformer};
use rand::distributions::{Distribution, Uniform};
use serde::{Deserialize, Serialize};

const DEFAULT_LENGTH: usize = 32;
const CHARS: [char; 16] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
];

/// Transformer generates random hex tokens.
/// You can set the token length (default is 32)
///
/// # Examples
///
/// With defaults:
/// ```yaml
/// #...
/// rules:
/// field_name:
/// hex_token: {}
/// ```
///
/// with custom length:
///
/// ```yaml
/// #...
/// rules:
/// field_name:
/// hex_token:
/// len: 128
///
/// ```
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Debug)]
#[serde(default)]
pub struct HexTokenTransformer {
/// Length
pub len: usize,
}

impl Default for HexTokenTransformer {
fn default() -> Self {
Self {
len: DEFAULT_LENGTH,
}
}
}

impl Transformer for HexTokenTransformer {
fn transform(
&self,
_field_name: &str,
_field_value: &str,
_ctx: &Option<TransformContext>,
) -> TransformResult {
let rng = rand::thread_rng();
let distribution = Uniform::<usize>::from(0..16);
TransformResult::present(
distribution
.sample_iter(rng)
.take(self.len)
.map(|i| CHARS[i])
.collect::<String>(),
)
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::Transformers;

fn transformed_value(cfg: &str) -> String {
let transformer: HexTokenTransformer = serde_yaml::from_str(cfg).unwrap();
transformer.transform("token", "", &None).unwrap().unwrap()
}

#[test]
fn deserialize() {
let config = "hex_token: {}";
let transformer: Transformers = serde_yaml::from_str(config).unwrap();

assert_eq!(
transformer,
Transformers::HexToken(HexTokenTransformer::default())
);
}

#[test]
fn default() {
let value = transformed_value("{}");

assert_eq!(value.len(), DEFAULT_LENGTH);
for c in value.chars() {
assert!(CHARS.contains(&c));
}
}

#[test]
fn custom_length() {
let value = transformed_value("len: 50");

assert_eq!(value.len(), 50);
for c in value.chars() {
assert!(CHARS.contains(&c));
}
}
}

0 comments on commit 6692afb

Please sign in to comment.