summaryrefslogtreecommitdiff
path: root/lib/JWebmail/Plugin/Helper.pm
diff options
context:
space:
mode:
authorJannis M. Hoffmann <jannis@fehcom.de>2023-03-13 21:34:03 +0100
committerJannis M. Hoffmann <jannis@fehcom.de>2023-03-13 21:34:03 +0100
commit8ee2d7149baa58ea225cb40e0f95030ee21f1081 (patch)
tree11d2bd52f36d3d566f9abcb30654b9bd78e56422 /lib/JWebmail/Plugin/Helper.pm
parent6441b5ad6657873fcd8f3695515fa6ef3bc4e6f5 (diff)
Split up Helper plugin and added Views instead
Diffstat (limited to 'lib/JWebmail/Plugin/Helper.pm')
-rw-r--r--lib/JWebmail/Plugin/Helper.pm426
1 files changed, 0 insertions, 426 deletions
diff --git a/lib/JWebmail/Plugin/Helper.pm b/lib/JWebmail/Plugin/Helper.pm
deleted file mode 100644
index b298a17..0000000
--- a/lib/JWebmail/Plugin/Helper.pm
+++ /dev/null
@@ -1,426 +0,0 @@
-package JWebmail::Plugin::Helper;
-
-use Mojo::Base Mojolicious::Plugin;
-
-use List::Util qw(all any min max);
-use Carp 'carp';
-use POSIX qw(floor round log ceil);
-
-use Mojo::Util qw(encode decode b64_encode b64_decode xml_escape);
-
-use constant TRUE_RANDOM => eval { require Crypt::URandom; Crypt::URandom->import('urandom'); 1 };
-
-
-### filter and checks for mojo validator
-
-sub mail_line {
- my ($v, $name, $value, @args) = @_;
-
- my $mail_addr = qr/\w+\@\w+\.\w+/;
- # my $unescaped_quote = qr/"(*nlb:\\)/; # greater perl version required
- my $unescaped_quote = qr/"(?<!:\\)/;
-
- return $value !~ /^(
- (
- (
- (
- $unescaped_quote.*?$unescaped_quote
- ) | (
- [\w\s]*
- )
- )
- \s*<$mail_addr>
- ) | (
- $mail_addr
- ))$
- /xn;
-}
-
-sub filter_empty_upload {
- my ($v, $name, $value) = @_;
-
- return $value->filename ? $value : undef;
-}
-
-
-### template formatting functions
-
-sub print_sizes10 {
- my $var = shift || return '0 Byte';
-
- my $i = floor(((log($var)/log(10))+1e-5) / 3);
- my $expo = $i * 3;
-
- my @PREFIX;
- $PREFIX[0] = 'Byte';
- $PREFIX[1] = 'kByte';
- $PREFIX[2] = 'MByte';
- $PREFIX[3] = 'GByte';
- $PREFIX[4] = 'TByte';
- $PREFIX[5] = 'PByte';
-
- return sprintf('%.0f %s', $var / (10**$expo), $PREFIX[$i]);
-}
-
-sub print_sizes2 {
- my $var = shift || return '0 Byte';
-
- my $i = floor(((log($var)/log(2))+1e-5) / 10);
- my $expo = $i * 10;
- my %PREFIX = (
- 0 => 'Byte',
- 1 => 'KiByte',
- 2 => 'MiByte',
- 3 => 'GiByte',
- 4 => 'TiByte',
- 5 => 'PiByte',
- );
- my $pref = $PREFIX{$i};
- return round($var / (2**$expo)) . " $pref";
-}
-
-my sub dgt { "([[:digit:]]{$_[0]})" }
-
-sub parse_iso_date {
- state $rx = do { my $re = dgt(4).'-'.dgt(2).'-'.dgt(2).'T'.dgt(2).':'.dgt(2).':'.dgt(2); qr/$re/a };
- my @d = shift =~ /$rx/;
- if (@d != 6) {
- # TODO
- warn "issue when parsing date";
- }
- return {
- year => $d[0],
- month => $d[1],
- mday => $d[2],
- hour => $d[3],
- min => $d[4],
- sec => $d[5],
- };
-}
-
-
-### session password handling
-
-use constant { S_PASSWD => 'pw', S_OTP_S3D_PW => 'otp_s3d_pw' };
-
-sub _rand_data {
- my $len = shift;
-
- if (TRUE_RANDOM) {
- #return makerandom_octet(Length => $len, Strength => 0); # was used for Crypt::Random
- return urandom($len);
- }
- else {
- my $res = '';
- for (0..$len-1) {
- vec($res, $_, 8) = int rand 256;
- }
-
- return $res;
- }
-}
-
-sub session_passwd {
- my ($c, $passwd, $challenge) = @_;
- my $secAlg = $c->config->{session}{secure};
-
- warn_crypt($c);
-
- if (defined $passwd) { # set
- if ($secAlg eq 'cram') {
- $c->session(S_PASSWD() => $passwd, challenge => $challenge);
- }
- elsif ($secAlg eq 's3d') {
- unless ($passwd) {
- $c->s3d(S_PASSWD, '');
- delete $c->session->{S_OTP_S3D_PW()};
- return;
- }
- die "'$passwd' contains invalid character \\n" if $passwd =~ /\n/;
- if (length $passwd < 20) {
- $passwd .= "\n" . ' ' x (20 - length($passwd) - 1);
- }
- my $passwd_utf8 = encode('UTF-8', $passwd);
- my $rand_bytes = _rand_data(length $passwd_utf8);
- $c->s3d(S_PASSWD, b64_encode($passwd_utf8 ^ $rand_bytes, ''));
- $c->session(S_OTP_S3D_PW, b64_encode($rand_bytes, ''));
- }
- else {
- $c->session(S_PASSWD() => $passwd);
- }
- }
- else { # get
- if ($secAlg eq 'cram') {
- wantarray or carp "you forgot the challenge";
- return ($c->session(S_PASSWD), $c->session('challenge'));
- }
- elsif ($secAlg eq 's3d') {
- my $pw = b64_decode($c->s3d(S_PASSWD) || '');
- my $otp = b64_decode($c->session(S_OTP_S3D_PW) || '');
- my ($res) = split "\n", decode('UTF-8', $pw ^ $otp), 2;
- return $res;
- }
- else {
- return $c->session(S_PASSWD);
- }
- }
-}
-
-sub warn_crypt {
- my $c = shift;
-
- state $once = 0;
-
- if ( !TRUE_RANDOM && !$once && lc $c->config->{session}{secure} eq 's3d' ) {
- $c->log->warn("Falling back to pseudo random generation. Please install Crypt::URandom");
- $once = 1;
- }
-}
-
-
-### pagination
-
-sub _clamp {
- my ($x, $y, $z) = @_;
-
- die '!($x <= $z)' unless $x <= $z;
-
- if ($x <= $y && $y <= $z) {
- return $y;
- }
-
- return $x if ($y < $x);
- return $z if ($z < $y);
-}
-
-sub _paginate {
- my %args = @_;
-
- my $first_item = $args{first_item};
- my $page_size = $args{page_size};
- my $total_items = $args{total_items};
-
- my $current_page = ceil($first_item/$page_size);
- my $total_pages = ceil($total_items/$page_size);
-
- my $page = sub {
- my $page_ = shift;
- return [0, 0] unless $total_items;
- $page_ = _clamp(0, $page_, $total_pages-1);
- [_clamp(0, $page_*$page_size, $total_items-1), _clamp(0, ($page_+1)*$page_size, $total_items)]
- };
-
- my $ret = {
- total_items => $total_items,
- page_size => $page_size,
-
- total_pages => $total_pages,
- current_page => $current_page,
-
- first_page => $page->(0),
- prev_page => $page->($current_page-1),
- this_page => $page->($current_page),
- next_page => $page->($current_page+1),
- last_page => $page->($total_pages-1),
- };
-
- if ($total_items) {
- $ret->{first_item} = $first_item;
- $ret->{last_item} = _clamp($first_item, $first_item+$page_size-1, $total_items-1);
- }
-
- return $ret;
-}
-
-sub paginate {
- my $c = shift;
- my ($count) = @_;
-
- my $v = $c->validation;
- my $start = $v->optional('start')->num(0, undef)->param // 0;
- my $psize = $v->optional('page_size')->num(1, undef)->param // 50;
-
- $start = _clamp(0, $start, max($count-1, 0));
- my $end = _clamp($start, $start+$psize, max($count, 0));
-
- $c->stash(pgn => _paginate(
- first_item => int($start/$psize)*$psize,
- page_size => $psize,
- total_items => $count,
- ));
-
- return $start, $end;
-}
-
-
-### registering
-
-sub register {
- my ($self, $app, $conf) = @_;
- $conf //= {};
-
- if (ref $conf->{import} eq 'ARRAY' and my @import = @{ $conf->{import} }) {
- my sub contains { any { $_[0] eq $_ } @import }
-
- # selective import
- $app->helper(print_sizes10 => sub { shift; print_sizes10(@_) })
- if contains 'print_sizes10';
- $app->helper(parse_iso_date => sub { shift; parse_iso_date(@_) })
- if contains 'parse_iso_date';
- $app->helper(print_sizes2 => sub { shift; print_sizes2(@_) })
- if contains 'print_sizes2';
- $app->helper(mime_render => \&mime_render)
- if contains 'mime_render';
- $app->helper(session_passwd => \&session_passwd)
- if contains 'session_passwd';
- $app->helper(paginate => \&paginate)
- if contains 'paginate';
- $app->validator->add_check(mail_line => \&mail_line)
- if contains 'mail_line';
- $app->validator->add_filter(non_empty_ul => \&filter_empty_upload)
- if contains 'non_empty_ul';
- }
- elsif (!$conf->{import}) { # default imports
- $app->helper(print_sizes10 => sub { shift; print_sizes10(@_) });
- $app->helper(parse_iso_date => sub { shift; parse_iso_date(@_) });
- $app->helper(mime_render => \&mime_render);
- $app->helper(session_passwd => \&session_passwd);
- $app->helper(paginate => \&paginate);
-
- $app->validator->add_check(mail_line => \&mail_line);
-
- $app->validator->add_filter(non_empty_ul => \&filter_empty_upload);
- }
- else {
- die 'unkown value for "import"'
- }
-}
-
-
-1
-
-__END__
-
-=encoding utf-8
-
-=head1 NAME
-
-Helper - Functions used as helpers in controller and templates and additional validator checks and filters
-
-=head1 SYNOPSIS
-
- use Mojo::Base 'Mojolicious';
-
- sub startup($self) {
- $app->plugin('Helper');
- }
-
-=head1 DESCRIPTION
-
-L<JWebmail::Helper> provides useful helper functions and validator cheks and filter for
-L<JWebmail::Controller::All> and various templates.
-
-=head1 HELPERS
-
-=head2 mail_line
-
-A check for validator used in mail headers for fields containing email addresses.
-
- $app->validator->add_check(mail_line => \&JWebmail::Plugin::Helper::mail_line);
-
- my $v = $c->validation;
- $v->required('to', 'not_empty')->check('mail_line');
-
-=head2 filter_empty_upload
-
-A filter for validator used to filter out empty uploads.
-
- $app->validator->add_filter(non_empty_ul => \&JWebmail::Plugin::Helper::filter_empty_upload);
-
- my $v = $c->validation;
- $v->required('file_upload', 'non_empty_ul');
-
-=head2 print_sizes10
-
-A helper for templates used to format byte sizes.
-
- $app->helper(print_sizes10 => sub { shift; JWebmail::Plugin::Helper::print_sizes10(@_) });
-
- %= print_sizes10 12345 # => 12 kB
-
-=head2 print_sizes2
-
-A helper for templates used to format byte sizes.
-
- %= print_sizes10 12345 # => 12 KiB
-
-This is not registered by default.
-
-=head2 paginate
-
-A helper for calculating page bounds.
-
-Takes the total number of items as argument.
-
-Reads in 'start' and 'page_size' query arguments.
-start is 0 based.
-
-Returns the calculated start and end points as 0 based inclusive range.
-
-Sets the stash values (all 1 based inclusive):
-
- first_item
- last_item
- total_items
- page_size
- total_pages
- current_page
- first_page
- prev_page
- next_page
- last_page
-
-=head2 session_passwd
-
-A helper used to set and get the session password. The behavior can be altered by
-setting the config variable C<< session => {secure => 's3d'} >>.
-
- $app->helper(session_passwd => \&JWebmail::Plugin::Helper::session_passwd);
-
- $c->session_passwd('s3cret');
-
-Currently the following modes are supported:
-
-=over 6
-
-=item none
-
-The password is plainly stored in session cookie.
-The cookie is stored on the client side and send with every request.
-
-=item cram
-
-A nonce is send to the client and the cram_md5 is generated there via js
-and crypto-js.
-This is vulnurable to replay attacks as the nonce is not invalidated ever.
-
-=item s3d
-
-The password is stored on the server. Additionally the password is encrypted
-by an one-time-pad that is stored in the users cookie.
-This is vulnurable to replay attacks during an active session.
-On log-in it is transfered plainly.
-
-=back
-
-=head1 DEPENDENCIES
-
-Mojolicious and recommended Crypt::URandom.
-
-=head1 SEE ALSO
-
-L<JWebmail>
-
-=head1 NOTICE
-
-This package is part of JWebmail.