1package Crypt::Random::Source::Factory; 2# ABSTRACT: Load and instantiate sources of random data 3 4our $VERSION = '0.12'; 5 6use Moo; 7use Carp qw(croak); 8use Module::Find; 9use Module::Runtime qw(require_module); 10use Types::Standard qw(ClassName Bool ArrayRef Str); 11use namespace::clean; 12 13sub get { 14 my ( $self, %args ) = @_; 15 16 my $type = delete $args{type} || "any"; 17 18 my $method = "new_$type"; 19 20 $self->can($method) or croak "Don't know how to create a source of type $type"; 21 22 $self->$method(%args); 23} 24 25sub get_weak { 26 my ( $self, @args ) = @_; 27 $self->get( @args, type => "weak" ); 28} 29 30sub get_strong { 31 my ( $self, @args ) = @_; 32 $self->get( @args, type => "strong" ); 33} 34 35has weak_source => ( 36 isa => ClassName, 37 is => "rw", 38 lazy => 1, 39 builder => 1, 40 clearer => "clear_weak_source", 41 predicate => "has_weak_source", 42 handles => { new_weak => "new" }, 43); 44 45sub _build_weak_source { 46 my $self = shift; 47 $self->best_available(@{ $self->weak_sources }); 48} 49 50has strong_source => ( 51 isa => ClassName, 52 is => "rw", 53 lazy => 1, 54 builder => 1, 55 clearer => "clear_strong_source", 56 predicate => 'has_strong_source', 57 handles => { new_strong => "new" }, 58); 59 60sub _build_strong_source { 61 my $self = shift; 62 $self->best_available(@{ $self->strong_sources }); 63} 64 65has any_source => ( 66 isa => ClassName, 67 is => "rw", 68 lazy => 1, 69 builder => 1, 70 clearer => "clear_any_source", 71 predicate => 'has_any_source', 72 handles => { new_any => 'new' }, 73); 74 75sub _build_any_source { 76 my $self = shift; 77 $self->weak_source || $self->strong_source; 78} 79 80has scan_inc => ( 81 is => "ro", 82 isa => Bool, 83 lazy => 1, 84 builder => 1, 85 clearer => 'clear_scan_inc', 86 predicate => 'has_scan_inc', 87); 88 89sub _build_scan_inc { 90 my $self = shift; 91 92 if ( exists $ENV{CRYPT_RANDOM_NOT_PLUGGABLE} ) { 93 return !$ENV{CRYPT_RANDOM_NOT_PLUGGABLE}; 94 } else { 95 return 1; 96 } 97} 98 99has weak_sources => ( 100 isa => ArrayRef[Str], 101 is => "rw", 102 lazy => 1, 103 builder => 1, 104 clearer => 'clear_weak_sources', 105 predicate => 'has_weak_sources', 106); 107 108sub _build_weak_sources { 109 my $self = shift; 110 111 if ( $self->scan_inc ) { 112 $self->locate_sources("Weak"); 113 } else { 114 return [qw( 115 Crypt::Random::Source::Weak::devurandom 116 Crypt::Random::Source::Weak::openssl 117 Crypt::Random::Source::Weak::rand 118 )]; 119 } 120} 121 122has strong_sources => ( 123 isa => ArrayRef[Str], 124 is => "rw", 125 lazy => 1, 126 builder => 1, 127 clearer => 'clear_strong_sources', 128 predicate => 'has_strong_sources', 129); 130 131sub _build_strong_sources { 132 my $self = shift; 133 134 if ( $self->scan_inc ) { 135 return $self->locate_sources("Strong"); 136 } else { 137 return [qw( 138 Crypt::Random::Source::Strong::devrandom 139 Crypt::Random::Source::Strong::egd 140 )]; 141 } 142} 143 144sub best_available { 145 my ( $self, @sources ) = @_; 146 147 my @available = grep { local $@; eval { require_module($_); $_->available }; } @sources; 148 149 my @sorted = sort { $b->rank <=> $a->rank } @available; 150 151 wantarray ? @sorted : $sorted[0]; 152} 153 154sub first_available { 155 my ( $self, @sources ) = @_; 156 157 foreach my $class ( @sources ) { 158 local $@; 159 return $class if eval { require_module($class); $class->available }; 160 } 161} 162 163sub locate_sources { 164 my ( $self, $category ) = @_; 165 my @sources = findsubmod "Crypt::Random::Source::$category"; 166 # Untaint class names (which are tainted in taint mode because 167 # they came from the disk). 168 ($_) = $_ =~ /^(.*)$/ foreach @sources; 169 return \@sources; 170} 171 1721; 173 174=pod 175 176=encoding UTF-8 177 178=head1 NAME 179 180Crypt::Random::Source::Factory - Load and instantiate sources of random data 181 182=head1 VERSION 183 184version 0.12 185 186=head1 SYNOPSIS 187 188 use Crypt::Random::Source::Factory; 189 190 my $f = Crypt::Random::Source::Factory->new; 191 192 my $strong = $f->get_strong; 193 194 my $weak = $f->get_weak; 195 196 my $any = $f->get; 197 198=head1 DESCRIPTION 199 200This class implements a loading and instantiation factory for 201L<Crypt::Random::Source> objects. 202 203If C<$ENV{CRYPT_RANDOM_NOT_PLUGGABLE}> is set then only a preset list of 204sources will be tried. Otherwise L<Module::Find> will be used to locate any 205installed sources, and use the first available one. 206 207=head1 METHODS 208 209=head2 get %args 210 211Instantiate any random source, passing %args to the constructor. 212 213The C<type> argument can be C<weak>, C<strong> or C<any>. 214 215=head2 get_weak %args 216 217=head2 get_strong %args 218 219Instantiate a new weak or strong random source. 220 221=head1 SUPPORT 222 223Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Crypt-Random-Source> 224(or L<bug-Crypt-Random-Source@rt.cpan.org|mailto:bug-Crypt-Random-Source@rt.cpan.org>). 225 226=head1 AUTHOR 227 228יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> 229 230=head1 COPYRIGHT AND LICENCE 231 232This software is copyright (c) 2008 by Yuval Kogman. 233 234This is free software; you can redistribute it and/or modify it under 235the same terms as the Perl 5 programming language system itself. 236 237=cut 238 239__END__ 240 241 242# ex: set sw=4 et: 243