2

(这是为 x86_64-linux 构建的 cperl 5,版本 24,subversion 4 (v5.24.4c))Ubuntu 18.04。

下面是一个有效的程序。但是,当我在 Mojolicious::Lite(6.04 版)中运行该程序时,它会挂起。使用top,我看到“tr”是吃掉所有CPU的那个。我尝试使用 cat 而不是 tr ,但它仍然挂起。如果我 Control-C Mojo 代码,它会打印密码然后退出。就像 tr 正在接受 urandom 字节,但在我打断它之前不会继续折叠。但是,这适用于普通脚本,而不是 Mojo 脚本......

任何人对为什么有任何想法?

热情地

约翰

有效的脚本:

#! /usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my $pass_length = 3;
my $exec = qq{tr -cd "[:alnum:]" < /dev/urandom | fold -w$pass_length | head -n1};
print Dumper $exec;
my $pass = qx{$exec};
chomp $pass;
print Dumper $pass;

挂起的 Mojolicious Lite 代码:

use Mojolicious::Lite;

use strict;
use warnings;

use Data::Dumper;

post 'testit' => sub {
    my $c = shift;

    my $pass_length = 3;
    # tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1
    my $exec = qq{tr -cd '[:alnum:]' < /dev/urandom | fold -w$pass_length | head -n1};
    warn Dumper $exec;
    my $pass = qx{$exec};
    chomp $pass;
    warn Dumper $pass;
    return $c->render( json => { foo => 'bar'} );
};

app->secrets('foobar');
app->start;
4

2 回答 2

3
sub gen_password {
   my ($pass_len) = @_;

   # We use sysread to avoid wasting entropy by over-reading.
   # We use :raw because we use sysread.

   state $bad_syms = {
      map { $_ => 1 }
         qw( 0 O I 1 l )
   };
   state $ok_syms = {
      map { $_ => 1 }
         grep !$bad_syms->{$_},
            'a'..'z', 'A'..'Z', '0'..'9'
   };

   my $qfn = '/dev/urandom';
   open(my $fh, '<:raw', $qfn)
      or die("Can't open $qfn: $!\n");

   my $password = '';
   while (length($password) < $pass_len) {
      my $rv = sysread($fh, my $ch, 1);
      die("Can't read $qfn: $!\n") if !defined($rv);
      die("Can't read $qfn: Premature EOF\n") if !$rv;
      redo if !$ok_syms->{$ch};

      $password .= $ch;
   }

   return $password;
}

好处:

  • 更高效。
  • 更少的故障模式。
  • 更好的错误处理。
  • 保证是要求的长度。
  • 避免混淆相似的字符。

以下版本浪费的熵更少,但需要一组正好 64 个符号:

use MIME::Base64 qw( encode_base64 );

sub gen_password {
   my ($pass_len) = @_;

   my $qfn = '/dev/urandom';
   open(my $fh, '<:raw', $qfn)
      or die("Can't open $qfn: $!\n");

   my $bytes = int( ($pass_len+3) * (3/4) );
   my $buf = '';
   while ($bytes) {
      my $rv = sysread($fh, $buf, $bytes, length($buf));
      die("Can't read $qfn: $!\n") if !defined($rv);
      die("Can't read $qfn: Premature EOF\n") if !$rv;
      $bytes -= $rv;
   }

   return substr(
      encode_base64($buf, '') =~
         tr/a-zA-Z0-9+\//a-km-zA-HJ-NP-Z2-9!%^&*()/r,
      0, $pass_len,
   );
}
于 2020-07-30T17:31:54.950 回答
0

我不确定为什么tr直接从/dev/urandom. 我能够通过cattr. 以下对我有用:

my $exec = qq{head -1 /dev/urandom | cat | tr -cd '[:alnum:'] | fold -w$pass_length}

编辑

如果要生成$pass_length字符密码,可以head -c这样使用:

my $exec = qq{head -1 /dev/urandom | cat | tr -cd '[:alnum:'] | head -c $pass_length}
于 2020-07-30T12:56:16.877 回答