Crypt-Credentials

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

   },
   "provides" : {
      "Crypt::Credentials" : {
         "file" : "lib/Crypt/Credentials.pm",
         "version" : "0.006"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/Leont/crypt-credentials/issues"
      },
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/Leont/crypt-credentials.git",
         "web" : "https://github.com/Leont/crypt-credentials"
      }
   },
   "version" : "0.006",
   "x_generated_by_perl" : "v5.40.1",
   "x_serialization_backend" : "Cpanel::JSON::XS version 4.39",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}

META.yml  view on Meta::CPAN

  Crypt::SysRandom: '0'
  File::Basename: '0'
  File::Path: '0'
  File::Slurper: '0'
  File::Spec::Functions: '0'
  YAML::PP: '0'
  perl: '5.010'
  strict: '0'
  warnings: '0'
resources:
  bugtracker: https://github.com/Leont/crypt-credentials/issues
  repository: git://github.com/Leont/crypt-credentials.git
version: '0.006'
x_generated_by_perl: v5.40.1
x_serialization_backend: 'YAML::Tiny version 1.76'
x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later'

lib/Crypt/Credentials.pm  view on Meta::CPAN

use Crypt::SysRandom 'random_bytes';
use File::Basename 'dirname';
use File::Path 'make_path';
use File::Slurper qw/read_binary write_binary/;
use File::Spec::Functions qw/catdir catfile curdir updir abs2rel rel2abs/;
use YAML::PP;

sub new {
	my ($class, %args) = @_;

	my $dir = rel2abs($args{dir} // catdir(curdir, 'credentials'));

	my $check_file = catfile($dir, 'check.enc');

	my $real_key;

	if (-f $check_file) {
		for my $key (@{ $args{keys} }) {
			my $length = length $key;
			croak "Invalid key size($length)" if $length != 16 && $length != 24 && $length != 32;
			my $tag = eval { $class->_get($check_file, $key) } // '';

lib/Crypt/Credentials.pm  view on Meta::CPAN

	my ($self, $name, @content) = @_;
	my $plaintext = $ypp->dump_string(@content);
	return $self->put($name, $plaintext);
}

sub _get {
	my ($self, $filename, $key) = @_;
	my $raw = read_binary($filename);
	my ($iv, $tag, $ciphertext) = unpack $format, $raw;
	my $plaintext = gcm_decrypt_verify('AES', $key, $iv, '', $ciphertext, $tag);
	croak 'Could not decrypt credentials file' if not defined $plaintext;
	return $plaintext;
}

sub get {
	my ($self, $name) = @_;
	my $filename = catfile($self->{dir}, "$name.yml.enc");
	croak "No such credentials '$name'" if not -f $filename;
	return $self->_get($filename, $self->{key});
}

sub get_yaml {
	my ($self, $name) = @_;
	my $plaintext = $self->get($name);
	return $ypp->load_string($plaintext);
}

sub has {

lib/Crypt/Credentials.pm  view on Meta::CPAN

=head1 NAME

Crypt::Credentials - Manage credential files

=head1 VERSION

version 0.006

=head1 SYNOPSIS

 my $credentials = Crypt::Credentials->new(
   dir => $dir,
   keys => split /:/, $ENV{CREDENTIAL_KEYS},
 );

 my $password = $credentials->get('password');

=head1 DESCRIPTION

This module implements a credentials store. Essentially it allows you to expand one secret (the key of the store) into any number of secrets.

=head1 METHODS

=head2 new

 $self->new(keys => \@keys, dir => $dir)

This creates a new C<Crypt::Credentials> object. It takes two named arguments: C<@keys> (mandatory) are the cryptographic keys used to encrypt the credentials, they must be either 16, 24, or 32 bytes long. If multiple keys are given they're tried unt...

=head2 get

 $self->get($name)

This reads the credentials entry for C<$name>, or throws an exception if it can't be opened for any reason.

=head2 get_yaml

 $self->get_yaml($name)

Like the above, except it will decode the payload as YAML.

=head2 put

 $self->put($name, $value)

This will write the values to the named credentials entry.

=head2 put_yaml

 $self->put_yaml($name, \%values)

Like the above, but it will encode the value to YAML first.

=head2 has

 $self->has($name)

This checks if a credentials entry exists

=head2 remove

 $self->remove($name)

This removes a credentials entry. It will silently succeed if no such entry exists.

=head2 list

 $self->list

This will list all credential entries.

=head2 recode

 $self->recode($new_key)

t/basic.t  view on Meta::CPAN

use warnings;

use Test::More;

use Crypt::Credentials;
use File::Slurper 'read_binary';
use File::Temp 'tempdir';

my $dir = tempdir(CLEANUP => 1);

my $credentials = Crypt::Credentials->new(
	keys => [ '0123456789ABCDEF' ],
	dir  => $dir,
);

is_deeply [$credentials->list], [], 'No entries yet';

my $original = { password => 'pass123' };
my $written = eval { $credentials->put_yaml('first', $original); 1 };
ok $written, 'Entry was written';

my $back = eval { $credentials->get_yaml('first') };
is_deeply($back, $original, 'Values roundtrip');

is_deeply [$credentials->list], ['first'], 'One entry';

my $file = File::Spec->catdir($dir, 'first.yml.enc');
ok -B $file, 'File is binary';

my $raw_before = read_binary($file);

$credentials->recode('FEDCBA9876543210');

my $raw_after = read_binary($file);

isnt($raw_after, $raw_before, 'File changed on recode');

my $credentials2 = Crypt::Credentials->new(
	keys => [ '0123456789ABCDEF', 'FEDCBA9876543210' ],
	dir  => $dir,
);

my $back2 = eval { $credentials2->get_yaml('first') };
is_deeply($back2, $original, 'Values roundtrip again');

done_testing;



( run in 0.268 second using v1.01-cache-2.11-cpan-4d50c553e7e )