diff options
-rw-r--r-- | Makefile | 89 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | config.def.mk | 11 | ||||
-rw-r--r-- | favicon.ico | bin | 9278 -> 26790 bytes | |||
-rwxr-xr-x | genpass.pl | 84 | ||||
-rwxr-xr-x | gpigeon-template.cgi | 117 | ||||
-rw-r--r-- | index.html | 29 | ||||
-rw-r--r-- | link-tmpl-template.cgi | 24 | ||||
-rw-r--r-- | nginx-example.conf | 6 | ||||
-rw-r--r-- | styles.css | 163 |
10 files changed, 390 insertions, 141 deletions
@@ -6,10 +6,35 @@ BOLD=\033[01m RED=\033[31m STOP=\033[0m -RANDOM_ARGON2 := $(shell perl genpass.pl > genpass.txt && tail -1 genpass.txt) include config.mk +RANDOM_ARGON2 := $(shell perl genpass.pl > genpass.txt && tail -1 genpass.txt) +_GPGID := $(shell gpg --with-colons -k $(MYMAIL_ADDR) | grep "pub:u" | cut -d':' -f5) gpigeon: gpigeon-template.cgi link-tmpl-template.cgi + @if test -n '$(MYMAIL_ADDR)'; then \ + printf "Your mail address is ${BOLD}$(MYMAIL_ADDR)${STOP}\n"; \ + sed -e 's|your_addr_goes_here|$(MYMAIL_ADDR)|g' link-tmpl-template.cgi > link-tmpl.cgi; \ + else \ + printf "${RED}There's no mail adress configured for gpigeon in your config.mk !${STOP}\n" ; \ + $(MAKE) clean ; \ + exit 1; \ + fi + + @if test -n '$(MAILSENDER)'; then \ + printf "Encrypted 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 '$(_GPGID)'; then \ + printf "Your GPG 0xlong id is ${BOLD}$(_GPGID)${STOP}\n";\ + sed -e 's|gpgid_goes_here|0x$(_GPGID)|g' -i link-tmpl.cgi;\ + else \ + printf "${RED}It seems that no public GPG key is tied to ${BOLD}$(MYMAIL_ADDR)${STOP}\n";\ + exit 1; \ + 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.$(STOP)\n";\ @@ -41,70 +66,40 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi fi @if test -n '$(LINK_TEMPLATE_PATH)'; then \ printf "\nLink template is at ${BOLD}$(LINK_TEMPLATE_PATH)${STOP}"; \ - sed -e 's|link_template_path_goes_here|$(LINK_TEMPLATE_PATH)|g' gpigeon-template.cgi > gpigeon.cgi; \ + 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 '$(ARGON2ID_HASH)'; then\ - printf "\nThe argon2id hash is ${BOLD}$(ARGON2ID_HASH)${STOP}"; \ - sed -e 's|argon2id_hash_goes_here|$(ARGON2ID_HASH)|g' gpigeon-template.cgi > gpigeon.cgi; \ + printf "\nThe argon2id hash is ${BOLD}${ARGON2ID_HASH}${STOP}\n"; \ + sed -e 's|argon2id_hash_goes_here|$(ARGON2ID_HASH)|g' -i gpigeon.cgi; \ else \ - sed -e 's|argon2id_hash_goes_here|$(RANDOM_ARGON2)|g' gpigeon-template.cgi > gpigeon.cgi; \ + sed -e 's|argon2id_hash_goes_here|$(RANDOM_ARGON2)|g' -i gpigeon.cgi; \ printf "\nThe variable ARGON2ID_HASH wasn't declared in your config.mk thus a password \nand its argon2id hash as been generated (look into `pwd`/genpass.txt)."; \ printf "\nYour password is:\n${BOLD}`head -1 genpass.txt`${STOP}"; \ printf "\nAnd the hash is:\n${BOLD}%s${STOP}\n\n" '${RANDOM_ARGON2}'; \ rm -f genpass.txt; \ fi - - - - @if test -n '$(MYGPG_ID_0XLONG)'; then \ - printf "Mails will be encrypted to you with the ${BOLD}$(MYGPG_ID_0XLONG)${STOP} GPG key\n"; \ - sed -e 's|gpgid_goes_here|$(MYGPG_ID_0XLONG)|g' link-tmpl-template.cgi > link-tmpl.cgi; \ - gpg --armor --export $(MYGPG_ID_0XLONG) > gpg.txt; \ - else \ - printf "${RED}No GPG key found because the 0xlong fingerprint format wasn't set in config.mk. Fix this.${STOP}\n";\ - $(MAKE) clean;\ - 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;\ + sed -e "s|msg_char_limit_goes_here|$(MSG_FORM_CHAR_LIMIT)|g" -i link-tmpl.cgi;\ else \ printf "${RED}No character limits were defined in your config.mk. Fix that.${STOP}\n" ;\ $(MAKE) clean ;\ exit 1;\ fi - @if test -n '$(MYMAIL_ADDR)'; then \ - printf "Your mail address is ${BOLD}$(MYMAIL_ADDR)${STOP}\n"; \ - sed -e 's|your_addr_goes_here|$(MYMAIL_ADDR)|g' link-tmpl-template.cgi > link-tmpl.cgi; \ - else \ - printf "There's no mail adress configured for gpigeon in your config.mk !\n" ; \ - $(MAKE) clean ; \ - exit 1; \ - fi - @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' link-tmpl-template.cgi > 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' link-tmpl-template.cgi > link-tmpl.cgi; \ + sed -e 's|sender_pw_goes_here|$(MAILSENDER_PW)|g' -i link-tmpl.cgi; \ else\ printf "\t${RED}Password for the sender address wasn't set in your config.mk. Fix this${STOP}.\n";\ $(MAKE) clean ; \ @@ -112,7 +107,7 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi fi; \ if test -n '$(SMTP_DOMAIN)'; then \ printf "\tSMTP server: ${BOLD}$(SMTP_DOMAIN)${STOP}\n"; \ - sed -e 's|smtp_domain_goes_here|$(SMTP_DOMAIN)|g' link-tmpl-template.cgi > link-tmpl.cgi; \ + sed -e 's|smtp_domain_goes_here|$(SMTP_DOMAIN)|g' -i link-tmpl.cgi; \ else\ printf "\t${RED}No SMTP server was configured in your config.mk. Fix this.${STOP}\n";\ $(MAKE) clean ; \ @@ -120,19 +115,16 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi fi; \ if test -n '$(SMTP_PORT)'; then \ printf "\tSMTP port: ${BOLD}$(SMTP_PORT)${STOP}\n"; \ - sed -e 's|smtp_port_goes_here|$(SMTP_PORT)|g' link-tmpl-template.cgi > link-tmpl.cgi; \ + sed -e 's|smtp_port_goes_here|$(SMTP_PORT)|g' -i link-tmpl.cgi; \ else \ printf "\t${RED}No SMTP port configured in your config.mk. Fix this${STOP}.\n"; \ $(MAKE) clean ; \ exit 1; \ fi; \ fi - @sed -e 's|has_mailserver_goes_here|$(HAS_MAILSERVER)|g' link-tmpl-template.cgi > link-tmpl.cgi - @sed -e 's|gpg_homedir_goes_here|$(_GPG_HOMEDIR)|g' link-tmpl-template.cgi > link-tmpl.cgi - @if test -n '$(WWWDOMAIN)' && test -n '$(WWWPREFIX)'; then\ - $(MAKE) nginxconf;\ - printf "Done generating $(WWWDOMAIN).conf for nginx.";\ - 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 + $(MAKE) nginxconf @printf "\nDone preparing files. You can now type\nsudo make install\nin your terminal.\n" install: @@ -146,13 +138,16 @@ install: install -Dm644 index.html favicon.ico styles.css -t $(DESTDIR)$(WWWPREFIX)/gpigeon/ install -Dm755 merci/* -t $(DESTDIR)$(PREFIX)/merci/ @if test -e '$(WWWDOMAIN).conf'; then\ - printf "\nInstalling $(WWWDOMAIN).conf into $(NGINXCONFDIR)\n";\ - install -Dm644 $(WWWDOMAIN).conf -t $(DESTDIR)$(NGINXCONFDIR);\ + printf "\nInstalling $(WWWDOMAIN).conf into $(SITESENABLED)\n";\ + install -Dm644 $(WWWDOMAIN).conf -t $(DESTDIR)$(SITESENABLED);\ fi chown $(WWWUSER):$(WWWUSER) -R $(DESTDIR)$(PREFIX)/gpigeon || exit 1; chown $(WWWUSER):$(WWWUSER) -R $(DESTDIR)$(WWWPREFIX)/gpigeon || exit 1; nginxconf: nginx-example.conf + @if test -n '$(WWWDOMAIN)' && test -n '$(WWWPREFIX)'; then\ + printf "Done generating $(WWWDOMAIN).conf for nginx.";\ + fi @sed -e 's|wwwpath_goes_here|$(WWWPREFIX)|g;s|domain_goes_here|$(WWWDOMAIN)|g' nginx-example.conf > $(WWWDOMAIN).conf ;\ @@ -18,7 +18,7 @@ Features - A table of the links generated is visible when you connect so you can keep track of what has been created. You can also delete link individually, or all at once. -- No javascript used for the moment. +- No javascript used at the moment. Dependencies ============ @@ -94,6 +94,12 @@ server { fastcgi_pass unix:/run/fcgiwrap.sock; include /etc/nginx/fastcgi_params; } + + add_header Strict-Transport-Security "max-age=63072000; preload"; + add_header Content-Security-Policy "default-src 'self'"; + add_header X-Frame-Options DENY; + add_header Access-Control-Allow-Origin https://$server_name; + add_header Vary Origin; # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#cors_and_caching } ``` You can also tune the `WWWDOMAIN` and `NGINXCONFDIR` variable in your `config.mk` to have it generated for you when running `make`. diff --git a/config.def.mk b/config.def.mk index b02f14f..28c435c 100644 --- a/config.def.mk +++ b/config.def.mk @@ -2,27 +2,26 @@ # paths PREFIX = /usr/share/gpigeon +WWWPREFIX = /var/www COOKIES_DIR = $(PREFIX)/cookies _GPG_HOMEDIR = $(PREFIX)/gnupg LINK_TEMPLATE_PATH = $(PREFIX)/link-tmpl.cgi -WWWPREFIX = /var/www GPIGEON_PATH = $(WWWPREFIX)/cgi-bin/gpigeon.cgi # system stuff WEBUSER=www-data #it must match up with your nginx user. For ex. on arch it's 'http' -# CGI tuning stuff +# form customization stuff MSG_FORM_CHAR_LIMIT = 3000 # argon2id hash. generated by genpass.pl if empty when running make ARGON2ID_HASH = -# gpg and email vars +# email related HAS_MAILSERVER = 0# choose 0 if you'll use an external mail server, 1 if local mail server installed. -# you don't need to set the 3 last variables if you got a local mailserver. -MYGPG_ID_0XLONG =# the 0xlong format of your gpg key. - required MYMAIL_ADDR =# your mail address - required MAILSENDER =# the mailer address that'll send you the encrypted mails - required +# you don't need to set the 3 last variables if you got a local mailserver. MAILSENDER_PW =# password for the mailer address SMTP_DOMAIN =# smtp domain pour the mailer SMTP_PORT =# smtp port for the mailer @@ -30,4 +29,4 @@ SMTP_PORT =# smtp port for the mailer #optional, domain to generate nginx config for #and where to put the config WWWDOMAIN= -NGINXCONFDIR=/etc/nginx/sites-enabled +SITESENABLED=/etc/nginx/sites-enabled diff --git a/favicon.ico b/favicon.ico Binary files differindex 83bbd77..0db8263 100644 --- a/favicon.ico +++ b/favicon.ico @@ -1,9 +1,85 @@ #! /usr/bin/perl +# genpass.pl: generate argon2id hash from a random password. Can be used +# interactively. + +# 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) 2021, Miquel Lionel <lionel@les-miquelots.net> + use warnings; use strict; +use File::Copy qw(move); use Crypt::Argon2 qw/argon2id_pass/; -my $pass = `openssl rand -base64 32`; +use Term::ReadKey; +use Term::ANSIColor qw(:constants); my $salt = `openssl rand 16`; -chomp $pass; -print $pass,"\n"; -print argon2id_pass($pass, $salt, 3, '32M', 1, 32); +my $opt = $ARGV[0]; + +sub FillConfigMk { + my $hash = shift; + $hash =~ s/\$/\\044/g; + my $mkconfig = 'config.mk'; + if (-e $mkconfig){ + open my $in, '<', $mkconfig or die "$!"; + open my $out, '>', "$mkconfig.tmp" or die "$!"; + while (<$in>){ + s/ARGON2ID_HASH =.*/ARGON2ID_HASH = `printf "$hash"`/gi; + print $out $_; + } + close $out; + close $in; + move("$mkconfig.tmp", $mkconfig) or die "Uh oh, move failed: $!"; + print "Done modifying $mkconfig\n"; + } +} + + +if (defined $opt){ + if ($opt eq '-i'){ # interactive + print "Password: "; + ReadMode 2; + my $pass = <STDIN>; + chomp $pass; + while (length($pass) < 10){ + print "\nYour password is below 10 characters. Fix this: "; + $pass = <STDIN>; + chomp $pass; + } + print "\nRetype password: "; + my $confirm = <STDIN>; + chomp $confirm; + my $same = $pass cmp $confirm; + if (not $same == 0){ + ReadMode 1; + die "\nPasswords don't match."; + } + ReadMode 1; + + print "\n\nWant to see your typed password ? [y/n] : "; + my $ynchoice = <STDIN>; + chomp $ynchoice; + if ($ynchoice eq 'y' or $ynchoice eq 'o'){ + print "\nYour password is ", BOLD, "$pass", RESET; + } + my $hash = argon2id_pass($pass, $salt, 3, '32M', 1, 32); + print "\nThe resulting argon2id hash is: ", BOLD, $hash, RESET, "\n"; + FillConfigMk($hash); + } +} +else { + my $pass = `openssl rand -base64 32`; + chomp $pass; + print $pass,"\n"; + print argon2id_pass($pass, $salt, 3, '32M', 1, 32); +} diff --git a/gpigeon-template.cgi b/gpigeon-template.cgi index 6ee79d9..e8c5036 100755 --- a/gpigeon-template.cgi +++ b/gpigeon-template.cgi @@ -1,7 +1,24 @@ #! /usr/bin/perl -T +# gpigeon.cgi: generate links for someone to send you GPG encrypted messages via a one time form. + +# 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> use warnings; use strict; +use File::Path qw(mkpath rmtree); use Crypt::Argon2 qw(argon2id_verify); use Email::Valid; use String::Random; @@ -9,60 +26,76 @@ use CGI qw(param); use CGI::Cookie; use CGI::Carp qw(fatalsToBrowser); +my $uagent = $ENV{HTTP_USER_AGENT}; +my $rIP = $ENV{REMOTE_ADDR}; +my $hostname = $ENV{'SERVER_NAME'}; + sub ValidCookie { my $client_login_cookie = shift; my $dir = shift; + my $filename = $client_login_cookie->value; + my $login_cookiefile = "$dir/$filename.txt"; + if (not defined $client_login_cookie){ return; } - my $cookie_line = undef; - my $filename = $client_login_cookie->value; if ($filename =~ /^([\w]+)$/){ $filename = $1; } else{ return; } - my $login_cookiefile = "$dir/$filename.txt"; + if (-e $login_cookiefile){ open my $in, '<', $login_cookiefile or die "can't read file: $!"; - my $cookie_line = readline $in; + $rip_line = readline $in; + $ua_line = readline $in; + $cookie_line = readline $in; close $in; + chomp ($rip_line, $ua_line); if (not defined $cookie_line){ return; } + my %magic_cookie = CGI::Cookie->parse($cookie_line) or die "$!"; + my $magic_cookie_val = $magic_cookie{'id'}->value; + + my $rip_match = $rip_line cmp $rIP; + my $ua_match = $ua_line cmp $uagent; + my $magic_match = $magic_cookie_val cmp $client_login_cookie->value; + + if ($rip_match == 0 and $ua_match == 0 and $magic_match == 0){ + return 1; + } } else{ return; } - - if ($client_login_cookie == $cookie_line){ - return 1; - } return; - } sub LoginCookieGen { my $id_cookie = shift; my $dir = shift; - my $str_rand_obj = String::Random->new; - my $val = $str_rand_obj->randregex('\w{64}'); - my $cookiefile = "$dir/$val.txt"; - my $new_login_cookie = CGI::Cookie->new( - -name => 'id', - -value => $val, - -expires => '+1y', - '-max-age' => '+1y', - -domain => ".$ENV{'SERVER_NAME'}", - -path => '/', - -secure => 1, - -httponly => 1, - -samesite => 'Strict', - ) or die "Can't create cookie: $!"; if (not defined $id_cookie){ + if (not -d "$dir"){ + mkpath("$dir") or die "$!"; + } + my $str_rand_obj = String::Random->new; + my $val = $str_rand_obj->randregex('\w{64}'); + my $cookiefile = "$dir/$val.txt"; + my $new_login_cookie = CGI::Cookie->new( + -name => 'id', + -value => $val, + -expires => '+1y', + '-max-age' => '+1y', + -domain => ".$hostname", + -path => '/', + -secure => 1, + -httponly => 1, + -samesite => 'Strict', + ) or die "Can't create cookie: $!"; open my $out, '>', $cookiefile or die "Can't write to $cookiefile: $!"; - print $out "$new_login_cookie"; + print $out "$rIP\n$uagent\n$new_login_cookie"; close $out; print "Set-Cookie: $new_login_cookie\n"; } @@ -102,7 +135,6 @@ my ($linkgen_notif, $link_asker, $mailisok_notif, $deletion_notif, my @created_links = (); delete @ENV{qw(IFS PATH CDPATH BASH_ENV)}; $ENV{'PATH'} = '/usr/bin'; -my $hostname = $ENV{'SERVER_NAME'}; my $argon2id_hash = q{argon2id_hash_goes_here}; my $cookies_dir = q{cookies_dir_goes_here}; @@ -127,7 +159,7 @@ my %text_strings = ( link_del_failed => 'Deletion failed and here is why : ', 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.' + notif_login_failure => 'Cannot login. Check if your username and password match.', refresh_btn_text => 'Refresh', type_msg_below => 'Type your message below', theader_link => 'Link', @@ -146,12 +178,13 @@ if (not defined $id_cookie){ $hidden_pwfield = qq{<input type="hidden" name="password" value="$pw">}; $refresh_form = qq{<form method="POST"> $hidden_pwfield - <input type="submit" value="$text_strings{refresh_btn_text}"> + <input id="refreshbtn" type="submit" value="$text_strings{refresh_btn_text}"> </form>}; } else{ + $hidden_pwfield = '<!-- undef -->'; $refresh_form = qq{<form method="GET"> - <input type="submit" value="$text_strings{refresh_btn_text}"> + <input id="refreshbtn" type="submit" value="$text_strings{refresh_btn_text}"> </form>}; $idval = $id_cookie->value; @@ -188,10 +221,10 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) my $pending_deletion = $cgi_query_get->param('supprlien'); my $linkfile_fn = "./l/$pending_deletion"; if (unlink UntaintCGIFilename($linkfile_fn)){ - $deletion_notif = qq{<span style="color:green">$text_strings{link_del_ok}</span>}; + $deletion_notif = qq{<span id="success">$text_strings{link_del_ok}</span>}; } else { - $deletion_notif = qq{<span style="color:red">$text_strings{link_del_failed} $linkfile_fn : $!</span>}; + $deletion_notif = qq{<span id="failure">$text_strings{link_del_failed} $linkfile_fn : $!</span>}; } } @@ -200,7 +233,7 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) while (readdir $link_dir_handle) { if ($_ ne '.' and $_ ne '..'){ unlink UntaintCGIFilename("./l/$_") or die "$!"; - $deletion_notif = qq{<span style="color:green">$text_strings{link_del_ok}</span>}; + $deletion_notif = qq{<span id="success">$text_strings{link_del_ok}</span>}; } } closedir $link_dir_handle; @@ -210,7 +243,7 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) $link_asker = scalar $cgi_query_get->param('mail'); if ( Email::Valid->address($link_asker) ){ - $mailisok_notif = qq{<span style="color:green">$text_strings{addr} $link_asker $text_strings{addr_ok}</span>}; + $mailisok_notif = qq{<span id="success">$text_strings{addr} $link_asker $text_strings{addr_ok}</span>}; my $escaped_link_asker = EscapeArobase($link_asker); my $str_rand_obj = String::Random->new; my $generated_form_filename = $str_rand_obj->randregex('\w{64}') . '.cgi'; @@ -230,10 +263,10 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) close $in or die; chmod(0755,$link_path) or die; close $out or die; - $linkgen_notif = qq{<span style="color:green">$text_strings{link_ok_for} $link_asker: </span><br><a href="$href">$href</a>}; + $linkgen_notif = qq{<span id="success">$text_strings{link_ok_for} $link_asker: </span><br><a href="$href">$href</a>}; } else{ - $mailisok_notif = qq{<span style="color:red">$text_strings{addr} $link_asker $text_strings{addr_nok}.</span>}; + $mailisok_notif = qq{<span id="failure">$text_strings{addr} $link_asker $text_strings{addr_nok}.</span>}; } } @@ -249,7 +282,7 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) } close $linkfile_handle; - if (Email::Valid->address($link_asker){ + if (Email::Valid->address($link_asker)){ push @created_links, qq{<tr> <td><a href="/cgi-bin/l/$linkfile_fn">$text_strings{here}</a></td> @@ -258,7 +291,7 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) <form method="POST"> $hidden_pwfield <input type="hidden" name="supprlien" value="$linkfile_fn"> - <input type="submit" value="$text_strings{delete_link_btn_text}"> + <input id="deletelinkbtn" type="submit" value="$text_strings{delete_link_btn_text}"> </form> </td> </tr>}; @@ -286,7 +319,7 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) <p>$text_strings{web_greet_msg}</p> <form method="GET"> <input type="hidden" name="logout" value="1"> - <input type="submit" value="$text_strings{logout_btn_text}"> + <input id="logoutbtn" type="submit" value="$text_strings{logout_btn_text}"> </form> $refresh_form <hr> @@ -295,7 +328,7 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) $hidden_pwfield $text_strings{link_asker_field_label}<br> <input tabindex="1" type="text" name="mail"> - <input tabindex="2" type="submit" value="$text_strings{create_link_btn}"> + <input id="genlinkbtn" tabindex="2" type="submit" value="$text_strings{create_link_btn}"> </form>}, NotifIfDefined($mailisok_notif), '<br>', @@ -304,14 +337,14 @@ if (ValidCookie($id_cookie, $cookies_dir) or argon2id_verify($argon2id_hash,$pw) <form method="POST"> $hidden_pwfield <input type="hidden" name="supprtout"> - <input type="submit" value="$text_strings{delete_links_btn_text}"> + <input id="deleteallbtn" type="submit" value="$text_strings{delete_links_btn_text}"> </form>}, NotifIfDefined($deletion_notif), qq{<table> <tr> - <th>$text_strings{theader_link}</th> - <th>$text_strings{theader_for}</th> - <th>$text_strings{theader_deletion}</th> + <th>$text_strings{theader_link} 🔗</th> + <th>$text_strings{theader_for} 📧</th> + <th>$text_strings{theader_deletion} 🗑</th> </tr> @created_links </table> @@ -1,19 +1,28 @@ <!DOCTYPE html> -<html> +<html lang="en"> <head> <title>GPIGEON - Login</title> - <link rel="icon" type="image/x-icon" href="/favicon.ico"> - <link rel="stylesheet" type="text/css" href="/styles.css"> <meta charset="utf-8"> + <link rel="icon" type="image/x-icon" href="/favicon.ico"> + <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> - <h1 style="text-align:center">GPIGEON</h1> - <form action="/cgi-bin/gpigeon.cgi" method="POST"> - Password : <input type="password" name="password"> - <input type="submit" value="Login"> - </form> - - <p><a href="http://git.les-miquelots.net/gpigeon" title="gpigeon download link" alt="gpigeon download link">Source code here.</a> It is similar to <a href="https://hawkpost.co/">hawkpost.co</a>.</p> + <h1>GPIGEON - Login</h1> + <form action="/cgi-bin/gpigeon.cgi" method="POST"> + <table id="loginbox"> + <tbody> + <tr> + <td>Password :</td> + <td><input type="password" name="password"></td> + </tr> + <tr id="authbtn"> + <td></td> + <td><input type="submit" value="S'authentifier"></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 href="https://hawkpost.co/">hawkpost.co</a>.</p> </body> </html> diff --git a/link-tmpl-template.cgi b/link-tmpl-template.cgi index d781252..c060131 100644 --- a/link-tmpl-template.cgi +++ b/link-tmpl-template.cgi @@ -1,6 +1,24 @@ #! /usr/bin/perl -wT my $linkuser = q{link_user}; my $linkfilename = q{link_filename}; +# 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> + use warnings; use strict; use GPG; @@ -43,9 +61,9 @@ else { if ($HAS_MAILSERVER){ use Mail::Sendmail; - my %mail = ( To => "$mymailaddr" - From => "$mailsender" - Subject => '.' + my %mail = ( To => "$mymailaddr", + From => "$mailsender", + Subject => '.', Message => "$enc_msg\n" ); sendmail(%mail) or die $Mail::Sendmail::error; diff --git a/nginx-example.conf b/nginx-example.conf index 97e5027..f3d9252 100644 --- a/nginx-example.conf +++ b/nginx-example.conf @@ -30,5 +30,11 @@ server { fastcgi_pass unix:/run/fcgiwrap.sock; include /etc/nginx/fastcgi_params; } + + add_header Strict-Transport-Security "max-age=63072000; preload"; + add_header Content-Security-Policy "default-src 'self'"; + add_header X-Frame-Options DENY; + add_header Access-Control-Allow-Origin https://$server_name; + add_header Vary Origin; # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#cors_and_caching } @@ -1,51 +1,158 @@ html{ - background-color:skyblue -} + background-color:#87CEEB +} -th{ - padding:10px; - font-size:110%; -} +body{ + font-family:sans-serif; + width:80%; + margin:auto; + font-size:12pt; +} -td{ - text-align:center; +h1, #msgbelow{ + text-align:center; +} + + +#linkstable tr th{ + padding:10px; + font-size:110%; + margin:0; +} + +#linkstable td{ + text-align:center; padding: 5px ; -} +} -input{ +#linkstable input{ padding:10px; margin:5px; margin-top:10px; } -table{ +#linkstable table{ margin-top:10px; border: 1px solid black; } -th,tr,td{ +#linkstable td{ border:1px solid black; } - -body{ - font-family:sans-serif; - width:80%; - margin:auto; - font-size:12pt; -} #msg{ - border: 1px solid black; - resize:vertical; - width:50%; + display:block; + margin-left:auto; + margin-right:auto; + border: 1px solid black; + overflow: -moz-scrollbars-none; + resize:vertical; + width:50%; + -ms-overflow-style:none; +} + + +#msg::-webkit-scrollbar { + width: 0 !important +} + +#success { + color:green; +} + +#failure { + color:red; +} + +#loginbox { + border:none; + margin-right:auto; + margin-left:auto +} + +#loginbox input { + width:100%; + padding: 5px; + line-height:25px; + +} + +#loginbox td { + text-align:right; + border:none; +} + +#loginbox tr { + border:none; +} + +#authbtn td { + text-align:center; +} + +#authbtn input { + width:100px; +} + +#mailfied { + padding: 10px +} + +#refreshbtn, #deletelinkbtn, #deleteallbtn, +#logoutbtn, #genlinkbtn, #sendbtn { + border-radius:0 + border:3px outset silver; + padding:15px; + margin:5px; +} + +#mailfield { + padding: 10px; } @media screen and (max-width: 740px) { - body { font-size:0.8em; } - #msg{width:100%;} - th, td{ padding:3px; } - input { - padding:4px; - margin: 2px; + body { + font-size:0.8em; + } + + #linkstable th,td{ + padding:3px; + } + + #linkstable input{ + padding:4px; + margin:2px; + margin-top:10px; + } + + #loginbox input{ + padding: 2px; + line-height:15px; + } + + #mailfield{ + padding: 3px; + } + + #msg { + width:50%; + margin:0; + } + + #msgbelow { + text-align:left; + } + + #refreshbtn, #deletelinkbtn, #deleteallbtn, + #logoutbtn, #genlinkbtn, #sendbtn { + padding: 8px + } + + #genlinkbtn{ + display:block + } + + #sendbtn { + display:inline } } |