package Mojolicious::Plugin::Util::RandomString;
use Mojo::Base 'Mojolicious::Plugin';
use Session::Token;
our $VERSION = '0.05';
our (%generator, %setting, %default, %param);
our $read_config;
our $ok = 1;
# Register plugin
sub register {
my ($plugin, $mojo, $param) = @_;
$ok--;
if (ref $param ne 'HASH') {
$mojo->log->fatal(__PACKAGE__ . ' expects a hash reference');
return;
};
if ($param) {
$param{$_} = $param->{$_} foreach keys %$param;
};
# Load parameter from Config file
unless ($read_config) {
if (my $config_param = $mojo->config('Util-RandomString')) {
%param = ( %$config_param, %param );
};
$read_config = 1;
};
# Reseed on fork
Mojo::IOLoop->timer(
0 => sub {
my %created = ();
# Create generators by param
foreach (keys %param) {
# Named generator
if (ref $param{$_} && ref $param{$_} eq 'HASH') {
next if $created{$_};
# Construct object
unless ($generator{$_} = Session::Token->new(
%{ $param{$_} }
)) {
# Unable to construct object
$mojo->log->fatal(qq!Unable to create generator for "$_"!);
next;
};
$setting{$_} = { %{$param{$_}} };
$created{$_} = 1;
}
# Default parameter
else {
$default{$_} = $param{$_};
};
};
# Plugin registered
$ok++;
# Create default generator
unless (exists $generator{default}) {
$generator{default} = Session::Token->new( %default );
};
});
# Establish 'random_string' helper
$mojo->helper(
random_string => sub {
shift;
my $gen = $_[0];
# One tick for loop until the plugin is registered
Mojo::IOLoop->one_tick until Mojo::IOLoop->is_running || $ok > 0;
# Generate from generator
unless ($_[1]) {
# Generator doesn't exist
if ($gen && !exists $generator{$gen}) {
$mojo->log->warn(qq!RandomString generator "$gen" is unknown!);
return '';
};
# Get from generator
return $generator{$gen || 'default'}->get;
};
# Overwrite default configuration
return Session::Token->new(%default, @_)->get unless @_ % 2;
$gen = shift;
return Session::Token->new(%default, @_)->get if $gen eq 'default';
# Overwrite specific configuration
if ($setting{ $gen }) {
return Session::Token->new( %{ $setting{ $gen } } , @_)->get;
};
# Generator is unknown
$mojo->log->warn(qq!RandomString generator "$gen" is unknown!);
return '';
}
) unless exists $mojo->renderer->helpers->{random_string};
};
1;
__END__
=pod
=head1 NAME
Mojolicious::Plugin::Util::RandomString - Generate Secure Random Strings for Mojolicious
=head1 SYNOPSIS
# Mojolicious::Lite
plugin 'Util::RandomString' => {
entropy => 256,
printable => {
alphabet => '2345679bdfhmnprtFGHJLMNPRT',
length => 20
}
};
# Generate string with default configuration
<%= random_string %>
# Generate string with 'printable' configuration
<%= random_string 'printable' %>
# Generate string with 'printable' configuration
# and overwrite length
<%= random_string 'printable', length => 16 %>
# Generate string with default configuration
# and overwrite character set in a Controller
$c->random_string(alphabet => ['a' .. 'z']);
=head1 DESCRIPTION
L<Mojolicious::Plugin::Util::RandomString> is a plugin to generate
random strings for session tokens, encryption salt, temporary
password generation etc. Internally it uses L<Session::Token>
(see L<this comparison|http://neilb.org/reviews/passwords.html#Session::Token>
for reasons for this decision).
This plugin will automatically reseed the random number generator in
a forking environment like Hypnotoad (although it is untested in other
forking environments that don't use L<Mojo::IOLoop>).
=head1 METHODS
L<Mojolicious::Plugin::Util::RandomString> inherits all methods from
L<Mojolicious::Plugin> and implements the following new one.
=head2 register
# Mojolicious
$app->plugin('Util::RandomString');
# Mojolicious::Lite
plugin 'Util::RandomString' => {
entropy => 256,
printable => {
alphabet => '2345679bdfhmnprtFGHJLMNPRT',
length => 20
}
};
# Or in your config file
{
'Util-RandomString' => {
entropy => 256,
printable => {
alphabet => '2345679bdfhmnprtFGHJLMNPRT',
length => 20
}
}
}
Called when registering the plugin.
Expects a hash reference containing parameters as defined in
L<Session::Token> for the default generator.
To specify named generators, use a name key (other than C<alphabet>,
C<length>, and C<entropy>) and specify the parameters as a hash reference.
The name key 'default' can overwrite the default configuration.
All parameters can be set either on registration or
as part of the configuration file with the key C<Util-RandomString>.
The plugin can be registered multiple times with different,
overwriting configurations.
The default alphabet is base62. This is good for a lot of use cases.
If you want to generate human readable tokens, you can define another scheme
(e.g. the above shown 'printable' base26 scheme with a character set with
visually distinctive characters, that also makes it unlikely to generate
insulting words due to missing vocals).
=head1 HELPERS
=head2 random_string
# In Controller
print $c->random_string;
print $c->random_string('printable');
print $c->random_string(length => 45)
print $c->random_string('printable', length => 45)
# In Template
%= random_string;
%= random_string('printable');
%= random_string(length => 45)
%= random_string('printable', length => 45)
Generate a random string.
In case of no parameters, the default configuration is used.
In case of one parameter, this is treated as the key of a
chosen configuration. The following parameters can be used to modify
a given configuration for one request (but please B<note>: each
modified request creates a new and seeded L<Session::Token> generator,
which is bad for performance).
=head1 DEPENDENCIES
L<Mojolicious> (best with SSL support),
L<Session::Token>.
=head1 AVAILABILITY
https://github.com/Akron/Mojolicious-Plugin-Util-RandomString
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2013-2014, L<Nils Diewald|http://nils-diewald.de/>.
This program is free software, you can redistribute it
and/or modify it under the terms of the Artistic License version 2.0.
=cut