App::Genpass - Quickly and easily create secure passwords


App-Genpass documentation Contained in the App-Genpass distribution.

Index


Code Index:

NAME

Top

App::Genpass - Quickly and easily create secure passwords

VERSION

Top

version 2.01

SYNOPSIS

Top

    use App::Genpass;

    my $genpass = App::Genpass->new();
    print $genpass->generate, "\n";

    $genpass = App::Genpass->new( readable => 0, length => 20 );
    print "$_\n" for $genpass->generate(10);

DESCRIPTION

Top

If you've ever needed to create 10 (or even 10,000) passwords on the fly with varying preferences (lowercase, uppercase, no confusing characters, special characters, minimum length, etc.), you know it can become a pretty pesky task.

This script makes it possible to create flexible and secure passwords, quickly and easily.

    use App::Genpass;
    my $genpass = App::Genpass->new();

    my $single_password    = $genpass->generate(1);  # returns scalar
    my @single_password    = $genpass->generate(1);  # returns array
    my @multiple_passwords = $genpass->generate(10); # returns array again
    my $multiple_passwords = $genpass->generate(10); # returns arrayref

SUBROUTINES/METHODS

Top

new

Creates a new instance. It gets a lot of options.

flags

These are boolean flags which change the way App::Genpass works.

number

You can decide how many passwords to create. The default is 1.

This can be overridden per generate so you can have a default of 30 but in a specific case only generate 2, if that's what you want.

readable

Use only readable characters, excluding confusing characters: "o", "O", "0", "l", "1", "I".

You can overwrite what characters are considered unreadable under "character attributes" below.

Default: on.

special

Include special characters: "!", "@", "#", "$", "%", "^", "&", "*", "(", ")"

Default: on.

verify

Verify that every type of character wanted (lowercase, uppercase, numerical, specials, etc.) are present in the password. This makes it just a tad slower, but it guarantees the result. Best keep it on.

To emphesize how "slower" it is: if you create 500 passwords of 500 character length, using verify off, will make it faster by 0.1 seconds.

Default: on.

attributes

length

How long will the passwords be.

Default: 10.

character attributes

These are the attributes that control the types of characters. One can change which lowercase characters will be used or whether they will be used at all, for example.

    # only a,b,c,d,e,g will be consdered lowercase and no uppercase at all
    my $gp = App::Genpass->new( lowercase => [ 'a' .. 'g' ], uppercase => [] );

lowercase

All lowercase characters, excluding those that are considered unreadable if the readable flag (described above) is turned on.

Default: [ 'a' .. 'z' ] (not including excluded chars).

uppercase

All uppercase characters, excluding those that are considered unreadable if the readable flag (described above) is turned on.

Default: [ 'A' .. 'Z' ] (not including excluded chars).

numerical

All numerical characters, excluding those that are considered unreadable if the readable flag (described above) is turned on.

Default: [ '0' .. '9' ] (not including excluded chars).

unreadable

All characters which are considered (by me) unreadable. You can change this to what you consider unreadable characters. For example:

    my $gp = App::Genpass->new( unreadable => [ qw(jlvV) ] );

After all the characters are set, unreadable characters will be removed from all sets.

Thus, unreadable characters override all other sets. You can make unreadable characters not count by using the <readable = 0>> option, described by the readable flag above.

specials

All special characters.

Default: [ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')' ].

(not including excluded chars)

generate

This method generates the password or passwords.

It accepts only one parameter, which is how many passwords to generate.

    $gp = App::Genpass->new();
    my @passwords = $gp->generate(300); # 300 passwords to go

This method tries to be tricky and DWIM (or rather, DWYM). That is, if you request it to generate only one password and use a scalar (<my $p = $gp-generate(1)>>), it will return a single password.

However, if you try to generate multiple passwords and use a scalar (<my $p = $gp-generate(30)>>), it will return an arrayref for the passwords.

Generating passwords with arrays (<my @p = $gp-generate(...)>>) will always return an array of the passwords, even if it's a single password.

get_config_from_file

Reads the configuration file using Config::Any.

Shamelessly lifted from MooseX::SimpleConfig because there is no MouseX::SimpleConfig.

AUTHOR

Top

Sawyer X, <xsawyerx at cpan.org>

DEPENDENCIES

Top

Mouse

MouseX::Getopt

MouseX::ConfigFromFile

Config::Any

Path::Class

List::AllUtils

File::HomeDir

namespace::autoclean

BUGS AND LIMITATIONS

Top

Please report any bugs or feature requests to bug-app-genpass at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Genpass. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

Top

You can find documentation for this module with the perldoc command.

    perldoc App::Genpass

You can also look for information at:

* Github: App::Genpass repository

http://github.com/xsawyerx/app-genpass

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Genpass

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/App-Genpass

* CPAN Ratings

http://cpanratings.perl.org/d/App-Genpass

* Search CPAN

http://search.cpan.org/dist/App-Genpass/

AUTHOR

Top

  Sawyer X <xsawyerx@cpan.org>

COPYRIGHT AND LICENSE

Top


App-Genpass documentation Contained in the App-Genpass distribution.

package App::Genpass;
BEGIN {
  $App::Genpass::VERSION = '2.01';
}
# ABSTRACT: Quickly and easily create secure passwords

use Carp;
use Mouse;
use Path::Class 'file';
use Config::Any;
use File::HomeDir;
use List::AllUtils qw( any none shuffle );
use namespace::autoclean;

with qw/
    MouseX::ConfigFromFile
    MouseX::Getopt
/;

# attributes for password generation
has 'lowercase' => (
    is => 'rw', isa => 'ArrayRef[Str]', default => sub { [ 'a'..'z' ] },
);

