summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis M. Hoffmann <jannis@fehcom.de>2023-09-08 23:32:10 +0200
committerJannis M. Hoffmann <jannis@fehcom.de>2023-09-08 23:32:10 +0200
commit926ec7a6b85e6e3f7335a8c5ddcccd51937ee2d8 (patch)
treeb7a420a919d0146f2a0bd2e1e577b795fcb99202
parent4510e3720274865996ef056f1687997ba0b482be (diff)
added a build configuration step
-rw-r--r--MANIFEST72
-rw-r--r--MANIFEST.BIN68
-rw-r--r--MANIFEST.SKIP15
-rwxr-xr-xactions91
-rwxr-xr-xconfigure140
-rw-r--r--confninja.sh109
-rw-r--r--jwebmail.development.toml21
-rw-r--r--jwebmail.production.toml15
-rw-r--r--jwebmail.service13
-rw-r--r--jwebmail.service.tmpl15
-rw-r--r--lib/JWebmail.pm37
-rw-r--r--lib/JWebmail/Config.pm.in25
-rw-r--r--lib/JWebmail/Controller/Webmail.pm17
-rw-r--r--lib/JWebmail/Model/ReadMails/MockJSON.pm16
-rw-r--r--lib/JWebmail/Model/ReadMails/MockMaildir.pm23
-rw-r--r--lib/JWebmail/Model/ReadMails/QMailAuthuser.pm23
-rw-r--r--lib/JWebmail/Model/WriteMails.pm6
-rw-r--r--lib/JWebmail/Plugin/I18N2/Maketext.pm19
-rw-r--r--t/Webmail.t9
-rw-r--r--templates/webmail/about.html.ep1
-rw-r--r--templates/webmail/login.html.ep3
21 files changed, 510 insertions, 228 deletions
diff --git a/MANIFEST b/MANIFEST
index b5a7c96..56284c1 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,63 +1,73 @@
+b/extract.pl
+
script/jwebmail
+script/mojocookiecheck.pl
script/qmauth.pl
script/qmauth.py
-bin/jwebmail-extract
-lib/JWebmail.pm
lib/JWebmail/Controller/Webmail.pm
-lib/JWebmail/I18N.pm
lib/JWebmail/I18N/de.pm
lib/JWebmail/I18N/en.pm
-lib/JWebmail/Model/ReadMails/Role.pm
-lib/JWebmail/Model/ReadMails/MockMaildir.pm
lib/JWebmail/Model/ReadMails/MockJSON.pm
+lib/JWebmail/Model/ReadMails/MockMaildir.pm
lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
+lib/JWebmail/Model/ReadMails/Role.pm
lib/JWebmail/Model/WriteMails.pm
-lib/JWebmail/Plugin/TOMLConfig.pm
-lib/JWebmail/Plugin/I18N2.pm
-lib/JWebmail/Plugin/I18N2/Role.pm
lib/JWebmail/Plugin/I18N2/INI.pm
lib/JWebmail/Plugin/I18N2/Maketext.pm
+lib/JWebmail/Plugin/I18N2/Role.pm
+lib/JWebmail/Plugin/I18N2.pm
+lib/JWebmail/Plugin/INIConfig.pm
lib/JWebmail/Plugin/Paginate.pm
lib/JWebmail/Plugin/ServerSideSessionData.pm
+lib/JWebmail/Plugin/TOMLConfig.pm
lib/JWebmail/View/RenderMail.pm
lib/JWebmail/View/Webmail.pm
+lib/JWebmail/Config.pm.in
+lib/JWebmail/I18N.pm
+lib/JWebmail.pm
+
+scss/my_bulma.scss
+
+src/displayheaders.js
+src/login_cram.js
+src/rendermail.js
-t/Webmail.t
-t/ViewWebmail.t
-t/INI.t
t/Extract.t
-t/Pagination.t
t/I18N2.t
+t/INI.t
+t/Pagination.t
+t/ViewWebmail.t
+t/Webmail.t
-templates/webmail/readmail.html.ep
-templates/webmail/writemail.html.ep
-templates/webmail/displayheaders.html.ep
-templates/webmail/about.html.ep
-templates/webmail/login.html.ep
-templates/layouts/mainlayout.html.ep
-templates/displayheaders/_top_nav.html.ep
templates/displayheaders/_bot_nav.html.ep
templates/displayheaders/_folders.html.ep
templates/displayheaders/_main_table.html.ep
templates/displayheaders/_pagination1.html.ep
templates/displayheaders/_pagination2.html.ep
templates/displayheaders/_pagination3.html.ep
-templates/not_found.production.html.ep
+templates/displayheaders/_top_nav.html.ep
+templates/layouts/mainlayout.html.ep
+templates/webmail/about.html.ep
+templates/webmail/displayheaders.html.ep
+templates/webmail/login.html.ep
+templates/webmail/readmail.html.ep
+templates/webmail/writemail.html.ep
templates/exception_.html.ep
+templates/not_found.html.ep
-public/css/style.css
-public/src/login_cram.js
-
-jwebmail.development.toml
-
-README.md
+.editorconfig
+actions
CHANGES.md
+configure
+confninja.sh
+jwebmail.development.toml
+jwebmail.production.toml
+jwebmail.service
LICENSE
-
-actions
-jwebmail.service.tmpl
-
Makefile.PL
MANIFEST
-MANIFEST.SKIP
+MANIFEST.BIN
+package-lock.json
+package.json
+README.md
diff --git a/MANIFEST.BIN b/MANIFEST.BIN
new file mode 100644
index 0000000..58d4dc9
--- /dev/null
+++ b/MANIFEST.BIN
@@ -0,0 +1,68 @@
+b/extract.pl
+
+bin/jwebmail-extract
+
+script/jwebmail
+script/qmauth.pl
+script/qmauth.py
+
+lib/JWebmail/Controller/Webmail.pm
+lib/JWebmail/I18N/de.pm
+lib/JWebmail/I18N/en.pm
+lib/JWebmail/Model/ReadMails/MockJSON.pm
+lib/JWebmail/Model/ReadMails/MockMaildir.pm
+lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
+lib/JWebmail/Model/ReadMails/Role.pm
+lib/JWebmail/Model/WriteMails.pm
+lib/JWebmail/Plugin/I18N2/INI.pm
+lib/JWebmail/Plugin/I18N2/Maketext.pm
+lib/JWebmail/Plugin/I18N2/Role.pm
+lib/JWebmail/Plugin/I18N2.pm
+lib/JWebmail/Plugin/INIConfig.pm
+lib/JWebmail/Plugin/Paginate.pm
+lib/JWebmail/Plugin/ServerSideSessionData.pm
+lib/JWebmail/Plugin/TOMLConfig.pm
+lib/JWebmail/View/RenderMail.pm
+lib/JWebmail/View/Webmail.pm
+lib/JWebmail/Config.pm
+lib/JWebmail/I18N.pm
+lib/JWebmail.pm
+
+public/css/my_bulma.css
+public/src/displayheaders.js
+public/src/login_cram.js
+public/src/rendermail.js
+
+t/Extract.t
+t/I18N2.t
+t/INI.t
+t/Pagination.t
+t/ViewWebmail.t
+t/Webmail.t
+
+templates/displayheaders/_bot_nav.html.ep
+templates/displayheaders/_folders.html.ep
+templates/displayheaders/_main_table.html.ep
+templates/displayheaders/_pagination1.html.ep
+templates/displayheaders/_pagination2.html.ep
+templates/displayheaders/_pagination3.html.ep
+templates/displayheaders/_top_nav.html.ep
+templates/layouts/mainlayout.html.ep
+templates/webmail/about.html.ep
+templates/webmail/displayheaders.html.ep
+templates/webmail/login.html.ep
+templates/webmail/readmail.html.ep
+templates/webmail/writemail.html.ep
+templates/exception_.html.ep
+templates/not_found.html.ep
+
+actions
+CHANGES.md
+build.ninja
+jwebmail.development.toml
+jwebmail.production.toml
+jwebmail.service
+LICENSE
+Makefile.PL
+MANIFEST.BIN
+README.md
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
deleted file mode 100644
index 6036ec7..0000000
--- a/MANIFEST.SKIP
+++ /dev/null
@@ -1,15 +0,0 @@
-extract/
-log/
-.git/
-.gitignore
-.vscode/settings.json
-.mypy_cache/
-lang/
-node_modules/
-css/
-src/
-t/testdata/
-package.json
-package-lock.json
-b/extract.pl
-__pycache__
diff --git a/actions b/actions
index 487cf22..1fd405d 100755
--- a/actions
+++ b/actions
@@ -1,31 +1,32 @@
-#!/usr/bin/env sh
+#!/bin/sh
set -euC
help_text=
-help_text="$help_text install\t[]\t\n"
-install () {
- perl Makefile.PL
- make
- make test
- make install
+help_text="$help_text build\t[]\t\n"
+dev_config () {
+ ./configure -e extractrs -n cat
}
-help_text="$help_text dist\t[]\tcreate a source distribution\n"
-dist () {
- perl Makefile.PL
- make
- make test
- make dist
+help_text="$help_text unconfigure\t[]\tresets the build\n"
+unconfigure () {
+ rm -f .configured jwebmail.service lib/JWebmail/Config.pm
+}
+
+help_text="$help_text build\t[]\t\n"
+build () {
+ env PATH="node_modules/.bin/:$PATH" ninja "$@"
}
-help_text="$help_text run_tests\t[args='t/' ...]\tpasses arg to the 'prove' tool\n"
-run_tests () {
- if [ $# -gt 0 ]
- then prove -l "$@"
- else prove -l t/
+help_text="$help_text install\t[]\t\n"
+install () {
+ perl Makefile.PL
+ make
+ if readlink /bin/init | grep -q 'systemd'
+ then install -m 644 jwebmail.service /etc/systemd/system
fi
+ install -m 644 jwebmail.toml /etc
}
help_text="$help_text start_dev\t[]\tstarts a hot reloading dev server\n"
@@ -33,29 +34,26 @@ start_dev () {
morbo script/jwebmail
}
-help_text="$help_text logrotate\t[mode=development]\tarchives the current log file\n"
-logrotate () {
+help_text="$help_text logrotate_dev\t[mode=development]\tarchives the current log file\n"
+logrotate_dev () {
mode=${1:-development}
mv -i "log/$mode.log" "log/${mode}_$(date --iso-8601=minutes).log"
}
-help_text="$help_text linelength\t[[files]]\tchecks documentation files for overly long lines\n"
-linelength () {
- files=${1:-'README.md CHANGES.md LICENSE'}
+help_text="$help_text follow_log\t[mode=development]\tfollows the current log file\n"
+follow_log () {
+ mode=${1:-development}
+ tail -f "log/$mode.log"
+}
+
+help_text="$help_text release_check\t[]\t\n"
+release_check () {
+ files='README.md CHANGES.md LICENSE'
for file in $files
do
fold -s -w 85 "$file" | diff "$file" -
done
-}
-
-help_text="$help_text follow\t[mode=development]\tfollows the current log file\n"
-follow () {
- mode=${1:-development}
- tail -f "log/$mode.log"
-}
-help_text="$help_text check_manifest\t[]\tchecks if files in the MANIFEST actually exist\n"
-check_manifest () {
perl -nE 'chomp; say if $_ && !-e' MANIFEST
}
@@ -87,37 +85,10 @@ list_translations () {
fi
}
-help_text="$help_text rust_extract\t[]\tupdates and gets the rust extract binary\n"
-rust_extract () {
- cd extract
- cargo build --release --target=x86_64-unknown-linux-musl
- cp target/x86_64-unknown-linux-musl/release/jwebmail-extract ../bin
- cd ..
-}
-
-help_text="$help_text systemd_unit\t[path=/etc/systemd/system/\$JWM_NAME.service] env(JWM_{NAME,USER,HOME,LOG_LEVEL})\tcreates a systemd unit file\n"
-systemd_unit () {
- : "${JWM_NAME=jwebmail}" "${JWM_USER=$USER}" "${JWM_HOME=$(pwd)}" "${JWM_LOG_LEVEL=info}"
- export JWM_NAME JWM_USER JWM_HOME JWM_LOG_LEVEL
-
- cmd='perl -pe s/\$(\w+)/$ENV{$1}/ga jwebmail.service.tmpl'
- path=${1-/etc/systemd/system/$JWM_NAME.service}
- if [ "$path" = '-' ]
- then $cmd
- else $cmd >|"$path"
- fi
-}
-
-help_text="$help_text compile_python\t[]\tprepare python bytecode files\n"
-compile_python () {
- python3 -m compileall script/qmauth.py
-}
-
help () {
echo "The following actions are available:"
echo
- printf "$help_text" | expand -t 22,43
- echo
+ printf "$help_text\n" | expand -t 21,41
}
cmd=${1-help}
diff --git a/configure b/configure
new file mode 100755
index 0000000..6196300
--- /dev/null
+++ b/configure
@@ -0,0 +1,140 @@
+#!/bin/sh
+
+set -euC
+
+check_command () {
+ printf 'Checking for command %s ... ' "$1"
+ if command -v "$1" >/dev/null
+ then echo 'found!'
+ else echo 'not available!'; exit 1
+ fi
+}
+
+check_perl_deps () {
+ for d in "$@"
+ do
+ printf 'Checking for perl module %s ... ' "$d"
+ if perl -Ilib -e "use $d;"
+ then echo 'found!'
+ else echo 'not available!'; exit 1
+ fi
+ done
+}
+
+check_node_module () {
+ printf 'Checking for node module %s ... ' "$1"
+ if [ -d "node_modules/$1" ]
+ then echo 'found!'
+ else echo 'not available!'; exit 1
+ fi
+}
+
+check_ninja_version () {
+ ninja_file="$(mktemp -t jwm-build-XXXXXXXX)"
+ echo "ninja_required_version = $1" >>"$ninja_file"
+ printf 'Checking ninja version at least %s ... ' "$1"
+ if ninja -f "$ninja_file" >/dev/null
+ then echo 'sufficient!'
+ else echo 'inadequate!'; exit 1
+ fi
+ rm "$ninja_file"
+}
+
+detect_languages () {
+ cd lib/JWebmail/I18N
+ for l in *
+ do echo "${l%.pm}"
+ done
+}
+
+allargs="$*"
+while getopts 'c:e:hm:n:r:u:' opt
+do case $opt in
+ (e) JWM_MAILDIR_EXTRACTOR="$OPTARG";;
+ (r) JWM_READ_MODEL="$OPTARG";;
+ (m) JWM_MODE="$OPTARG";;
+ (n) JWM_SENDMAIL="$OPTARG";;
+ (u) JWM_USER="$OPTARG";;
+ (c) JWM_LOGIN_SCHEME="$OPTARG";;
+ (h)
+ t="$(printf '\t')"
+ expand -t 70 <<END
+usage: $0 configure [options...]
+
+ OPTIONS
+ FLAG ARGUMENT DEFAULT VALUES DESCRIPTION
+ -e MAILDIR_EXTRACTOR extractpy {extractpy,extractpl,extractrs}
+ -r PERL_MODULE JWebmail::Model::ReadMails::MockMaildir The read model implementation
+ -m MODE development {development,production}
+ -u USERNAME $USER $t The server runs as this user
+ -c LOGIN_SCHEME plain {plain,cram_md5} The login scheme (don't use plain unless over TLS)
+ -n PATH sendmail The path to a sendmail executable
+END
+ exit
+ ;;
+ (*) exit 2;;
+esac
+done
+shift $((OPTIND-1))
+
+: "${JWM_MAILDIR_EXTRACTOR=extractpy}" && echo "$JWM_MAILDIR_EXTRACTOR" | grep -Eq '^extract(pl|py|rs)$'
+: "${JWM_READ_MODEL=JWebmail::Model::ReadMails::MockMaildir}"
+: "${JWM_MODE=development}" && [ "$JWM_MODE" = development -o "$JWM_MODE" = production ]
+: "${JWM_USER=$USER}" && id "$JWM_USER" >/dev/null
+: "${JWM_LOGIN_SCHEME=plain}" && [ "$JWM_LOGIN_SCHEME" = plain -o "$JWM_LOGIN_SCHEME" = cram_md5 ]
+: "${JWM_SENDMAIL=sendmail}" && [ -x "$(command -v "$JWM_SENDMAIL")" ]
+
+PATH="$(pwd)/node_modules/.bin${PATH:+:$PATH}"
+
+check_command perl
+check_perl_deps v5.24
+check_command prove
+check_command morbo
+check_command hypnotoad
+check_command npm
+check_command esbuild
+check_command sass
+check_command ninja
+check_ninja_version 1.11
+
+check_perl_deps 'Mojolicious 9.31' Email::MIME Role::Tiny Class::Method::Modifiers TOML::Tiny namespace::clean
+
+check_node_module bulma
+
+if [ "$JWM_LOGIN_SCHEME" = cram_md5 ]
+then
+ check_node_module crypto-js
+ check_perl_deps Digest::HMAC_MD5
+fi
+
+case "$JWM_MAILDIR_EXTRACTOR" in
+ (extractpl)
+ [ -x "$(pwd)/script/extract.pl" ]
+ check_perl_deps Mail::Box::Maildir
+ MAILDIR_EXTRACTOR_BIN=script/extract.pl
+ ;;
+ (extractpy)
+ [ -x "$(pwd)/script/extract.py" ]
+ check_command python3
+ MAILDIR_EXTRACTOR_BIN=script/extract.py
+ ;;
+ (extractrs)
+ [ -f "$(pwd)/extract/Cargo.toml" ]
+ JWM_EXTRACTRS_DIR=extract
+ check_command cargo
+ MAILDIR_EXTRACTOR_BIN=bin/jwebmail-extract
+ ;;
+esac
+
+export SENDMAIL="$JWM_SENDMAIL"
+export LOGIN_SCHEME="$JWM_LOGIN_SCHEME"
+export CONFARGS="$allargs"
+export MAILDIR_EXTRACTOR_NAME="$JWM_MAILDIR_EXTRACTOR"
+export MAILDIR_EXTRACTOR_BIN
+export JWM_EXTRACTRS_DIR
+export JWM_READ_MODEL
+export JWM_MODE
+
+sh confninja.sh >|build.ninja
+
+perl -pe 's/@(\w+)@/$ENV{$1}/ga' lib/JWebmail/Config.pm.in >|lib/JWebmail/Config.pm
diff --git a/confninja.sh b/confninja.sh
new file mode 100644
index 0000000..f1507a0
--- /dev/null
+++ b/confninja.sh
@@ -0,0 +1,109 @@
+set -eu
+
+cat <<'END'
+# File generated by confninja.sh; DO NOT EDIT!
+
+ninja_required_version = 1.11
+
+rule cargo
+ command = cd $extractrs_dir && cargo build $rust_mode && cp $rs_bin ../bin
+ description = CARGO $out
+
+rule scss
+ command = sass --load-path=node_modules/ $scss_mode $in $out
+ description = SCSS $out
+
+rule bundle
+ command = esbuild --bundle $bundle_mode --outfile=$out $in
+ description = BUNDLE $out
+
+rule dist
+ command = tar --posix --zstd -cf $out $in
+ description = DIST $out
+
+rule cpy
+ command = cp $in $out
+ description = CPY $out
+
+rule perltest
+ command = prove -l t/
+ description = PERLTEST
+
+rule configure
+ command = ./configure $confargs
+ description = CONFIGURE
+ generator = 1
+
+build test: perltest
+END
+
+echo "confargs = $CONFARGS"
+echo "build build.ninja lib/JWebmail/Config.pm: configure configure confninja.sh lib/JWebmail/Config.pm.in MANIFEST"
+
+case "$JWM_MODE" in
+ (development)
+ echo 'bundle_mode = --sourcemap'
+ echo 'rs_bin = target/debug/jwebmail-extract'
+ ;;
+ (production)
+ echo 'bundle_mode = --minify'
+ echo 'sass_mode = --style=compress --no-source-maps'
+ echo 'rust_mode = --release --target x86_64-unknown-linux-musl'
+ echo 'rs_bin = target/x86_64-unknown-linux-musl/release/jwebmail-extract'
+ ;;
+esac
+
+case "$MAILDIR_EXTRACTOR_NAME" in
+ (extractrs)
+ echo "extractrs_dir = $JWM_EXTRACTRS_DIR"
+ printf '%s' 'build bin/jwebmail-extract: cargo'
+ FILES_RS='arguments.rs cmd.rs error.rs main.rs rfc822.rs cmd/count.rs cmd/folders.rs cmd/list.rs cmd/raw.rs'
+ for f in $FILES_RS
+ do
+ printf '%s' " \$extractrs_dir/src/$f"
+ done
+ echo
+ ;;
+esac
+
+FILES_JS='src/displayheaders.js src/login_cram.js src/rendermail.js'
+for f in $FILES_JS
+do case "$JWM_MODE" in
+ (development) echo "build public/$f | public/$f.map: bundle $f";;
+ (production) echo "build public/$f: bundle $f";;
+esac
+done
+
+FILES_CSS='my_bulma'
+for f in $FILES_CSS
+do case "$JWM_MODE" in
+ (development) echo "build public/css/$f.css | public/css/$f.css.map: scss scss/$f.scss";;
+ (production) echo "build public/css/$f.css: scss scss/$f.scss";;
+esac
+done
+
+while read f
+do [ -n "$f" ] && echo "build JWebmail-srcdist/$f: cpy $f"
+done <MANIFEST
+
+printf '%s' "build JWebmail-srcdist.tar.zstd: dist"
+while read f
+do [ -n "$f" ] && printf '%s' " JWebmail-srcdist/$f"
+done <MANIFEST
+echo
+
+#if [ "$JWM_MODE" = production ]
+#then for f in
+#do echo "build JWebmail-bindist/$f: cp $f"
+#done
+#fi
+
+while read f
+do [ -n "$f" ] && echo "build JWebmail-bindist/$f: cpy $f"
+done <MANIFEST.BIN
+
+printf '%s' "build JWebmail-bindist.tar.zstd: dist"
+while read f
+do [ -n "$f" ] && printf '%s' " JWebmail-bindist/$f"
+done <MANIFEST.BIN
+echo
diff --git a/jwebmail.development.toml b/jwebmail.development.toml
index c4aa39c..f8b670b 100644
--- a/jwebmail.development.toml
+++ b/jwebmail.development.toml
@@ -1,21 +1,8 @@
-logpath = "log/"
-
-[defaults]
-scriptadmin = "me@example.com" # for complaints / support
+admin_mail = "me@example.com" # for complaints / support
[i18n]
default_language = "en"
-directory = "lib/JWebmail/I18N"
-# languages = ["en", "de"]
-
-[model.read.devel]
-driver = "JWebmail::Model::ReadMails::MockMaildir"
-#driver = "JWebmail::Model::ReadMails::MockJSON"
-
-[model.write]
-#sendmail = "/usr/sbin/sendmail"
-devel.block_writes = 1
-[session]
-# secure sesssion [none, cram, s3d]
-secure = "cram"
+[model.read]
+virtual_user = 'jmhoffmann'
+mailbox_path = 't/testdata'
diff --git a/jwebmail.production.toml b/jwebmail.production.toml
new file mode 100644
index 0000000..b18fbaf
--- /dev/null
+++ b/jwebmail.production.toml
@@ -0,0 +1,15 @@
+secret = "S3CR3T"
+
+admin_mail = "test@example.org"
+
+[i18n]
+default_language = "en"
+
+[model.read]
+virtual_user = netfehcom
+mailbox_path = /home/netfehcom/users
+
+[hypnotoad]
+proxy = 1
+pid_file = /run/jwebmail/hypnotoad.pid
+listen = ["http://127.0.0.1:8081"]
diff --git a/jwebmail.service b/jwebmail.service
new file mode 100644
index 0000000..9c52ac1
--- /dev/null
+++ b/jwebmail.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=JWebmail managed by hypnotoad
+After=network.target
+
+[Service]
+Type=exec
+ExecStart=/usr/bin/hypnotoad -f jwebmail
+ExecReload=/usr/bin/hypnotoad -f jwebmail
+PIDFile=/run/jwebmail/hypnotoad.pid
+Environment=MOJO_LOG_SHORT=1
+
+[Install]
+WantedBy=multi-user.target
diff --git a/jwebmail.service.tmpl b/jwebmail.service.tmpl
deleted file mode 100644
index bbd7e39..0000000
--- a/jwebmail.service.tmpl
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=JWebmail managed by hypnotoad
-After=network.target
-
-[Service]
-Type=exec
-User=$JWM_USER
-ExecStart=/usr/bin/hypnotoad -f $JWM_HOME/script/jwebmail
-ExecReload=/usr/bin/hypnotoad -f $JWM_HOME/script/jwebmail
-PIDFile=$JWM_HOME/script/hypnotoad.pid
-WorkingDirectory=$JWM_HOME
-Environment=MOJO_LOG_LEVEL=$JWM_LOG_LEVEL MOJO_LOG_SHORT=1
-
-[Install]
-WantedBy=multi-user.target
diff --git a/lib/JWebmail.pm b/lib/JWebmail.pm
index e2c291c..993ad59 100644
--- a/lib/JWebmail.pm
+++ b/lib/JWebmail.pm
@@ -8,6 +8,7 @@ use JWebmail::Controller::Webmail;
use JWebmail::Model::ReadMails::Role;
use JWebmail::Model::ReadMails::QMailAuthuser;
use JWebmail::Model::WriteMails;
+use JWebmail::Config qw'LOGIN_SCHEME MAILDIR_READER';
sub validateConf {
@@ -15,11 +16,16 @@ sub validateConf {
my $conf = $self->config;
- exists $conf->{session}{secure} or die;
- grep(sub { $_ eq $conf->{session}{secure} }, qw(none cram s3d)) > 0 or die;
+ exists $conf->{admin_mail} or die;
+ $conf->{admin_mail} =~ /@/ or die;
- exists $conf->{defaults}{scriptadmin} or die;
- $conf->{defaults}{scriptadmin} =~ /@/ or die;
+ exists $conf->{i18n}{default_language} or die;
+ $conf->{i18n}{default_language} =~ /^[\w_]+$/a or die;
+
+ exists $conf->{model}{read}{virtual_user} or die;
+ getpwnam $conf->{model}{read}{virtual_user} or die;
+ exists $conf->{model}{read}{mailbox_path} or die;
+ -d $conf->{model}{read}{mailbox_path} or die;
return 1;
}
@@ -36,11 +42,7 @@ sub startup {
$self->plugin('TOMLConfig');
$self->validateConf;
- if (my $logpath = $self->config('logpath')) {
- $self->log->path($logpath . '/' . $self->mode . '.log');
- }
-
- if (fc $self->config->{session}{secure} eq fc 's3d') {
+ if (fc LOGIN_SCHEME eq fc 's3d') {
$self->plugin('ServerSideSessionData');
}
$self->plugin('Paginate');
@@ -51,23 +53,14 @@ sub startup {
# initialize models
my $read_mails = do {
- if ($self->mode eq 'development') {
- my $cls = $self->config->{model}{read}{devel}{driver};
- eval { load $cls; 1 } || die "Issue for module $cls with: $@";
- $cls->new(($self->config->{model}{read}{devel} // {})->%*)
- }
- else {
- JWebmail::Model::ReadMails::QMailAuthuser->new(
- ($self->config->{model}{read}{prod} // {})->%*
- )
- }
+ my $cls = MAILDIR_READER;
+ eval { load $cls; 1 } || die "Issue for module $cls with: $@";
+ $cls->new(($self->config->{model}{read} // {})->%*)
};
die "given class @{[ ref $read_mails ]} does not ReadMails"
unless $read_mails->DOES('JWebmail::Model::ReadMails::Role');
$self->helper(users => sub { $read_mails });
$self->helper(send_mail => sub { my ($c, $mail) = @_; JWebmail::Model::WriteMails::sendmail($mail) });
- $JWebmail::Model::WriteMails::Block_Writes = 1
- if $self->mode eq 'development' && $self->config->{model}{write}{devel}{block_writes};
$self->validator->add_check(mail_line => \&_mail_line);
$self->validator->add_filter(non_empty_ul => \&_filter_empty_upload);
@@ -149,7 +142,7 @@ JWebmail - Provides a web based e-mail client meant to be used with s/qmail.
hypnotoad script/jwebmail
-And use a server in reverse proxy configuration.
+And use a server in reverse proxy configuration.
=head1 DESCRIPTION
diff --git a/lib/JWebmail/Config.pm.in b/lib/JWebmail/Config.pm.in
new file mode 100644
index 0000000..e91f933
--- /dev/null
+++ b/lib/JWebmail/Config.pm.in
@@ -0,0 +1,25 @@
+package JWebmail::Config;
+
+use v5.24;
+use warnings;
+use utf8;
+
+use Exporter 'import';
+our @EXPORT_OK = qw(MAILDIR_READER MAILDIR_EXTRACTOR SENDMAIL LOGIN_SCHEME);
+
+use constant {
+ MAILDIR_READER => '@JWM_READ_MODEL@',
+ MAILDIR_EXTRACTOR => '@MAILDIR_EXTRACTOR_BIN@',
+ SENDMAIL => '@SENDMAIL@',
+ LOGIN_SCHEME => fc '@LOGIN_SCHEME@',
+};
+
+1
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+JWebmail::Config - Fixed configuration parameters
diff --git a/lib/JWebmail/Controller/Webmail.pm b/lib/JWebmail/Controller/Webmail.pm
index e06a8f7..94df668 100644
--- a/lib/JWebmail/Controller/Webmail.pm
+++ b/lib/JWebmail/Controller/Webmail.pm
@@ -8,6 +8,7 @@ use List::Util qw(any first);
use Mojo::Util qw(encode decode b64_encode b64_decode);
use Mojolicious::Types;
+use JWebmail::Config 'LOGIN_SCHEME';
use JWebmail::View::Webmail;
use JWebmail::View::RenderMail;
@@ -72,7 +73,7 @@ sub _time :prototype(&$$) {
sub login {
my $self = shift;
- my $uses_cram = $self->config->{session}{secure} eq 'cram';
+ my $uses_cram = LOGIN_SCHEME eq fc 'cram_md5';
my $v = $self->validation;
@@ -338,12 +339,12 @@ sub _rand_data {
sub _session_passwd {
my ($self, $passwd, $challenge) = @_;
- my $secAlg = $self->config->{session}{secure};
+ my $secAlg = LOGIN_SCHEME;
$self->_warn_crypt;
if (defined $passwd) { # set
- if ($secAlg eq 'cram') {
+ if ($secAlg eq fc 'cram_md5') {
$self->session(S_PASSWD() => $passwd, challenge => $challenge);
}
elsif ($secAlg eq 's3d') {
@@ -352,7 +353,7 @@ sub _session_passwd {
delete $self->session->{S_OTP_S3D_PW()};
return;
}
- die "'$passwd' contains invalid character \\n" if $passwd =~ /\n/;
+ die "'$passwd' contains invalid character \\n" if $passwd =~ /\n/;
if (length $passwd < 20) {
$passwd .= "\n" . ' ' x (20 - length($passwd) - 1);
}
@@ -366,7 +367,7 @@ sub _session_passwd {
}
}
else { # get
- if ($secAlg eq 'cram') {
+ if ($secAlg eq fc 'cram_md5') {
wantarray or carp "you forgot the challenge";
return ($self->session(S_PASSWD), $self->session('challenge'));
}
@@ -472,18 +473,18 @@ Currently the following modes are supported:
=over 6
-=item none
+=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
+=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
+=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.
diff --git a/lib/JWebmail/Model/ReadMails/MockJSON.pm b/lib/JWebmail/Model/ReadMails/MockJSON.pm
index 64d6873..9ad5f09 100644
--- a/lib/JWebmail/Model/ReadMails/MockJSON.pm
+++ b/lib/JWebmail/Model/ReadMails/MockJSON.pm
@@ -21,14 +21,12 @@ use constant {
with 'JWebmail::Model::ReadMails::Role';
-sub new { bless {}, shift }
+sub new { bless {%$_[1]}, shift }
sub _read_json_file {
- my ($file_name) = @_;
+ my ($self, $file_name) = @_;
- use constant PREFIX => 't/testdata/json/';
-
- open my $body_file, '<', PREFIX . $file_name;
+ open my $body_file, '<', $self->{mailbox_path} . '/' . $file_name;
local $/;
my $body = <$body_file>;
close $body_file;
@@ -37,13 +35,15 @@ sub _read_json_file {
}
sub list_reply {
- state $init = _read_json_file('msgs.json');
+ my $self = shift;
+ state $init = _read_json_file($self, 'msgs.json');
}
sub read_reply {
+ my $self = shift;
state $init = {
- 'SC-ORD-MAIL54526c63b751646618a793be3f8329cca@sc-ord-mail5' => _read_json_file('msg2.json'),
- 'example' => _read_json_file('msg.json'),
+ 'SC-ORD-MAIL54526c63b751646618a793be3f8329cca@sc-ord-mail5' => _read_json_file($self, 'msg2.json'),
+ 'example' => _read_json_file($self, 'msg.json'),
};
}
diff --git a/lib/JWebmail/Model/ReadMails/MockMaildir.pm b/lib/JWebmail/Model/ReadMails/MockMaildir.pm
index fc9cc4a..f9d530f 100644
--- a/lib/JWebmail/Model/ReadMails/MockMaildir.pm
+++ b/lib/JWebmail/Model/ReadMails/MockMaildir.pm
@@ -4,35 +4,26 @@ use Mojo::Base 'JWebmail::Model::ReadMails::QMailAuthuser';
use Mojo::JSON 'decode_json';
-use Digest::HMAC_MD5 'hmac_md5_hex';
+use JWebmail::Config 'LOGIN_SCHEME';
+if (LOGIN_SCHEME eq fc 'cram_md5') {
+ require Digest::HMAC_MD5;
+ Digest::HMAC_MD5->import('hmac_md5_hex');
+}
use constant {
VALID_USER => 'mockmaildir@example.org',
VALID_PW => '12345',
};
-has user => sub { $ENV{USER} };
-has maildir => 't/testdata/';
-has extractor => 'python';
-
-our %EXTRACTORS = (
- perl => 'script/qmauth.pl',
- python => 'script/qmauth.py',
- rust => 'bin/jwebmail-extract',
-);
-
sub new {
my $cls = shift;
my %args = @_ == 1 ? %$_[0] : @_;
my $self = bless {%args}, ref $cls || $cls;
- $self->user;
- $self->maildir;
- $self->next::method(prog => $EXTRACTORS{$self->extractor});
- return $self;
+ return $self->next::method();
}
@@ -56,7 +47,7 @@ sub start_qmauth {
my ($auth, $mode, $args) = @_;
my $mail_user = 'maildir';
- my @exec = ($EXTRACTORS{$self->extractor}, $self->maildir, $self->user, $mail_user, $mode, @$args);
+ my @exec = ($self->{prog}, $self->{mailbox_path}, $self->{virtual_user}, $mail_user, $mode, @$args);
my $pid = open(my $reader, '-|', @exec)
or die "failed to create subprocess: $!";
diff --git a/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm b/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
index 19f8b12..b2015aa 100644
--- a/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
+++ b/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
@@ -1,10 +1,9 @@
package JWebmail::Model::ReadMails::QMailAuthuser;
-use v5.22;
+use v5.24;
use warnings;
use utf8;
-use File::Basename 'fileparse';
use IPC::Open2;
use JSON::PP 'decode_json';
use Params::Check 'check';
@@ -12,6 +11,8 @@ use Role::Tiny::With;
use Scalar::Util 'blessed';
use namespace::clean;
+use JWebmail::Config 'MAILDIR_EXTRACTOR';
+
with 'JWebmail::Model::ReadMails::Role';
@@ -73,12 +74,9 @@ package JWebmail::Model::ReadMails::QMailAuthuser::Error {
my $QMailAuthuserCheck = {
- user => {required => 1},
- maildir => {required => 1},
- prog => {required => 1},
- prefix => {default => ''},
- qmail_dir => {default => '/var/qmail/'},
- logfile => {default => '/dev/null'},
+ virtual_user => {required => 1},
+ mailbox_path => {required => 1},
+ qmail_dir => {default => '/var/qmail/'},
};
sub new {
@@ -94,6 +92,7 @@ sub new {
local $Params::Check::WARNINGS_FATAL = 1;
my $s = check($QMailAuthuserCheck, $self)
or die __PACKAGE__ . " creation failed!";
+ $s->{prog} = MAILDIR_EXTRACTOR;
return bless $s, $cls;
}
@@ -180,11 +179,9 @@ sub build_arg {
my ($user_name) = $user_mail_addr =~ /(\w*)@/;
- return $self->{qmail_dir}.'/bin/qmail-authuser'
- . $self->{prefix} . ' '
- . join(' ', map { my $x = s/(['\\])/\\$1/gr; "'$x'" } ($self->{prog}, $self->{maildir}, $self->{user}, $user_name, $mode, @$args))
- . ' 3<&0'
- . ' 2>>'.$self->{logfile};
+ return $self->{qmail_dir}.'/bin/qmail-authuser '
+ . join(' ', map { my $x = s/(['\\])/\\$1/gr; "'$x'" } ($self->{prog}, $self->{mailbox_path}, $self->{virtual_user}, $user_name, $mode, @$args))
+ . ' 3<&0';
}
sub start_qmauth {
diff --git a/lib/JWebmail/Model/WriteMails.pm b/lib/JWebmail/Model/WriteMails.pm
index 05c4cd1..751192a 100644
--- a/lib/JWebmail/Model/WriteMails.pm
+++ b/lib/JWebmail/Model/WriteMails.pm
@@ -1,9 +1,11 @@
package JWebmail::Model::WriteMails;
-use v5.18;
+use v5.24;
use warnings;
use utf8;
+use JWebmail::Config 'SENDMAIL';
+
use Exporter 'import';
our @EXPORT_OK = qw(sendmail);
@@ -51,7 +53,7 @@ sub _build_mail {
sub _send {
my ($mime, @recipients) = @_;
- open(my $m, '|-', 'sendmail', '-i', @recipients)
+ open(my $m, '|-', SENDMAIL, '-i', @recipients)
or die 'Connecting to sendmail failed. Is it in your PATH?';
$m->print($mime->as_string());
close($m);
diff --git a/lib/JWebmail/Plugin/I18N2/Maketext.pm b/lib/JWebmail/Plugin/I18N2/Maketext.pm
index ef3b08d..1046a99 100644
--- a/lib/JWebmail/Plugin/I18N2/Maketext.pm
+++ b/lib/JWebmail/Plugin/I18N2/Maketext.pm
@@ -1,12 +1,12 @@
package JWebmail::Plugin::I18N2::Maketext;
-use v5.22;
+use v5.24;
use warnings;
use utf8;
use JWebmail::I18N;
-use File::Basename 'fileparse';
+use Mojo::File qw(path curfile);
use Role::Tiny::With;
with 'JWebmail::Plugin::I18N2::Role';
@@ -16,19 +16,10 @@ sub new {
my $class = shift;
my $conf = @_ == 1 ? shift : {@_};
- my $lexica = $conf->{directory};
+ my $lexica = curfile->dirname->child('..', '..', 'I18N');
- my @languages = keys %{$conf->{languages} // {}};
-
- unless (@languages) {
- use autodie;
-
- opendir(my $dh, $lexica);
- my @res = grep { /\.pm$/ && -f "$lexica/$_" } readdir $dh;
- closedir($dh);
- @languages = map { scalar fileparse $_, '.pm' } @res;
- @languages = map { my ($l, $c) = split '_', $_, 2; $c ? "$l-\U$c" : $l } @languages;
- }
+ my $res = $lexica->list()->map('basename', '.pm');
+ my @languages = map { my ($l, $c) = split '_', $_, 2; $c ? "$l-\U$c" : $l } @$res;
if (my $dl = $conf->{default_language}) { push @languages, $dl; };
my $self = {};
diff --git a/t/Webmail.t b/t/Webmail.t
index 3deb547..c88b31a 100644
--- a/t/Webmail.t
+++ b/t/Webmail.t
@@ -14,12 +14,11 @@ my $pw = JWebmail::Model::ReadMails::MockJSON::VALID_PW;
my $t = Test::Mojo->new('JWebmail', {
- model => { read => { devel => { driver => 'JWebmail::Model::ReadMails::MockJSON' }},
- write => { devel => { block_writes => 1 }}},
- i18n => { default_language => DEFAULT_LANGUAGE, directory => 'lib/JWebmail/I18N' },
- session => { secure => 'none' },
- defaults => { scriptadmin => 'test@example.org' },
+ model => { read => { virtual_user => $ENV{USER}, mailbox_path => 't/testdata/json' }},
+ i18n => { default_language => DEFAULT_LANGUAGE },
+ admin_mail => 'test@example.org',
});
+$t->app->helper(users => sub { state $read = 'JWebmail::Model::ReadMails::MockJSON'->new($t->app->config->{model}{read}) });
$t->get_ok('/')->status_is(200);
diff --git a/templates/webmail/about.html.ep b/templates/webmail/about.html.ep
index a5cd4a7..15e35ab 100644
--- a/templates/webmail/about.html.ep
+++ b/templates/webmail/about.html.ep
@@ -38,7 +38,6 @@
and currently maintained by
<a href="mailto:jannis@fehcom.de">Jannis M. Hoffmann</a>
</p>
-
<p>
<h3>Supported languages</h3>
diff --git a/templates/webmail/login.html.ep b/templates/webmail/login.html.ep
index 54ab40a..378ac05 100644
--- a/templates/webmail/login.html.ep
+++ b/templates/webmail/login.html.ep
@@ -1,6 +1,7 @@
% layout 'mainlayout';
-% my $uses_cram = config->{session}{secure} eq 'cram';
+% use JWebmail::Config;
+% my $uses_cram = JWebmail::Config::LOGIN_SCHEME eq fc 'cram_md5';
<section class=section>
<div class="container is-max-desktop box">