summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.PL17
-rw-r--r--README.md25
-rw-r--r--lib/JWebmail/Model/ReadMails/MockJSON.pm2
-rw-r--r--lib/JWebmail/Plugin/Helper.pm48
-rw-r--r--lib/JWebmail/Plugin/I18N.pm4
-rw-r--r--lib/JWebmail/Plugin/I18N2.pm15
-rw-r--r--lib/JWebmail/Plugin/ServerSideSessionData.pm30
7 files changed, 71 insertions, 70 deletions
diff --git a/Makefile.PL b/Makefile.PL
index 6e07149..4a9ce64 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -7,13 +7,14 @@ WriteMakefile(
VERSION_FROM => 'lib/JWebmail.pm',
LICENSE => 'gpl_3',
PREREQ_PM => {
- 'Mojolicious' => '8.64',
- 'Config::Tiny' => 'v2.24',
- 'Crypt::URandom' => 0,
- 'Email::MIME' => 0,
- 'Mail::Box::Manager' => 'v3.9',
- 'Role::Tiny' => 'v2.0.1',
- 'Class::Method::Modifiers' => 'v2.13',
+ Mojolicious => '9.19',
+ Config::Tiny => 'v2.24',
+ Crypt::URandom => 'v0.36',
+ Digest::HMAC_MD5 => '1.04',
+ Email::MIME => 'v1.951',
+ Mail::Box::Manager => 'v3.9',
+ Role::Tiny => 'v2.2',
+ Class::Method::Modifiers => 'v2.13',
},
- test => {TESTS => 't/*.t'}
+ test => {TESTS => 't/*.t'},
)
diff --git a/README.md b/README.md
index 07bcb27..0040006 100644
--- a/README.md
+++ b/README.md
@@ -78,21 +78,28 @@ matching have been published. No need to monkey_patch and it works well enough.
## Concepts
- Router Mojolicious build-in
- Configuration INI via Config::Tiny
+ Logging Mojo::Log
+ Router Mojolicious::Routes
Middleware (auth) Mojo under
Controller/Handler Mojolicious::Controller
- Templates Mojo format ep
- Template helpers Mojolicious->helper
- i18n (url rewriting) see 'I18N patch url_for'
- Sessions (server side) self developed plug-in
+ Templates Mojolicious::Renderer (format ep)
+ Sessions Mojo::Sessions (cookies) and Plugin::ServerSideSessionData
Flash Mojo
+ Validation Mojo::Validator
+ MIME handling
+ Static server Mojolicious::Static
+ Maildir client
+ Object system Mojo::Base and Role::Tiny
+ Exceptions
+ Frontend code
+ Configuration Plugin::INIConfig
Pagination self developed
- Validation Mojo
- Logging Mojo::Log
+ I18N Plugin::I18N2
+
Debug printing Data::Dumper
Development server Mojo
- MIME handling
+ Frontend package manager NPM
+ Backend package manager CPAN
Dependencies
diff --git a/lib/JWebmail/Model/ReadMails/MockJSON.pm b/lib/JWebmail/Model/ReadMails/MockJSON.pm
index f77cd2a..7decb7d 100644
--- a/lib/JWebmail/Model/ReadMails/MockJSON.pm
+++ b/lib/JWebmail/Model/ReadMails/MockJSON.pm
@@ -69,7 +69,7 @@ sub read_headers_for {
}
my $s = sub {
my $sort_by = $sort;
- my $rev = $sort_by !~ m/^![[:lower:]]+/ ? 1 : -1;
+ my $rev = $sort_by !~ m/^!/ ? 1 : -1;
$sort_by =~ s/^!//;
return (($a->{$sort_by}||$a->{head}{$sort_by}) cmp ($b->{$sort_by}||$b->{head}{$sort_by})) * $rev;
};
diff --git a/lib/JWebmail/Plugin/Helper.pm b/lib/JWebmail/Plugin/Helper.pm
index be147fe..cd72bfa 100644
--- a/lib/JWebmail/Plugin/Helper.pm
+++ b/lib/JWebmail/Plugin/Helper.pm
@@ -1,13 +1,14 @@
package JWebmail::Plugin::Helper;
-use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::Base Mojolicious::Plugin;
use List::Util qw(all min max);
-use Mojo::Util qw(encode decode b64_encode b64_decode xml_escape);
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 };
-use constant HMAC => eval { require Digest::HMAC_MD5; Digest::HMAC_MD5->import('hmac_md5'); 1 };
+use constant HMAC_MD5 => eval { require Digest::HMAC_MD5; Digest::HMAC_MD5->import('hmac_md5'); 1 };
### filter and checks for mojo validator
@@ -32,7 +33,7 @@ sub mail_line {
) | (
$mail_addr
))$
- /xno;
+ /xn;
}
@@ -80,13 +81,14 @@ sub print_sizes2 {
}
-sub d { qr/([[:digit:]]{$_[0]})/ }
+my sub d { "([[:digit:]]{$_[0]})" }
sub parse_iso_date {
- state $rx = d(4).'-'.d(2).'-'.d(2).'T'.d(2).':'.d(2).':'.d(2);
- my @d = shift =~ m/$rx/;
- if (!all { defined $_ } @d) {
+ state $rx = do { my $re = d(4).'-'.d(2).'-'.d(2).'T'.d(2).':'.d(2).':'.d(2); qr/$re/a };
+ my @d = shift =~ /$rx/;
+ if (@d != 6) {
# TODO
+ warn "issue when parsing date";
}
return {
year => $d[0],
@@ -155,15 +157,17 @@ sub _rand_data {
sub session_passwd {
my ($c, $passwd) = @_;
+ my $secAlg = $c->config->{session}{secure};
- warn_cram($c);
+ die "you need to install Digest::HMAC_MD5 for cram to work"
+ if !HMAC_MD5 && $secAlg eq 'cram';
warn_crypt($c);
if (defined $passwd) { # set
- if ( HMAC && lc($c->config->{session}{secure}) eq 'cram' ) {
+ if ($secAlg eq 'cram') {
$c->session(S_PASSWD() => $passwd ? b64_encode(hmac_md5($passwd, $c->app->secrets->[0]), '') : '');
}
- elsif (lc($c->config->{session}{secure}) eq 's3d') {
+ elsif ($secAlg eq 's3d') {
unless ($passwd) {
$c->s3d(S_PASSWD, '');
delete $c->session->{S_OTP_S3D_PW()};
@@ -171,7 +175,7 @@ sub session_passwd {
}
die "'$passwd' contains invalid character \\n" if $passwd =~ /\n/;
if (length $passwd < 20) {
- $passwd .= "\n" . " " x (20 - length($passwd) - 1);
+ $passwd .= "\n" . ' ' x (20 - length($passwd) - 1);
}
my $rand_bytes = _rand_data(length $passwd);
$c->s3d(S_PASSWD, b64_encode(encode('UTF-8', $passwd) ^ $rand_bytes, ''));
@@ -182,10 +186,11 @@ sub session_passwd {
}
}
else { # get
- if ( HMAC && lc($c->config->{'session'}{secure}) eq 'cram' ) {
+ if ($secAlg eq 'cram') {
+ wantarray or warn "you forgot the challenge";
return ($c->app->secrets->[0], $c->session(S_PASSWD));
}
- elsif (lc($c->config->{'session'}{secure}) eq 's3d') {
+ 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;
@@ -197,24 +202,13 @@ sub session_passwd {
}
}
-sub warn_cram {
- my $c = shift;
-
- state $once = 0;
-
- if ( !HMAC && !$once && lc($c->config->{'session'}{secure}) eq 'cram' ) {
- $c->log->warn("cram requires Digest::HMAC_MD5. Falling back to 'none'.");
- $once = 1;
- }
-}
-
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::Random");
+ 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;
}
}
diff --git a/lib/JWebmail/Plugin/I18N.pm b/lib/JWebmail/Plugin/I18N.pm
index 6d58932..55b1a39 100644
--- a/lib/JWebmail/Plugin/I18N.pm
+++ b/lib/JWebmail/Plugin/I18N.pm
@@ -45,7 +45,7 @@ sub register {
{
local $" = ',';
- $i18n_log->debug("loaded languages (@languages)");
+ $i18n_log->info("loaded languages (@languages)");
}
$self->_language_loaded( { map { $_ => 1 } @languages } );
@@ -55,7 +55,7 @@ sub register {
my ($lang, $word) = @_;
$TXT->{$lang}{$word} || scalar(
local $" = ' ',
- $lang && $word ? $app->log->debug('[' . __PACKAGE__ . "] missing translation for $lang:$word @{[ caller(2) ]}[0..2]") : (),
+ $lang && $word ? $app->log->warn('[' . __PACKAGE__ . "] missing translation for $lang:$word @{[ caller(2) ]}[0..2]") : (),
'',
)
};
diff --git a/lib/JWebmail/Plugin/I18N2.pm b/lib/JWebmail/Plugin/I18N2.pm
index c951eec..61f87d6 100644
--- a/lib/JWebmail/Plugin/I18N2.pm
+++ b/lib/JWebmail/Plugin/I18N2.pm
@@ -125,8 +125,10 @@ sub register {
}
}
- $app->defaults(default_language => $defaultLang);
- $app->defaults(languages => [$t->languages]);
+ $app->defaults(
+ default_language => $defaultLang,
+ languages => [$t->languages],
+ );
# add translator as helper
$app->helper(l => sub {
@@ -142,16 +144,13 @@ sub register {
return $res;
});
- # modify incoming url
- $app->hook(before_dispatch => sub {
+ # modify incoming and generated urls
+ $app->hook(before_routes => sub {
my $c = shift;
+
unshift @{ $c->req->url->path->parts }, ''
unless $t->languages($c->req->url->path->parts->[0] || '');
- });
- # modify generated url
- $app->hook(before_dispatch => sub {
- my $c = shift;
$c->match(JWebmail::Plugin::I18N2::Match->new(
root => $c->app->routes,
_i18n2_stash => $c->stash,
diff --git a/lib/JWebmail/Plugin/ServerSideSessionData.pm b/lib/JWebmail/Plugin/ServerSideSessionData.pm
index d416c00..40772eb 100644
--- a/lib/JWebmail/Plugin/ServerSideSessionData.pm
+++ b/lib/JWebmail/Plugin/ServerSideSessionData.pm
@@ -1,13 +1,13 @@
package JWebmail::Plugin::ServerSideSessionData v1.1.0;
-use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::Base Mojolicious::Plugin;
+
+use Fcntl qw(:DEFAULT :seek);
+use Time::HiRes 'sleep';
use Mojo::JSON qw(decode_json encode_json);
use Mojo::File;
-use Fcntl ':DEFAULT', ':seek';
-use Time::HiRes 'sleep';
-
use constant {
S_KEY => 's3d.key',
@@ -16,11 +16,11 @@ use constant {
ADVANCE_ON_FAILURE => 10, # seconds to retry to acquire the lock
};
+
has 'session_directory';
has 'expiration';
has 'cleanup_interval';
-
-has 'next_cleanup' => 0;
+has _next_cleanup => 0;
# read and potentially update file return bool
@@ -30,8 +30,8 @@ sub _rw_cleanup_file {
my $self = shift;
my $time = shift;
- my $lock_name = $self->session_directory->child(CLEANUP_FILE_NAME . ".lock");
- my $info_name = $self->session_directory->child(CLEANUP_FILE_NAME . ".info");
+ my $lock_name = $self->session_directory->child(CLEANUP_FILE_NAME . '.lock');
+ my $info_name = $self->session_directory->child(CLEANUP_FILE_NAME . '.info');
my ($lock, $ctr, $rmlock);
until (sysopen($lock, $lock_name, O_WRONLY | O_CREAT | O_EXCL)) {
@@ -46,7 +46,7 @@ sub _rw_cleanup_file {
$rmlock = 1;
next;
}
- $self->next_cleanup($time + ADVANCE_ON_FAILURE);
+ $self->_next_cleanup($time + ADVANCE_ON_FAILURE);
return 0;
}
sleep(0.01); # TODO: better spin locking
@@ -60,12 +60,12 @@ sub _rw_cleanup_file {
use autodie;
open(my $info, -e $info_name ? '+<' : '+>', $info_name);
- my $next_time = $info->getline;
- $next_time = 0 unless ($next_time//'') =~ /^\d+$/;
+ my $next_time = $info->getline // '';
+ $next_time = 0 unless $next_time =~ /^\d+$/a;
chomp $next_time;
if ($next_time > $time) {
$info->close;
- $self->next_cleanup($next_time);
+ $self->_next_cleanup($next_time);
return 0;
}
else {
@@ -73,7 +73,7 @@ sub _rw_cleanup_file {
$info->seek(0, SEEK_SET);
$info->say($time + $self->cleanup_interval);
$info->close;
- $self->next_cleanup($time + $self->cleanup_interval);
+ $self->_next_cleanup($time + $self->cleanup_interval);
return 1;
}
};
@@ -86,7 +86,7 @@ sub cleanup_files {
my $self = shift;
my $t = time;
- if ($self->next_cleanup < $t && $self->_rw_cleanup_file($t)) {
+ if ($self->_next_cleanup < $t && $self->_rw_cleanup_file($t)) {
for ($self->session_directory->list->each) {
if ( $_->stat->mtime + $self->expiration < $t ) {
$_->remove;
@@ -127,7 +127,7 @@ sub s3d {
$data->{$key} = $val;
$file->spurt(encode_json $data, "\n");
- return;
+ return $self;
}
else { # get
return defined $key ? $data->{$key} : $data;