Data-Censor

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

SYNOPSIS
        # OO way, letting you specify your own list of sensitive-looking fields, and
        # what they should be replaced by (all options here are optional)
        my $censor = Data::Censor->new(
            # Specify which fields to censor:
            sensitive_fields => [ qw(card_number password) ],

            # Specify text to replace their values with:
            replacement => '(Sensitive data hidden)',

            # Or specify callbacks for each field name which return the "censored"
            # value - in this case, masking a card number (PAN) to show only the
            # last four digits:
            replacement_callbacks => {
                card_number => sub {
                    my $pan = shift;
                    return "x" x (length($pan) - 4) . substr($pan, -4, 4);
                },
            },
        );
    
        # Censor the data in-place (changes the data structure, returns the number
        # of keys censored)
        my $censor_count = $censor->censor(\%data);

README  view on Meta::CPAN


new (CONSTRUCTOR)
    Accepts the following arguments:

    sensitive_fields
        Either an arrayref of sensitive fields, checked for equality, or a
        regex to test against each key to see if it's considered sensitive.

    replacement
        The string to replace each value with. Any censoring callback
        provided in `replacement_callbacks' which matches this key will take
        precedence over this straightforward value.

    replacement_callbacks
        A hashref of key => sub {...}, where each key is a column name to
        match, and the coderef takes the uncensored value and returns the
        censored value, letting you for instance mask a card number but
        leave the last 4 digits visible.

        If you provide both `replacement' and `replacement_callbacks', any
        callback defined which matches the key being considered takes
        precedence. =back

METHODS
  censor
        Given a data structure (hashref), clones it and returns the cloned
        version after censoring potentially sensitive data within.

  clone_and_censor
        Clones the provided hashref (using Clone - will die if not

lib/Data/Censor.pm  view on Meta::CPAN


    # OO way, letting you specify your own list of sensitive-looking fields, and
    # what they should be replaced by (all options here are optional)
    my $censor = Data::Censor->new(
        # Specify which fields to censor:
        sensitive_fields => [ qw(card_number password) ],

        # Specify text to replace their values with:
        replacement => '(Sensitive data hidden)',

        # Or specify callbacks for each field name which return the "censored"
        # value - in this case, masking a card number (PAN) to show only the
        # last four digits:
        replacement_callbacks => {
            card_number => sub {
                my $pan = shift;
                return "x" x (length($pan) - 4) . substr($pan, -4, 4);
            },
        },
    );
    
    # Censor the data in-place (changes the data structure, returns the number
    # of keys censored)
    my $censor_count = $censor->censor(\%data);

lib/Data/Censor.pm  view on Meta::CPAN

=over

=item sensitive_fields

Either an arrayref of sensitive fields, checked for equality, or a regex to test
against each key to see if it's considered sensitive.

=item replacement

The string to replace each value with.  Any censoring callback provided in
C<replacement_callbacks> which matches this key will take precedence over this
straightforward value.

=item replacement_callbacks

A hashref of key => sub {...}, where each key is a column name to match, and the
coderef takes the uncensored value and returns the censored value, letting you
for instance mask a card number but leave the last 4 digits visible.

If you provide both C<replacement> and C<replacement_callbacks>, any callback
defined which matches the key being considered takes precedence.

=back

=cut

sub new {
    my $class = shift;
    my %args  = @_;

lib/Data/Censor.pm  view on Meta::CPAN

    } else {
        $self->{is_sensitive_field} = {
            map { $_ => 1 } qw(
              pass         password     old_password   secret
              private_key  cardnum      card_number    pan
              cvv          cvv2         ccv
            )
        };
    }

    if ( is_hashref $args{replacement_callbacks} ) {
        $self->{replacement_callbacks} = $args{replacement_callbacks};
    }
    if ( exists $args{replacement} ) {
        $self->{replacement} = $args{replacement};
    } else {
        $self->{replacement} = 'Hidden (looks potentially sensitive)';
    }

    $self->{recurse_limit} = $args{recurse_limit} || 100;

    return $self;

lib/Data/Censor.pm  view on Meta::CPAN

              unless $visited->{ $data->{$key} }++;
            next;
        }

        next unless
          (    $self->{is_sensitive_field}
            && $self->{is_sensitive_field}{ lc $key } )
          or ( $self->{censor_regex} && $key =~ $self->{censor_regex} );

        # OK, censor this
        if ( $self->{replacement_callbacks}{ lc $key } ) {
            $data->{$key} = $self->{replacement_callbacks}{ lc $key }->(
                $data->{$key}
            );
            $censored++;
        } else {
            $data->{$key} = $self->{replacement};
            $censored++;
        }
    }

    return $censored;

t/01-basic.t  view on Meta::CPAN

my $count = $censor->censor($data);
my $hidden = 'Hidden (looks potentially sensitive)';
is($count, 3, "Two items censored with default config");
is($data->{password}, $hidden, 'password field censored');
is($data->{email}, 'davidp@preshweb.co.uk', 'email field not censored');
is($data->{card}{pan}, $hidden, 'pan field censored (recursion works)');
is($data->{card}{expiry}, '03/16', 'expiry field not censored');

# Test replacement callback
$censor = Data::Censor->new(
    replacement_callbacks => {
        pan => sub {
            my $pan = shift;
            return "x" x (length($pan) - 4) 
                . substr($pan, -4, 4);
        },
    },
);
$data = get_data();
$count = $censor->censor($data);
is($data->{password}, $hidden, "password censored normally");



( run in 2.186 seconds using v1.01-cache-2.11-cpan-9b1e4054eb1 )