has 'uppercase' => (
    is => 'rw', isa => 'ArrayRef[Str]', default => sub { [ 'A'..'Z' ] },
);

has 'numerical' => (
    is => 'rw', isa => 'ArrayRef[Str]', default => sub { [ '0' .. '9' ] },
);

has 'unreadable' => (
    is      => 'ro',
    isa     => 'ArrayRef[Str]',
    default => sub { [ split //sm, q{oO0l1I} ] },
);

## no critic (RequireInterpolationOfMetachars)

has 'specials' => (
    is      => 'ro',
    isa     => 'ArrayRef[Str]',
    default => sub { [ split //sm, q{!@#$%^&*()} ] },
);

## use critic

has 'number' => (
    is          => 'ro',
    isa         => 'Int',
    default     => 1,
    traits      => ['Getopt'],
    cmd_aliases => 'n',
);

has 'readable' => (
    is          => 'ro',
    isa         => 'Bool',
    default     => 1,
    traits      => ['Getopt'],
    cmd_aliases => 'r',
);

has 'special' => (
    is          => 'ro',
    isa         => 'Bool',
    default     => 1,
    traits      => ['Getopt'],
    cmd_aliases => 's',
);

has 'verify' => (
    is          => 'ro',
    isa         => 'Bool',
    default     => 1,
    traits      => ['Getopt'],
    cmd_aliases => 'v',
);

has 'length' => (
    is          => 'ro',
    isa         => 'Int',
    default     => 10,
    traits      => ['Getopt'],
    cmd_aliases => 'l',
);

has '+configfile' => (
    isa     => 'Maybe[MouseX::Types::Path::Class::File]',
    default => sub {
        my @files = (
            file( File::HomeDir->my_home, '.genpass.yaml' ),
            '/etc/genpass.yaml',
        );

        foreach my $file (@files) {
            -e $file && -r $file and return file($file);
        }

        return;
    },
);

sub get_config_from_file {
    my ($class, $file) = @_;

    $file = $file->() if ref $file eq 'CODE';
    my $files_ref = ref $file eq 'ARRAY' ? $file : [$file];

    my $can_config_any_args = $class->can('config_any_args');
    my $extra_args = $can_config_any_args ?
        $can_config_any_args->($class, $file) : {};
    ;
    my $raw_cfany = Config::Any->load_files({
        %$extra_args,
        use_ext         => 1,
        files           => $files_ref,
        flatten_to_hash => 1,
    } );

    my %raw_config;
    foreach my $file_tested ( reverse @{$files_ref} ) {
        if ( ! exists $raw_cfany->{$file_tested} ) {
            warn qq{Specified configfile '$file_tested' does not exist, } .
                qq{is empty, or is not readable\n};
                next;
        }

        my $cfany_hash = $raw_cfany->{$file_tested};
        die "configfile must represent a hash structure in file: $file_tested"
            unless $cfany_hash && ref $cfany_hash && ref $cfany_hash eq 'HASH';

        %raw_config = ( %raw_config, %{$cfany_hash} );
    }

    \%raw_config;
}

sub _get_chars {
    my $self      = shift;
    my @all_types = qw( lowercase uppercase numerical specials );
    my @chars     = ();
    my @types     = ();

    # adding all the combinations
    foreach my $type (@all_types) {
        if ( my $ref = $self->$type ) {
            push @chars, @{$ref};
            push @types, $type;
        }
    }

    # removing the unreadable chars
    if ( $self->readable ) {
        my @remove_chars = (
            @{ $self->unreadable },
            @{ $self->specials   },
        );

        @chars = grep {
            local $a = $_;
            none { $a eq $_ } @remove_chars;
        } @chars;

        # removing specials
        pop @types;
    }

    # make both refs
    return [ \@types, @chars ];
}

sub generate {
    my ( $self, $number ) = @_;

    my $length        = $self->length;
    my $verify        = $self->verify;
    my @passwords     = ();
    my @verifications = ();
    my $EMPTY         = q{};

    my ( $char_types, @chars ) = @{ $self->_get_chars };

    my @char_types   = @{$char_types};
    my $num_of_types = scalar @char_types;

    if ( $num_of_types > $length ) {
        croak <<"_DIE_MSG";
You wanted a longer password that the variety of characters you've selected.
You requested $num_of_types types of characters but only have $length length.
_DIE_MSG
    }

    $number ||= $self->number;

    # each password iteration needed
    foreach my $pass_iter ( 1 .. $number ) {
        my $password  = $EMPTY;
        my $char_type = shift @char_types;

        # generating the password
        while ( $length > length $password ) {
            my $char = $chars[ int rand @chars ];

            # for verifying, we just check that it has small capital letters
            # if that doesn't work, we keep asking it to get a new random one
            # the check if it has large capital letters and so on
            if ( $verify && $char_type ) {
                # verify $char_type
                while ( ! any { $_ eq $char } @{ $self->$char_type } ) {
                    $char = $chars[ int rand @chars ];
                }

                $char_type =
                    scalar @char_types > 0 ? shift @char_types : $EMPTY;
            }

            $password .= $char;
        }

        # since the verification process creates a situation of ordered types
        # (lowercase, uppercase, numerical, special)
        # we need to shuffle the string
        $password = join $EMPTY, shuffle( split //sm, $password );

        $number == 1 && return $password;

        push @passwords, $password;

        @char_types = @{$char_types};
    }

    return wantarray ? @passwords : \@passwords;
}

__PACKAGE__->meta->make_immutable;
no Mouse;

1;




__END__