aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Lionel <lionel@les-miquelots.net>2021-07-02 12:09:24 +0100
committerMiquel Lionel <lionelmiquel@sfr.fr>2021-07-04 00:28:00 +0100
commit2137a587bb3a314ac13327d4cdb53f0ee8b9d970 (patch)
treecea28ad0f1b4782a5eea556f5346f712108d1c6e
parent23c6d4753895870224209a44624c1350e934f762 (diff)
downloadgpigeon-2137a587bb3a314ac13327d4cdb53f0ee8b9d970.tar.gz
gpigeon-2137a587bb3a314ac13327d4cdb53f0ee8b9d970.zip
Better way to validate cookies and others improvs
- Added GPLv3+ short header in source files (genpass.pl, gpigeon-template.cgi and link-template-tmpl.cgi). - Added some security headers in the example nginx configuration file, and renamed the NGINXCONFDIR variable in the Makefile to SITESENABLED, it makes a bit more sense. - Hastily drawed a more fitting .ico/mascot for the project - Tweaked the styles.css to be somewhat more responsive. Some tags in index.html and gpigeon-template.cgi and link-template-tmpl.cgi have now an id for styling. - Fixed and improved cookie validation. While working on the multi-user alternative, I noticed that the ValidCookies() function was flimsy, I was used eq... I learned about 'cmp' and throwed some UA and IP address match to make it a bit more robust. - Improved the genpass.pl script, if you want a argon2id of your password, you can now launch it in interactive mode with the '-i' arg. It'll fill the ARGON2ID_HASH variable in the existing config.mk with the hash of the provided password - Fixed inconsistencies in the Makefile. I was overwriting changes with sed for no good reason instead of using the -i switch ! I also moved the mail address, mail sender, and gpg id checks to the top of the file since they are the most important. Also, the 0xlong is not needed in config.def.mk anymore, we extract via the mail address.
-rw-r--r--Makefile89
-rw-r--r--README.md8
-rw-r--r--config.def.mk11
-rw-r--r--favicon.icobin9278 -> 26790 bytes
-rwxr-xr-xgenpass.pl84
-rwxr-xr-xgpigeon-template.cgi117
-rw-r--r--index.html29
-rw-r--r--link-tmpl-template.cgi24
-rw-r--r--nginx-example.conf6
-rw-r--r--styles.css163
10 files changed, 390 insertions, 141 deletions
diff --git a/Makefile b/Makefile
index 24b9489..000e898 100644
--- a/Makefile
+++ b/Makefile
@@ -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 ;\
diff --git a/README.md b/README.md
index 9a27592..8be7b9a 100644
--- a/README.md
+++ b/README.md
@@ -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
index 83bbd77..0db8263 100644
--- a/favicon.ico
+++ b/favicon.ico
Binary files differ
diff --git a/genpass.pl b/genpass.pl
index 44b0f53..a57d98b 100755
--- a/genpass.pl
+++ b/genpass.pl
@@ -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} &#128279;</th>
+ <th>$text_strings{theader_for} &#128231;</th>
+ <th>$text_strings{theader_deletion} &#128465;</th>
</tr>
@created_links
</table>
diff --git a/index.html b/index.html
index b88c8a0..e5f3e13 100644
--- a/index.html
+++ b/index.html
@@ -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
}
diff --git a/styles.css b/styles.css
index a83cd47..7f8770d 100644
--- a/styles.css
+++ b/styles.css
@@ -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
}
}