diff options
author | Miquel Lionel <lionel@les-miquelots.net> | 2021-07-18 12:04:08 +0100 |
---|---|---|
committer | Miquel Lionel <lionelmiquel@sfr.fr> | 2021-07-18 16:03:51 +0100 |
commit | d55095b26b988192a209218fd00af872d9811302 (patch) | |
tree | 9b0055cc402383893696158a1e7977a9c1f7f92b | |
parent | de854ac0a8fe72a1b0d0137c351b39de25e0adfe (diff) | |
download | gpigeon-d55095b26b988192a209218fd00af872d9811302.tar.gz gpigeon-d55095b26b988192a209218fd00af872d9811302.zip |
Added file upload support and others fixes
- Added support for file upload from master branch
- Adjusted gpigeonctl.def file for BINPREFIX variable
- Did cleanup of dead variables and functions. Moved
text in their script, no need to do complicated sed.
$text_strings use is justified in gpigeon.cgi, not in
link-tmpl.cgi.
- Fixed seds in the Makefile
- Removed NotifIfDefined function, found a simpler
way for displaying/not displaying notifs.
- Removing $argon2id_hash variable. Unused and has its place
in the mono-user version of gpigeon.
-rw-r--r-- | Makefile | 146 | ||||
-rw-r--r-- | config.def.mk | 15 | ||||
-rwxr-xr-x | gpigeon-template.cgi | 117 | ||||
-rwxr-xr-x | gpigeonctl.def.pl | 2 | ||||
-rw-r--r-- | link-tmpl-template.cgi | 169 | ||||
-rw-r--r-- | styles.css | 22 |
6 files changed, 311 insertions, 160 deletions
@@ -6,71 +6,50 @@ STOP=\033[0m include config.mk gpigeon: gpigeon-template.cgi link-tmpl-template.cgi - @if test -z '$(BINPREFIX)'; then \ - printf "\n$(RED)No \u0024BINPREFIX variable defined in config.mk.\n";\ - printf "Look into config.def.mk for the defaults and fix that in your config.mk.$(STOP)\n";\ - exit 1;\ - else \ - printf "\n\u0024BINPREFIX var is set to $(BOLD)$(BINPREFIX)$(STOP)";\ - fi - @if test -z '$(PREFIX)'; then \ - printf "\n$(RED)No \u0024PREFIX variable defined in config.mk.\n";\ - printf "Look into config.def.mk for the defaults and fix that in your config.mk.$(STOP)\n";\ - exit 1;\ - else \ - printf "\n\u0024PREFIX var is set to $(BOLD)$(PREFIX)$(STOP)";\ - fi - @if test -z '$(WWWPREFIX)'; then\ - printf "\n${RED}No web directory defined in config.mk. Check your config.def.mk for the defaults and fix that in your config.mk.${STOP}";\ - exit 1; \ - else \ - printf "\nThe WWW directory is $(BOLD)$(WWWDIR)$(STOP)";\ - fi - @if test -z '$(DB_PATH)'; then\ - printf "\n${RED}No database path defined in config.mk. Check your config.def.mk for the defaults and fix that in your config.mk$(STOP)";\ - exit 1; \ - else \ - printf "\nThe path to the SQLite database is $(BOLD)$(DB_PATH)$(STOP)";\ - sed -e 's|db_path_goes_here|$(DB_PATH)|g' gpigeon-template.cgi > gpigeon.cgi;\ - fi - - @if test -n '$(_GPG_HOMEDIR)'; then \ - printf "\nThe home directory for GPG will be ${BOLD}$(_GPG_HOMEDIR)${STOP}" ;\ - else \ - printf "\n${RED}The GPG home directory for gpigeon wasn't set in config.mk . Fix that.${STOP}" ;\ - $(MAKE) clean ;\ - exit 1;\ - fi + $(MAKE) gpigeonctl; @if test -n '$(LINK_TEMPLATE_PATH)'; then \ printf "\nLink template is at ${BOLD}$(LINK_TEMPLATE_PATH)${STOP}\n"; \ - sed -e 's|link_template_path_goes_here|$(LINK_TEMPLATE_PATH)|g' -i gpigeon.cgi; \ else \ printf "\n${RED}The path for the link template wasn't set in your config.mk. Fix that.${STOP}" ;\ exit 1;\ fi + @if test -n '$(UPLOAD_TMPDIR)'; then \ + printf "\nUploaded files will be temporary stored at ${BOLD}$(UPLOAD_TMPDIR)${STOP}"; \ + else \ + printf "\n${RED}The temporary directory for uploaded files wasn't set in your config.mk. Fix that.${STOP}" ;\ + exit 1;\ + fi @if test -n '$(MSG_FORM_CHAR_LIMIT)'; then \ - printf "Message form will have a message limit of ${BOLD}$(MSG_FORM_CHAR_LIMIT) characters${STOP}\n"; \ - sed -e "s|msg_char_limit_goes_here|$(MSG_FORM_CHAR_LIMIT)|g" link-tmpl-template.cgi > link-tmpl.cgi;\ + printf "\nMessage form will have a message limit of ${BOLD}$(MSG_FORM_CHAR_LIMIT) characters${STOP}\n"; \ else \ printf "${RED}No character limits were defined in your config.mk. Fix that.${STOP}\n" ;\ $(MAKE) clean ;\ exit 1;\ fi + @if test -n '$(MAILSENDER)'; then \ + printf "Encrypted mails will be sent from ${BOLD}$(MAILSENDER)${STOP}\n"; \ + else \ + printf "${RED}No mail sender adress configured in your config.mk. Fix this.${STOP}\n" ; \ + $(MAKE) clean ; \ + exit 1; \ + fi + @sed -e 's|bin_path_goes_here|$(BINPREFIX)|g' gpigeon-template.cgi > gpigeon.cgi; + @sed -e 's|db_path_goes_here|$(DB_PATH)|g' -i gpigeon.cgi; + @sed -e 's|link_template_path_goes_here|$(LINK_TEMPLATE_PATH)|g' -i gpigeon.cgi; + @sed -e 's|cookies_dir_goes_here|$(COOKIES_DIR)|g' -i gpigeon.cgi; + @sed -e 's|bin_path_goes_here|$(BINPREFIX)|g' link-tmpl-template.cgi > link-tmpl.cgi; + @sed -e "s|msg_char_limit_goes_here|$(MSG_FORM_CHAR_LIMIT)|g" -i link-tmpl.cgi; + @sed -e 's|has_mailserver_goes_here|$(HAS_MAILSERVER)|g' -i link-tmpl.cgi; + @sed -e 's|sender_addr_goes_here|$(MAILSENDER)|g' -i link-tmpl.cgi; + @sed -e 's|gpg_homedir_goes_here|$(_GPG_HOMEDIR)|g' -i link-tmpl.cgi; + @sed -e 's|tmp_dir_goes_here|$(UPLOAD_TMPDIR)|g' -i link-tmpl.cgi; \ @if [ '${HAS_MAILSERVER}' == '1' ]; then \ printf "Local mail server setup. ${BOLD}Mail::Sendmail module will be used to send the mails${STOP}.\n"; \ else \ printf "External mail server setup. ${BOLD}Net::SMTPS module will be used to send the mails${STOP}.\n"; \ - if test -n '$(MAILSENDER)'; then \ - printf "\tEncrypted mails will be sent from ${BOLD}$(MAILSENDER)${STOP}\n"; \ - sed -e 's|sender_addr_goes_here|$(MAILSENDER)|g' -i link-tmpl.cgi; \ - else \ - printf "\t${RED}No mail sender adress configured in your config.mk. Fix this.${STOP}\n" ; \ - $(MAKE) clean ; \ - exit 1; \ - fi; \ if test -n '$(MAILSENDER_PW)'; then \ printf "\tPassword for ${BOLD}${MAILSENDER}${STOP} is %s.\n" '${MAILSENDER_PW}'; \ sed -e 's|sender_pw_goes_here|$(MAILSENDER_PW)|g' -i link-tmpl.cgi; \ @@ -96,22 +75,39 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi exit 1; \ fi; \ fi - - @sed -e 's|has_mailserver_goes_here|$(HAS_MAILSERVER)|g' -i link-tmpl.cgi; - @sed -e 's|gpg_homedir_goes_here|$(_GPG_HOMEDIR)|g' -i link-tmpl.cgi; @if test -n '$(WWWDOMAIN)' && test -n '$(WWWPREFIX)'; then\ $(MAKE) nginxconf;\ printf "Done generating $(WWWDOMAIN).conf for nginx.";\ fi + @printf "\nDone preparing files. You can now type\n\t$$ sudo make install\nin your terminal.\n" gpigeonctl: gpigeonctl.def.pl + @$(MAKE) check_cookiesdir; + @$(MAKE) check_dbpath; + @$(MAKE) check_prefixes; + @$(MAKE) check_gpghomedir; + @if test -n '$(WWWUSER)'; then \ + printf "The following UNIX user will be used for chowning and gpigeonctl: ${BOLD}$(WWWUSER)${STOP}\n"; \ + else \ + printf "\t${RED}No user configured. Check your config.mk${STOP}.\n"; \ + $(MAKE) clean ; \ + exit 1; \ + fi + @if test -n '$(WWWGROUP)'; then \ + printf "The following UNIX group will be used for chowning: ${BOLD}$(WWWGROUP)${STOP}\n"; \ + else \ + printf "\t${RED}No group configured. Check your config.mk${STOP}.\n"; \ + $(MAKE) clean ; \ + exit 1; \ + fi @sed -e 's|gpgdir_goes_here|$(_GPG_HOMEDIR)|g' gpigeonctl.def.pl > gpigeonctl; @sed -e 's|cookies_dir_goes_here|$(COOKIES_DIR)|g' -i gpigeonctl ; @sed -e 's|db_path_goes_here|$(DB_PATH)|g' -i gpigeonctl; @sed -e 's|web_user_goes_here|$(WWWUSER)|g' -i gpigeonctl; @sed -e 's|web_dir_goes_here|$(WWWDIR)|g' -i gpigeonctl; - chmod +x gpigeonctl; + @sed -e 's|bin_path_goes_here|$(BINPREFIX)|g' -i gpigeonctl; + @chmod +x gpigeonctl; install: $(MAKE) gpigeon gpigeonctl; @@ -127,6 +123,7 @@ install: install -Dm600 link-tmpl.cgi $(DESTDIR)$(LINK_TEMPLATE_PATH) install -Dm644 index.html favicon.ico styles.css -t $(DESTDIR)$(WWWDIR)/ install -Dm755 gpigeonctl -t $(DESTDIR)$(BINPREFIX) + chown $(WWWUSER):$(WWWGROUP) -R $(DESTDIR)$(GPIGEON_DIR) @printf "Done. Now execute `gpigeonctl init' to initialize the database.\n" nginxconf: nginx-example.conf @@ -135,10 +132,57 @@ nginxconf: nginx-example.conf uninstall: rm -f $(DESTDIR)$(BINPREFIX)/gpigeonctl - rm -rf $(DESTDIR)$(PREFIX)/gpigeon + rm -rf $(DESTDIR)$(GPIGEON_DIR) rm -rf $(DESTDIR)$(WWWDIR) clean: rm -f genpass.txt gpg.txt link-tmpl.cgi gpigeon.cgi $(WWWDOMAIN).conf the.db gpigeonctl +check_cookiesdir: + @if test -n '$(COOKIES_DIR)'; then \ + printf "\nThe cookies will be stored in ${BOLD}$(COOKIES_DIR)${STOP}"; \ + else \ + printf "\n${RED}No cookie directory configured. Check your config.def.mk for the defaults and fix that.${STOP}" ;\ + exit 1; \ + fi + +check_dbpath: + @if test -z '$(DB_PATH)'; then\ + printf "\n${RED}No database path defined in config.mk. Check your config.def.mk for the defaults and fix that in your config.mk$(STOP)";\ + exit 1; \ + else \ + printf "\nThe path to the SQLite database is $(BOLD)$(DB_PATH)$(STOP)";\ + fi + +check_prefixes: + @if test -z '$(PREFIX)'; then \ + printf "\n$(RED)No \u0024PREFIX variable defined in config.mk.\n";\ + printf "Look into config.def.mk for the defaults and fix that in your config.mk.$(STOP)\n";\ + exit 1;\ + else \ + printf "\n\u0024PREFIX var is set to $(BOLD)$(PREFIX)$(STOP)";\ + fi + @if test -z '$(BINPREFIX)'; then \ + printf "\n$(RED)No \u0024BINPREFIX variable defined in config.mk.\n";\ + printf "Look into config.def.mk for the defaults and fix that in your config.mk.$(STOP)\n";\ + exit 1;\ + else \ + printf "\n\u0024BINPREFIX var is set to $(BOLD)$(BINPREFIX)$(STOP)";\ + fi + @if test -z '$(WWWPREFIX)'; then\ + printf "\n${RED}No web directory defined in config.mk. Check your config.def.mk for the defaults and fix that in your config.mk.${STOP}";\ + exit 1; \ + else \ + printf "\nThe WWW directory is $(BOLD)$(WWWDIR)$(STOP)";\ + fi + +check_gpghomedir: + @if test -n '$(_GPG_HOMEDIR)'; then \ + printf "\nThe home directory for GPG will be ${BOLD}$(_GPG_HOMEDIR)${STOP}" ;\ + else \ + printf "\n${RED}The GPG home directory for gpigeon wasn't set in config.mk . Fix that.${STOP}" ;\ + $(MAKE) clean ;\ + exit 1;\ + fi + .PHONY: clean install uninstall diff --git a/config.def.mk b/config.def.mk index 931671f..f860bf3 100644 --- a/config.def.mk +++ b/config.def.mk @@ -1,20 +1,23 @@ # Customize below to fit your system # prefixes -BINPREFIX = /usr/local/bin PREFIX = /usr/share +BINPREFIX = /usr/bin WWWPREFIX = /var/www # system stuff WWWUSER = 'www-data' +WWWGROUP = 'www-data' # paths -COOKIES_DIR = $(PREFIX)/gpigeon/cookies -_GPG_HOMEDIR = $(PREFIX)/gpigeon/gnupg -WWWDIR = $(WWWPREFIX)/gpigeon -LINK_TEMPLATE_PATH = $(PREFIX)/gpigeon/link-tmpl.cgi +GPIGEON_DIR=$(PREFIX)/gpigeon +COOKIES_DIR = $(GPIGEON_DIR)/cookies +UPLOAD_TMPDIR = $(GPIGEON_DIR)/tmp/ +LINK_TEMPLATE_PATH = $(GPIGEON_DIR)/link-tmpl.cgi +DB_PATH=$(GPIGEON_DIR)/the.db +_GPG_HOMEDIR = $(GPIGEON_DIR)/gnupg GPIGEON_PATH = $(WWWDIR)/cgi-bin/gpigeon.cgi -DB_PATH=$(PREFIX)/gpigeon/the.db +WWWDIR = $(WWWPREFIX)/gpigeon # one time gpg form tuning MSG_FORM_CHAR_LIMIT = 3000 diff --git a/gpigeon-template.cgi b/gpigeon-template.cgi index 646846d..7757bcb 100755 --- a/gpigeon-template.cgi +++ b/gpigeon-template.cgi @@ -27,6 +27,8 @@ use CGI::Cookie; use CGI::Carp qw(fatalsToBrowser); use File::Path qw(mkpath rmtree); +delete @ENV{qw(IFS PATH CDPATH BASH_ENV)}; +$ENV{'PATH'} = q{bin_path_goes_here}; my $rIP = $ENV{REMOTE_ADDR}; my $uagent = $ENV{HTTP_USER_AGENT}; @@ -173,7 +175,7 @@ sub LoginCookieGen { -samesite => 'Strict', ) or die "Can't create cookie $!"; open my $out, '>', $cookiefile or die "Can't write to $cookiefile: $!"; - print $out "$rIP\n$ua\n$new_magic_cookie\n$new_userid_cookie"; + print $out "$rIP\n$uagent\n$new_magic_cookie\n$new_userid_cookie"; close $out; print "Set-Cookie: $new_magic_cookie\n"; print "Set-Cookie: $new_userid_cookie\n"; @@ -192,22 +194,9 @@ sub UntaintCGIFilename { return $filename; } -sub NotifIfDefined{ - my $notif = shift; - if (defined $notif){ - return $notif; - } - else{ - return '<!--undef notif-->'; - } -} - -delete @ENV{qw(IFS PATH CDPATH BASH_ENV)}; -$ENV{'PATH'} = '/usr/bin'; my $hostname = $ENV{'SERVER_NAME'}; my $db_path = q{db_path_goes_here}; -my $argon2id_hash = q{argon2id_hash_goes_here}; my $cookiesdir = q{cookies_dir_goes_here}; my $link_template_path = q{link_template_path_goes_here}; @@ -216,37 +205,40 @@ my %text_strings = ( addr_ok => 'is valid!', addr_nok => 'is not valid !', addr_unknown => 'Unknown', - create_link_btn => 'Generate link', + create_link_btn => 'Generate link', + cookie_problems =>'You got a cookie problem.<br> <b>Clean them and log in again</b>', delete_link_btn_text => 'Delete', delete_links_btn_text => 'Delete all links', disconnect_btn_text => 'Disconnect', logout_btn_text => 'Logout', here => 'here', + loginbtn => 'Log in', link_asker_field_label => "Asker's mail :", - link_web_title => 'One time GPG messaging form', link_del_ok => 'Successful removal !', link_legend_textarea =>'Type your message below :', - link_send_btn => 'Send', link_ok_for => 'Generated a link for', link_del_failed => 'Deletion failed and here is why : ', link_generated_ok => "Here's the link", mailto_body => 'Your link is ', mailto_subject => 'Link to your one time GPG messaging form', - notif_login_failure => 'Cannot login. Check if your username and password match.', + incorrect_ids => 'Username/password combination<br> is incorrect.<br>Try again.', + password_label => 'Password', + refresh_btn => 'Refresh', theader_link => 'Link', theader_for => 'For', - theader_deletion => 'Deletion', + theader_deletion => 'Deletion', + username_label => 'Username', web_title => 'GPIGEON.CGI: generate one time GPG messaging links !', - web_greet_msg => 'Hi and welcome.', + web_greet_msg => 'Hi and welcome. What will you do today ?', ); my $cgi_query_get = CGI->new; my $username = $cgi_query_get->param('username'); my $pass = $cgi_query_get->param('password'); my $disconnect = $cgi_query_get->param('disconnect'); -my ($linkgen_notif, $mailisok_notif, $deletion_notif, $checkedornot, - $session, $hidden_loginfield, $magic_cookie, +my ( $checkedornot, $hidden_loginfield, $magic_cookie, $uid_cookie, $idval, $refresh_form, $userid) = undef; +my $linkgen_notif = my $mailisok_notif = my $deletion_notif = my $login_notif = '<!-- undef notif -->'; my @created_links = (); my %cur_cookies = CGI::Cookie->fetch; $uid_cookie = $cur_cookies{'uid'}; @@ -259,12 +251,12 @@ if (not defined $magic_cookie){ # cookie is not set $refresh_form = qq{<form method="POST"> $hidden_loginfield - <input id="refreshbtn" type="submit" value="$text_strings{refresh_btn_text}"> + <input id="refreshbtn" type="submit" value="$text_strings{refresh_btn}"> </form>}; }else{ $hidden_loginfield = qq{<!-- undef -->}; $refresh_form = qq{<form method="GET"> - <input id="refreshbtn" type="submit" value="$text_strings{refresh_btn_text}"> + <input id="refreshbtn" type="submit" value="$text_strings{refresh_btn}"> </form>}; $idval = $magic_cookie->value; if ($idval =~ /^([\w]+)$/){ @@ -319,7 +311,6 @@ if($loginok){ $userid = $loginok; LoginCookieGen($userid, $magic_cookie, $cookiesdir); my $user_mailaddr = DbGetLine($dbh, qq{SELECT mail from pigeons where userid='$userid';}); - my $gpgid = DbGetLine($dbh, qq{SELECT gpgfp from pigeons where userid='$userid';}); my $nick = DbGetLine($dbh, qq{SELECT name from pigeons where userid='$userid';}); if (not -d "./l/$userid"){ mkpath("./l/$userid"); @@ -356,14 +347,7 @@ if($loginok){ open my $out, '>', $LINK_PATH or die "Can't write to link file: $!"; while( <$in> ) { s/{link_user}/{$link_asker}/g; - s/{gpgid_goes_here}/{$gpgid}/g; - s/{link_filename}/{$GENERATED_FORM_FILENAME}/g; - s/{user_mailaddr_goes_here}/{$user_mailaddr}/g; - s/{msg_too_long}/$text_strings{msg_too_long}/g; - s/{msg_empty}/$text_strings{msg_empty}/g; - s/{link_web_title}/$text_strings{link_web_title}/g; - s/{link_send_btn}/$text_strings{link_send_btn}/g; - s/{type_msg_below}/$text_strings{type_msg_below}/g; + s/{user_mailaddr_goes_here}/{$user_mailaddr}/g; print $out $_; } close $in or die; @@ -427,7 +411,7 @@ if($loginok){ <title>$text_strings{web_title}</title> </head> <body> - <p>$text_strings{web_greet_msg} <b>$nick</b></p> + <p>$text_strings{web_greet_msg}</p> <form method="GET"> <input type="hidden" name="disconnect" value="1"> <input id="logoutbtn" type="submit" value="$text_strings{disconnect_btn_text}"> @@ -438,20 +422,20 @@ if($loginok){ <form method="POST"> $hidden_loginfield Mail de la personne:<br> - <input id="mailfied" tabindex="1" type="text" name="mail"> + <input id="mailfield" tabindex="1" type="text" name="mail"> <input id="genlinkbtn" tabindex="2" type="submit" value="$text_strings{create_link_btn}"> - </form>}, - NotifIfDefined($mailisok_notif), - '<br>', - NotifIfDefined($linkgen_notif), - qq{<hr> + </form> + $mailisok_notif + <br> + $linkgen_notif + <hr> <form method="POST"> $hidden_loginfield <input type="hidden" name="supprtout"> <input id="deleteallbtn" type="submit" value="$text_strings{delete_links_btn_text}"> - </form>}, - NotifIfDefined($deletion_notif), - qq{<table> + </form> + $deletion_notif + <table> <tr> <th>$text_strings{theader_link} 🔗</th> <th>$text_strings{theader_for} 📧</th> @@ -464,5 +448,50 @@ if($loginok){ } else{ $dbh->disconnect; - print "Location: /\n\n"; + if (not $disconnect and defined $magic_cookie){ + $login_notif = qq{<span id="failure">$text_strings{cookie_problems}</span>}; + } + if (length($pass) > 0 or length($username) > 0){ + $login_notif = qq{<span id="failure">$text_strings{incorrect_ids}</span>}; + } + + print "Content-type: text/html\n\n", +qq{<!DOCTYPE html> +<html lang="fr"> +<head> +<meta charset="utf-8"> +<link rel="icon" type="image/x-icon" href="/favicon.ico"> +<link rel="stylesheet" type="text/css" href="/styles.css"> +<title>$text_strings{landingpage_title}</title> +</head> +<body> +<h1>$text_strings{landingpage_title}</h1> +<form action="/cgi-bin/gpigeon.cgi" method="POST"> +<table id="loginbox"> +<tbody> + <tr> + <td>$text_strings{username_label} :</td> + <td><input type="password" name="password"></td> + </tr> + <tr> + <td>$text_strings{password_label} :</td> + <td><input type="password" name="password"></td> + </tr> + <tr> + <td></td> + <td id="loginerr">$login_notif</td> + </tr> + <tr id="authbtn"> + <td></td> + <td><input type="submit" value="$text_strings{loginbtn}"></td> + </tr> +</tbody> +</table> +</form> + +<p><a href="http://git.les-miquelots.net/gpigeon" + title="gpigeon download link">Source code here.</a> It is similar to <a h> + +</body> +</html>}; } diff --git a/gpigeonctl.def.pl b/gpigeonctl.def.pl index 4585967..b7d4108 100755 --- a/gpigeonctl.def.pl +++ b/gpigeonctl.def.pl @@ -23,7 +23,7 @@ use Term::ReadKey; use Crypt::Argon2 qw(argon2id_pass); use DBI; delete @ENV{qw(IFS PATH CDPATH BASH_ENV)}; -$ENV{'PATH'} = '/usr/bin'; +$ENV{'PATH'} = q{bin_path_goes_here}; my $dbh_path = q{db_path_goes_here}; my $cookiesdir = q{cookies_dir_goes_here}; my $GNUPGHOME = q{gpgdir_goes_here}; diff --git a/link-tmpl-template.cgi b/link-tmpl-template.cgi index 5ac8dd4..3189b8f 100644 --- a/link-tmpl-template.cgi +++ b/link-tmpl-template.cgi @@ -1,24 +1,43 @@ -#! /usr/bin/perl -wT +#! /usr/bin/perl -T +# link-tmpl.cgi : self-destructing message form to send yourself GPG +# encrypted messages. Part of gpigeon. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# Copyright (c) 2020-2021, Miquel Lionel <lionel@les-miquelots.net> my $linkuser = q{link_user}; -my $linkfilename = q{link_filename}; use warnings; use strict; -use GPG; use CGI qw(param); -$ENV{'PATH'}="/usr/bin"; delete @ENV{qw(IFS PATH CDPATH BASH_ENV)}; +$ENV{'PATH'}=q{bin_path_goes_here}; +$ENV{TMPDIR}=q{tmp_dir_goes_here}; + +sub GetRFC822Date { + # https://stackoverflow.com/a/40149475, Daniel VÃrità + use POSIX qw(strftime locale_h); + my $old_locale = setlocale(LC_TIME, "C"); + my $date = strftime("%a, %d %b %Y %H:%M:%S %z", localtime(time())); + setlocale(LC_TIME, $old_locale); -sub EscapeArobase { - my $escapedmailaddress = shift; - $escapedmailaddress =~ s/@/\\@/; - return $escapedmailaddress; + return $date; } my $HAS_MAILSERVER = q{has_mailserver_goes_here}; my $msg_form_char_limit = q{msg_char_limit_goes_here}; -my $mymailaddr = q{user_mailaddr_goes_here}; -my $mymail_gpgid = q{gpgid_goes_here}; #0xlong keyid form +my $mailaddr = q{user_mailaddr_goes_here}; my $mailsender = q{sender_addr_goes_here}; my $mailsender_smtp = q{smtp_domain_goes_here}; my $mailsender_port = q{smtp_port_goes_here}; @@ -27,77 +46,113 @@ my $GPG_HOMEDIR = q{gpg_homedir_goes_here}; my $cgi_query_get = CGI->new; my $msg_form = $cgi_query_get->param('msg'); my $length_msg_form = length $msg_form; -my ($enc_msg, $error_processing_msg) = undef; +my ($smtp, $enc_msg) = undef; +my $form_error_notif = '<!-- undef notif -->'; +my $max_mb = 100; +$CGI::POST_MAX = 1024*1024*$max_mb; # 100MBytes +my $fupload_limit = $CGI::POST_MAX; if (defined $length_msg_form and $length_msg_form > $msg_form_char_limit){ - $error_processing_msg = qq{<span id="failure"><b>Cannot send message : message length must be under $msg_form_char_limit characters.</b></span>}; + $form_error_notif = qq{<span id="failure"><b>Cannot send message : message length must be under $msg_form_char_limit characters.</b></span>}; } elsif (defined $length_msg_form and $length_msg_form eq 0 ){ - $error_processing_msg = qq{<span id="failure"><b>Cannot send message : message is empty. You can type up to $msg_form_char_limit characters.</b></span>}; + $form_error_notif = qq{<span id="failure"><b>Cannot send message : message is empty. You can type up to $msg_form_char_limit characters.</b></span>}; } else { if (defined $length_msg_form and $ENV{REQUEST_METHOD} eq 'POST'){ - $msg_form =~ tr/\r//d; # if we dont do this, ^M character in plain text mail - my $gpg = new GPG(gnupg_path => "/usr/bin", homedir => $GPG_HOMEDIR); - $enc_msg = $gpg->encrypt("$linkuser:\n\n$msg_form", $mymail_gpgid) or die $gpg->error(); + $msg_form =~ tr/\r//d; # if we dont do this, ^M character in plain text mail will show up + use Mail::GPG; - if ($HAS_MAILSERVER){ - use Mail::Sendmail; - my %mail = ( To => "$mymailaddr", - From => "$mailsender", + my $gpgmail = Mail::GPG->new( + default_key_encrypt => $mailaddr, + default_key_id => $mailaddr, + gnupg_hash_init => {homedir=>$GPG_HOMEDIR}, + debug => 0, + no_strict_7bit_encoding => 1, + ); + my $rfc822date = GetRFC822Date(); + my $mimentity = MIME::Entity->build ( + Date => $rfc822date, + From => $mailsender, Subject => '.', - Message => "$enc_msg\n" - ); - sendmail(%mail) or die $Mail::Sendmail::error; - } - else { - use Net::SMTP; - use Net::SMTPS; - my $smtp = Net::SMTPS->new($mailsender_smtp, Port => $mailsender_port, doSSL => 'ssl', Debug_SSL => 0); - my $mymailaddr_escaped = EscapeArobase($mymailaddr); - my $mailsender_escaped = EscapeArobase($mailsender); - - $smtp->auth($mailsender, $mailsender_pw) or die; - $smtp->mail($mailsender) or die "Net::SMTP module has broke: $!."; - if ($smtp->to($mymailaddr)){ - $smtp->data(); - $smtp->datasend("From: $mailsender_escaped\n"); - $smtp->datasend("To: $mymailaddr_escaped\n"); - $smtp->datasend("Subject: .\n"); - $smtp->datasend("\n"); - $smtp->datasend("$enc_msg\n"); - $smtp->dataend(); + To => $mailaddr, + Data => [ "This is a message from $linkuser:\n\n$msg_form" ], + Charset => 'utf-8', + ); + + if ( my $fh = $cgi_query_get->upload('fupload') ){ + my $fullfn = $cgi_query_get->param('fupload'); + $fullfn =~ s/[^A-Za-z_0-9\.\-]/_/g; + $fullfn =~ s/__+/_/g; + my $fpath = $cgi_query_get->tmpFileName($fh) or die "can't get uploaded file name: $!"; + my $fsize = -s $fpath; + if ($fsize > $fsize_limit){ + die 'ERROR: File is too big (>100MB).'; # I don't think we'll se this error, it'll return 413 instead } - else { - die $smtp->message(); + + my $mimetype = $cgi_query_get->uploadInfo($fh)->{'Content-Type'}; + if (not $mimetype =~ /^([\w]+)\/([\w]+)$/){ + die "Unrecognized MIME type"; } + + $mimentity->attach( + Type => $mimetype, + Description => $fullfn, + Encoding => 'base64', + Path => $fpath, + Filename => $fullfn, + ) or die "can't attach file to main MIME entity: $!"; } - unlink $linkfilename; + my $encrypted_mime_blob = $gpgmail->mime_encrypt(entity => $mimentity); + my $encrypted_mime = $encrypted_mime_blob->as_string; + + use Net::SMTP; + use Net::SMTPS; + if ($HAS_MAILSERVER){ + $smtp = Net::SMTP->new(Host => 'localhost'); + } + else { + $smtp = Net::SMTPS->new($mailsender_smtp, Port => $mailsender_port, doSSL => 'ssl', Debug_SSL => 0); + $smtp->auth($mailsender, $mailsender_pw) or die "$!"; + } + + $smtp->mail($mailsender) or die "Net::SMTP module has broke: $!."; + if ($smtp->to($mailaddr)){ + $smtp->data($encrypted_mime); + $smtp->dataend(); + $smtp->quit(); + } + else { + die $smtp->message(); + } + + if ($0 =~ /([\w]+)\.cgi$/){ + unlink "$1.cgi"; + } print "Location: /merci/index.html\n\n"; } } -print "Content-type: text/html", "\n\n"; -print qq{<!DOCTYPE html> +print "Content-type: text/html", "\n\n", +qq{<!DOCTYPE html> <html> <head> <link rel="icon" sizes="48x48" type="image/ico" href="/favicon.ico"> <link rel="stylesheet" type="text/css" href="/styles.css"> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta charset="UTF-8"> - <title>{link_web_title}</title> + <title>GPIGEON - Message form</title> </head> <body> - <p id="msgbelow">{type_msg_below}:</p> - <form method="POST"> + <p id="msgbelow">Type your message below:</p> + <form method="POST" enctype="multipart/form-data"> <textarea id="msg" wrap="off" cols="50" rows="30" name="msg"></textarea><br> -}; -if (defined $error_processing_msg){ - printf $error_processing_msg; -} -printf q{ - <br> - <input id="sendbtn" type="submit" value="{link_send_btn}"> + $form_error_notif + <label for="filechoice" id="msgbelow"> + (Optional) file upload: + <input id="filechoice" type="file" name="file"> + </label> + <input id="sendbtn" type="submit" value="Send"> </form> </body> -</html> }; +</html>}; @@ -10,6 +10,7 @@ body{ } h1, #msgbelow{ + display:block; text-align:center; } @@ -40,6 +41,14 @@ h1, #msgbelow{ border:1px solid black; } +#logoutbtn { + display: inline; + float:right; + top: 0; + right: 0; + position:absolute; +} + #msg{ display:block; margin-left:auto; @@ -64,7 +73,7 @@ h1, #msgbelow{ color:red; } -#loginbox { +#loginbox #loginerr{ border:none; margin-right:auto; margin-left:auto @@ -115,6 +124,10 @@ h1, #msgbelow{ font-size:0.8em; } + h1{ + font-size:1.5em; + } + #linkstable th,td{ padding:3px; } @@ -130,6 +143,13 @@ h1, #msgbelow{ line-height:15px; } + #logoutbtn { + float:none; + top:unset; + right:unset; + position:revert; + } + #mailfield{ padding: 3px; } |