<commit_before>package Mojolicious::Plugin::Util::RandomString;
use Mojo::Base 'Mojolicious::Plugin';
use Session::Token;

our $VERSION = 0.02;

my (%generator, %default, %setting);
my $read_config;

# Register plugin
sub register {
  my ($plugin, $mojo, $param) = @_;

  $param //= {};

  if (ref $param ne 'HASH') {
    $mojo->log->fatal(__PACKAGE__ . ' expects a hash reference');
    return;
  };

  # 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->{$_};
	};
      };

      # Create default generator
      $generator{'default'} //= Session::Token->new( %default );
    });


  # Establish 'random_string' helper
  $mojo->helper(
    random_string => sub {

      my $gen = $_[1];

      # Start Loop unless it is running
      Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

      # Generate from generator
      unless ($_[2]) {

	# 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;
      };

      # Controller
      shift;

      # 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 '';
    }
  );
};


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 of 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
  {<commit_msg>Minor changes<commit_after>package Mojolicious::Plugin::Util::RandomString;
use Mojo::Base 'Mojolicious::Plugin';
use Session::Token;

our $VERSION = 0.02;

my (%generator, %default, %setting);
my $read_config;

# Register plugin
sub register {
  my ($plugin, $mojo, $param) = @_;

  $param //= {};

  if (ref $param ne 'HASH') {
    $mojo->log->fatal(__PACKAGE__ . ' expects a hash reference');
    return;
  };

  # 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->{$_};
	};
      };

      # Create default generator
      $generator{'default'} //= Session::Token->new( %default );
    });


  # Establish 'random_string' helper
  $mojo->helper(
    random_string => sub {

      my $gen = $_[1];

      # Start Loop unless it is running
      Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

      # Generate from generator
      unless ($_[2]) {

	# 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;
      };

      # Controller
      shift;

      # 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 '';
    }
  );
};


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
  {
{'fraction_non_alphanumeric': 0.14808383976187522, 'fraction_numerical': 0.010169911943445367, 'mean_word_length': 3.2893617021276595, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1679783', 'n_tokens_mistral': 2757, 'n_tokens_neox': 2554, 'n_words': 693}