diff options
-rw-r--r-- | Makefile | 162 | ||||
-rw-r--r-- | config.def.mk | 1 | ||||
-rwxr-xr-x | gpigeon-template.cgi | 233 | ||||
-rwxr-xr-x | gpigeonctl.def.pl | 163 | ||||
-rwxr-xr-x | invites-tmpl-template.cgi | 282 | ||||
-rw-r--r-- | link-tmpl-template.cgi | 2 | ||||
-rw-r--r-- | styles.css | 310 |
7 files changed, 806 insertions, 347 deletions
@@ -2,11 +2,57 @@ BOLD=\033[01m RED=\033[31m +UDRL=\033[4m STOP=\033[0m include config.mk -gpigeon: gpigeon-template.cgi link-tmpl-template.cgi - $(MAKE) gpigeonctl; +gpigeon: gpigeon-template.cgi link-tmpl-template.cgi invites-tmpl-template.cgi + @if test -z '$(PREFIX)'; then \ + printf "\n$(RED)No $(BOLD)\u0024PREFIX$(STOP)$(RED) 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$(UDRL)\u0024PREFIX$(STOP) var is set to $(BOLD)$(PREFIX)$(STOP)";\ + fi + @if test -z '$(BINPREFIX)'; then \ + printf "\n$(RED)No $(BOLD)\u0024BINPREFIX$(STOP)$(RED) 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$(UDRL)\u0024BINPREFIX$(STOP) 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 + @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 + @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 + @if test -n '$(TEST_GPG_HOMEDIR)'; then \ + printf "\nThe home directory for GPG tests will be ${BOLD}$(TEST_GPG_HOMEDIR)${STOP}" ;\ + else \ + printf "\n${RED}The GPG tests home directory for gpigeon wasn't set in config.mk . Fix that.${STOP}" ;\ + $(MAKE) clean ;\ + exit 1;\ + 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)";\ + fi @if test -n '$(LINK_TEMPLATE_PATH)'; then \ printf "\nLink template is at ${BOLD}$(LINK_TEMPLATE_PATH)${STOP}\n"; \ @@ -20,7 +66,26 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi 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 '$(WWWUSER)'; then \ + printf "\nThe 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; + @sed -e 's|bin_path_goes_here|$(BINPREFIX)|g' -i gpigeonctl; @if test -n '$(MSG_FORM_CHAR_LIMIT)'; then \ printf "\nMessage form will have a message limit of ${BOLD}$(MSG_FORM_CHAR_LIMIT) characters${STOP}\n"; \ else \ @@ -37,13 +102,16 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi 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|db_path_goes_here|$(DB_PATH)|g' invites-tmpl-template.cgi > invites-tmpl.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|bin_path_goes_here|$(BINPREFIX)|g' -i invites-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|has_mailserver_goes_here|$(HAS_MAILSERVER)|g' -i link-tmpl.cgi invites-tmpl.cgi; + @sed -e 's|sender_addr_goes_here|$(MAILSENDER)|g' -i link-tmpl.cgi invites-tmpl.cgi; + @sed -e 's|gpg_homedir_goes_here|$(_GPG_HOMEDIR)|g' -i link-tmpl.cgi invites-tmpl.cgi; + @sed -e 's|test_gpgdir_goes_here|$(TEST_GPG_HOMEDIR)|g' -i link-tmpl.cgi invites-tmpl.cgi; @sed -e 's|tmp_dir_goes_here|$(UPLOAD_TMPDIR)|g' -i link-tmpl.cgi; \ @if [ '${HAS_MAILSERVER}' == '1' ]; then \ @@ -52,7 +120,7 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi printf "External mail server setup. ${BOLD}Net::SMTPS module will be used to send the mails${STOP}.\n"; \ 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; \ + sed -e 's|sender_pw_goes_here|$(MAILSENDER_PW)|g' -i link-tmpl.cgi invites-tmpl.cgi; \ else\ printf "\t${RED}Password for the sender address wasn't set in your config.mk. Fix this${STOP}.\n";\ $(MAKE) clean ; \ @@ -60,7 +128,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' -i link-tmpl.cgi; \ + sed -e 's|smtp_domain_goes_here|$(SMTP_DOMAIN)|g' -i link-tmpl.cgi invites-tmpl.cgi; \ else\ printf "\t${RED}No SMTP server was configured in your config.mk. Fix this.${STOP}\n";\ $(MAKE) clean ; \ @@ -68,7 +136,7 @@ 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' -i link-tmpl.cgi; \ + sed -e 's|smtp_port_goes_here|$(SMTP_PORT)|g' -i link-tmpl.cgi invites-tmpl.cgi; \ else \ printf "\t${RED}No SMTP port configured in your config.mk. Fix this${STOP}.\n"; \ $(MAKE) clean ; \ @@ -80,37 +148,12 @@ gpigeon: gpigeon-template.cgi link-tmpl-template.cgi 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" + @printf "\nDone preparing files. You can now type\n\t$$ sudo make install\nin your terminal.\n\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; - @sed -e 's|bin_path_goes_here|$(BINPREFIX)|g' -i gpigeonctl; - @chmod +x gpigeonctl; install: - $(MAKE) gpigeon gpigeonctl; + $(MAKE) gpigeon; @if test -n "$(WWWDOMAIN)"; then\ $(MAKE) nginxconf;\ printf "\nInstalling $(WWWDOMAIN).conf into $(NGINXCONFDIR)\n";\ @@ -138,51 +181,4 @@ uninstall: 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 f860bf3..15ec910 100644 --- a/config.def.mk +++ b/config.def.mk @@ -14,6 +14,7 @@ GPIGEON_DIR=$(PREFIX)/gpigeon COOKIES_DIR = $(GPIGEON_DIR)/cookies UPLOAD_TMPDIR = $(GPIGEON_DIR)/tmp/ LINK_TEMPLATE_PATH = $(GPIGEON_DIR)/link-tmpl.cgi +INVITE_TEMPLATE_PATH = $(GPIGEON_DIR)/invites-tmpl.cgi DB_PATH=$(GPIGEON_DIR)/the.db _GPG_HOMEDIR = $(GPIGEON_DIR)/gnupg GPIGEON_PATH = $(WWWDIR)/cgi-bin/gpigeon.cgi diff --git a/gpigeon-template.cgi b/gpigeon-template.cgi index 0e6b9c0..69df82a 100755 --- a/gpigeon-template.cgi +++ b/gpigeon-template.cgi @@ -32,6 +32,40 @@ 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}; +my %text_strings = ( + addr => 'Address', + addr_ok => 'is valid!', + addr_nok => 'is not valid !', + addr_unknown => 'Unknown', + 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', + here => 'here', + landingpage_title => 'GPIGEON - Log in', + logout_btn_text => 'Logout', + loginbtn => 'Log in', + link_asker_field_label => "Asker's mail :", + link_del_ok => 'Successful removal !', + link_legend_textarea =>'Type your message below :', + 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', + 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_cdate => 'Created on', + username_label => 'Username', + web_title => 'GPIGEON.CGI - Main', + web_greet_msg => 'Hi and welcome. What will you do today ?', +); + sub DbGetLine { my ($dbh, $query) = @_; @@ -48,6 +82,54 @@ sub DbGetLine { } } +sub GetFileTable { + my ($dir ,$hidden_loginfield) = @_; + my @table = (); + opendir my $dir_hnd, "$dir" or die "[GetFileTable function] Can't open $dir: $!"; + while (readdir $dir_hnd) { + if ($_ ne '.' and $_ ne '..'){ + my $linkfile_fn = $_; + my $linkstats= stat("$dir/$linkfile_fn"); + my $mtime = scalar localtime $linkstats->mtime; + my $link_asker = undef; + if (open my $f_hnd , '<', "$dir/$linkfile_fn"){ + for (1..2){ + $link_asker = readline $f_hnd; + $link_asker =~ s/q\{(.*?)\}//i; + $link_asker = $1; + } + close $linkfile_handle; + my $for_field_body = qq{<a href="mailto:$link_asker?subject=$text_strings{mailto_subject}&body=$text_strings{mailto_body} http://$ENV{SERVER_NAME}/cgi-bin/$dir/$linkfile_fn">$link_asker</a>}; + + if (not defined $link_asker){ + $for_field_body = $text_strings{addr_unknown}; + } + #create links table html + push @table, + qq{<tr> + <td><a title="This link has been created on $mtime" href="/cgi-bin/$dir/$linkfile_fn" target="_blank" rel="noopener noreferrer nofollow">ici</a></td> + <td>$for_field_body</td> + <td> + <form method="POST"> + $hidden_loginfield + <input type="hidden" name="adminpan" value="1"> + <input type="hidden" name="supprlien" value="$dir/$linkfile_fn"> + <input id="deletelinkbtn" type="submit" value="$text_strings{delete_link_btn_text}"> + </form> + </td> + </tr>}; + + } + else { + close $linkfile_handle; + die "[GetFileTable function] Error: Can't open $linkfile_fn: $!"; + } + } + } + closedir $dir_hnd; + return @table; +} + sub LoginOk { my ($dbh, $username, $pass, $userid, $magic_cookie, $uid_cookie, $cookiesdir) = @_; my $loginsuccess = PasswdLogin($dbh, $username, $pass); @@ -78,7 +160,7 @@ sub CookieLogin { my $login_cookiefile = "$cookiesdir/$userid/$filename.txt"; if (-e $login_cookiefile){ - open my $in, '<', $login_cookiefile or die "can't read file: $!"; + open my $in, '<', $login_cookiefile or die "[CookieLogin function] can't read file: $!"; $rip_line = readline $in; $ua_line = readline $in; $id_line = readline $in; @@ -133,32 +215,6 @@ sub PasswdLogin { return; } return $userid; # as an userid is always > 0, we can use it as return value - } else { - return; - } - } else { - $dbh->disconnect; - return; - } - $dbh->disconnect; - return; -} - -sub LoginCookieGen { - my ($userid, $magic_cookie, $cookiesdir) = @_; - if (not defined $magic_cookie){ - my $str_rand_obj = String::Random->new; - my $val = $str_rand_obj->randregex('\w{64}'); - if (not -d "$cookiesdir/$userid"){ - mkpath("$cookiesdir/$userid"); - } - my $cookiefile = "$cookiesdir/$userid/$val.txt"; - my $new_magic_cookie = CGI::Cookie->new( - -name => 'id', - -value => $val, - -expires => '+1y', - '-max-age' => '+1y', - -domain => ".$ENV{'SERVER_NAME'}", -path => '/', -secure => 1, -httponly => 1, @@ -200,40 +256,7 @@ my $hostname = $ENV{'SERVER_NAME'}; my $db_path = q{db_path_goes_here}; my $cookiesdir = q{cookies_dir_goes_here}; my $link_template_path = q{link_template_path_goes_here}; - -my %text_strings = ( - addr => 'Address', - addr_ok => 'is valid!', - addr_nok => 'is not valid !', - addr_unknown => 'Unknown', - 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', - here => 'here', - landingpage_title => 'GPIGEON - Log in', - logout_btn_text => 'Logout', - loginbtn => 'Log in', - link_asker_field_label => "Asker's mail :", - link_del_ok => 'Successful removal !', - link_legend_textarea =>'Type your message below :', - 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', - 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_cdate => 'Created on', - username_label => 'Username', - web_title => 'GPIGEON.CGI - Main', - web_greet_msg => 'Hi and welcome. What will you do today ?', -); +my $invites_template_path = q{invite_template_goes_here}; my $cgi_query_get = CGI->new; my $username = $cgi_query_get->param('username'); @@ -298,8 +321,7 @@ if ($disconnect and defined $magic_cookie){ # if we disconnect and cookie is act ); my $f = "$cookiesdir/$userid/$idval.txt"; if (-e "$f"){ - unlink "$f" or die "cant delete cookie at $f :$!\n"; # delet it - + unlink "$f" or die "cant delete cookie at $f :$!\n"; } print "Set-Cookie: $delete_uid_cookie\n"; print "Set-Cookie: $delete_id_cookie\n"; @@ -315,6 +337,7 @@ if($loginok){ LoginCookieGen($userid, $magic_cookie, $cookiesdir); my $user_mailaddr = DbGetLine($dbh, qq{SELECT mail from pigeons where userid='$userid';}); my $nick = DbGetLine($dbh, qq{SELECT name from pigeons where userid='$userid';}); + my $gpgid = DbGetLine($dbh, qq{SELECT gpgfp from pigeons where userid='$userid';}); if (not -d "./l/$userid"){ mkpath("./l/$userid"); } @@ -351,6 +374,7 @@ if($loginok){ while( <$in> ) { s/{link_user}/{$link_asker}/g; s/{user_mailaddr_goes_here}/{$user_mailaddr}/g; + s/{gpgid_goes_here}/{$gpgid}/g; print $out $_; } close $in or die; @@ -365,8 +389,8 @@ if($loginok){ } - opendir my $link_dir_handle, "./l/$userid" or die "Can't open ./l: $!"; - while (readdir $link_dir_handle) { + opendir my $dir_hnd, "./l/$userid" or die "Can't open ./l: $!"; + while (readdir $dir_hnd) { if ($_ ne '.' and $_ ne '..'){ my $linkfile_fn = $_; my $linkstats = stat("./l/$userid/$linkfile_fn"); @@ -397,7 +421,6 @@ if($loginok){ </form> </td> </tr>}; - } else { close $linkfile_handle; @@ -405,7 +428,7 @@ if($loginok){ } } } - closedir $link_dir_handle; + closedir $dir_hnd; print 'Content-type: text/html',"\n\n", qq{<!DOCTYPE html> <html> @@ -464,42 +487,42 @@ else{ } 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="text" name="username"></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 target="_blank" rel="nofollow noopener noreferrer" href="https://hawkpost.co">hawkpost.co</a>. - -</body> -</html>}; + 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="text" name="username"></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 target="_blank" rel="nofollow noopener noreferrer" href="https://hawkpost.co">hawkpost.co</a>. + + </body> + </html>}; } diff --git a/gpigeonctl.def.pl b/gpigeonctl.def.pl index b7d4108..86d7295 100755 --- a/gpigeonctl.def.pl +++ b/gpigeonctl.def.pl @@ -32,6 +32,11 @@ my $web_dir = q{web_dir_goes_here}; my ($escaddr, $ynchoice) = undef; my $opt = $ARGV[0]; my $version = 0.1; +my $dbh = DBI->connect("DBI:SQLite:dbname=$dbh_path", undef, undef, +{ RaiseError => 1, +AutoCommit => 1, +}) +or die $DBI::errstr; sub DbGetLine { @@ -49,6 +54,20 @@ sub DbGetLine { } } +sub ListUsers { + my ($dbh, $query) = @_; + my $prep = $dbh->prepare( $query ); + my $exec = $prep->execute() or die $DBI::errstr; + + if ($exec < 0){ + print $DBI::errstr; + } + + while (my @rows = $prep->fetchrow_array()) { + print "$row[0]\t$rows[1]"; + } +} + sub RecursiveChown { my ($junk, $junk2, $uid, $gid) = getpwnam($web_user); @@ -64,14 +83,14 @@ sub DeleteCookies { } sub EscapeArobase { - my $esc = shift; - if ($esc =~ /^([-\@\w.]+)$/) { - $esc = $1; # $data now untainted - $esc =~ s/@/\\@/; - return $esc; - } else { - die "\n"; # log this somewhere - } + my $esc = shift; + if ($esc =~ /^([-\@\w.]+)$/) { + $esc = $1; # $data now untainted + $esc =~ s/@/\\@/; + return $esc; + } else { + die "\n"; # log this somewhere + } } sub PrintHelp{ @@ -81,57 +100,57 @@ sub PrintHelp{ } sub SetMail { - print "Mail address: "; - my $addr = <STDIN>; - if (not Email::Valid->address($addr)){ - die "\nNot a valid email address."; - } + print "Mail address: "; + my $addr = <STDIN>; + if (not Email::Valid->address($addr)){ + die "\nNot a valid email address."; + } chomp $addr; return $addr; } sub SetNick { my $addr = shift; - print "\nNickname (optional): "; - my $nick = <STDIN>; - chomp $nick; - if (length($nick) eq 0){ - $nick = $addr; - return $nick; - } - elsif (defined $nick and not $nick =~ /^([\w]+)$/){ - die "\nYour nickname must have only alphanumeric characters.\n"; - } + print "\nNickname (optional): "; + my $nick = <STDIN>; + chomp $nick; + if (length($nick) eq 0){ + $nick = $addr; + return $nick; + } + elsif (defined $nick and not $nick =~ /^([\w]+)$/){ + die "\nYour nickname must have only alphanumeric characters.\n"; + } return $nick; } sub SetPasswd { - ReadMode 2; - print "\nPassword: "; - my $pass = <STDIN>; - if (not length($pass) > 10){ - ReadMode 1; - die "\nFor your safety, you should have a password at least 10 characters long.\n"; - } + ReadMode 2; + print "\nPassword: "; + my $pass = <STDIN>; + if (not length($pass) > 10){ ReadMode 1; - chomp $pass; - my $salt = `openssl rand 16`; - my $hash = argon2id_pass($pass, $salt, 3, '32M', 1, 32); + die "\nFor your safety, you should have a password at least 10 characters long.\n"; + } + ReadMode 1; + chomp $pass; + my $salt = `openssl rand 16`; + my $hash = argon2id_pass($pass, $salt, 3, '32M', 1, 32); } sub TransferGPGPubKey { my ($addr, $GNUPGHOME) = @_; my $escaddr = EscapeArobase($addr); - my $gpgid = '0x'.`gpg --with-colons -k $escaddr | grep "pub:u" | cut -d':' -f5`; - chomp $gpgid; - if (not $gpgid =~ /^([\w]+)$/ and not length($gpgid) eq 18){ - die "\nYour GPG 0xlong key id is not a correct one. It seems that no public key was tied to the provided e-mail address.\n"; - } - else{ - $gpgid = $1; - print "\nGPG ID: $gpgid\n"; - return $gpgid; - } + my $gpgid = '0x'.`gpg --with-colons -k $escaddr | grep "pub:u" | cut -d':' -f5`; + chomp $gpgid; + if (not $gpgid =~ /^([\w]+)$/ and not length($gpgid) eq 18){ + die "\nYour GPG 0xlong key id is not a correct one. It seems that no public key was tied to the provided e-mail address.\n"; + } + else{ + $gpgid = $1; + print "\nGPG ID: $gpgid\n"; + return $gpgid; + } } # i should use a module for this lol @@ -228,11 +247,6 @@ if (defined $opt){ use File::Path qw/rmtree/; my $addr = SetMail(); my $esc = EscapeArobase($addr); - my $dbh = DBI->connect("DBI:SQLite:dbname=$dbh_path", undef, undef, - { RaiseError => 1, - AutoCommit => 1, - }) - or die $DBI::errstr; my $uid = DbGetLine($dbh, "SELECT userid FROM pigeons WHERE mail='$esc'") or die "$!"; $dbh->do(qq{DELETE FROM pigeons where mail='$addr'}) or die $DBI::errstr; $dbh->disconnect; @@ -241,7 +255,7 @@ if (defined $opt){ { verbose => 1, safe => 1 }); - # GPG module doesn't support the delete_key yet so we yolo + #GPG module doesn't delete key `GNUPGHOME="$GNUPGHOME" gpg --yes --batch --delete-key $esc`; } print "\nUser $addr deleted succesfully\n"; @@ -268,14 +282,63 @@ if (defined $opt){ print "All generated links have been deleted.\n"; } exit 0; - } + if ($opt eq 'invite'){ + my $verb = shift; + if ($verb eq 'gen'){ + my $preconf_mail = undef; + my $mailfield = q{<input type="text" name="mailaddr" required>}; + my $for_x = undef; + print "Set an email address beforehand ? [y/n] "; + $ynchoice = <STDIN>; + chomp $ynchoice; + if ($ynchoice eq 'o' or $ynchoice eq 'y'){ + $preconf_mail = SetMail(); + $mailfield = qq{<input value="$preconf_mail" type="text" name="mailaddr" required disabled>}; + $for_x = "for $preconf_mail"; + } + use File::Path qw/mkpath/; + mkpath($invites_dir) unless -d $invites_dir; + my $randengine = String::Random->new; + my $randfn = $randengine->randregex('\w{64}') . '.cgi'; + my $invite_path = "$invites_dir/$randfn"; + open my $in, '<', $invites_tmpl or die "Can't open template for invites : $!"; + open my $out, '>', $invite_path or die "Can't write to invite path: $!"; + while (<$in>) { + s/{mailfield_goes_here}/{$mailfield}/g; + print $out $_; + } + close $in or die "$!"; + chmod(0755, $invite_path) or die "$!"; + close $out or die "$!"; + print "\nSuccess ! The link was generated to $invite_path $for_x."; + } + + } + if ($opt eq 'version'){ print "$version\n"; exit 0; } + if ($opt eq 'list'){ + my $verb = shift; + if (defined $verb){ + if ($verb eq 'users'){ + my $dbh = DBI->connect("DBI:SQLite:dbname=$dbh_path", undef, undef, + { + RaiseError => 1, + AutoCommit => 1, + }) or die $DBI::errstr; + ListUsers($dbh); + } + } + else{ + print "Valid 'list' actions are:\n\tusers\n" ; + } + } + PrintHelp(); } else { diff --git a/invites-tmpl-template.cgi b/invites-tmpl-template.cgi new file mode 100755 index 0000000..3681546 --- /dev/null +++ b/invites-tmpl-template.cgi @@ -0,0 +1,282 @@ +#!/usr/bin/perl -T +my $mail = undef; +use warnings; +use strict; +use DBI; +use CGI qw/param/; +use CGI::Carp qw/fatalsToBrowser/; +use Crypt::Argon2 qw/argon2id_pass/; +use Email::Valid; +use Net::SMTP; +use Net::SMTPS; +use String::Random; +use File::Path qw/make_path rmtree/; +use Mail::GPG; + +sub EscapeArobase { + my $esc = shift; + if ($esc =~ /^([-\@\w.]+)$/) { + $esc = $1; # $data now untainted + $esc =~ s/@/\\@/; + return $esc; + } +} + +sub SetMail { + print "Mail address: "; + my $addr = <STDIN>; + if (not Email::Valid->address($addr)){ + die "\nNot a valid email address."; + } + chomp $addr; + return $addr; +} + +sub DbGetLine { + my ($dbh, $query) = @_; + my $prep = $dbh->prepare( $query ); + my $exec = $prep->execute() or die $DBI::errstr; + + if ($exec < 0){ + print $DBI::errstr; + } + + while (my @rows = $prep->fetchrow_array()) { + my $row = $rows[0]; + return $row; + } +} + +sub MakeGPGDir { + my $homedir = shift; + make_path($homedir) unless -d $homedir; + chmod(0700, $homedir); + if(not -e "$homedir/gpg.conf"){ + open my $out, '>', "$homedir/gpg.conf" or die "[MakeGPGDir function] Can't open $homedir/gpg.conf: $!"; + print $out "use-agent\n"; + print $out "charset utf-8\n"; + print $out "no-escape-from-lines\n"; + print $out "trust-model always\n"; + print $out "personal-digest-preferences SHA512 SHA384 SHA256 SHA224\n"; + print $out "default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 BZIP2 ZLIB ZIP Uncompressed"; + close $out; + } +} + +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); + return $date; +} + +delete @ENV{qw(IFS PATH CDPATH BASH_ENV)}; +$ENV{'PATH'} = q{bin_path_goes_here}; + +my $HAS_MAILSERVER = q{0}; +my $EMAIL_NOTIF = q{0}; +my $cgi = CGI->new; +if (not defined $mail){ + $mail = scalar $cgi->param('mailaddr'); +} +my $mailfield = q{mailfield_goes_here}; +my $mailsender = q{sender_addr_goes_here}; +my $mailsender_pw = q{sender_pw_goes_here}; +my $mailsender_smtp = q{smtp_domain_goes_here}; +my $mailsender_port = q{smtp_port_goes_here}; +my $isadmin = q{is_admin_goes_here}; +my $db_path = q{db_path_goes_here}; +my $GNUPGHOME = q{gpg_homedir_goes_here}; +my $TEST_GPGHOME = q{test_gpgdir_goes_here}; +my $dbh = DBI->connect("DBI:SQLite:dbname=$db_path", undef, undef, { RaiseError => 1}) + or die $DBI::errstr; +chomp $mail; +my $nick = $cgi->param('username'); +chomp $nick; +my $pw = $cgi->param('pw'); +my $pw2 = $cgi->param('pw2'); +my $gpgpubk = $cgi->param('gpgpubk'); +$gpgpubk =~ tr/\r//d; +my ($err, $smtp) = undef; + +my $pwmatch = $pw cmp $pw2; + +if ($ENV{REQUEST_METHOD} eq 'POST'){ + if (length($gpgpubk) eq 0){ + $err = q{<span id="failure">No public GPG key text found !</span>}; + } + + if (not $pwmatch eq 0){ + $err = q{<span id="failure">Passwords don't match</span>}; + } + + if (length($pw) eq 0 or length($pw) < 10){ + $err = q{<span id="failure">Password can't be empty or less than 10 characters !</span>}; + } + + if(length($nick) < 0){ + $nick = $mail; + } + else{ + if(length($nick) > 255){ + $err = q{<span id="failure">Username is too long (more than 255 characters).</span>}; + } + + if(length($nick) > 0 and length($nick) < 255){ + #we need to check if duplicate username in db + if($nick =~ /^([\w\'\s_]+)$/){ + $nick = $1; + my $dbnick = DbGetLine($dbh, qq{SELECT name from pigeons where name="$nick";}); + chomp $dbnick; + my $samenick = $nick cmp $dbnick; + if($samenick == 0){ + $err = q{<span id="failure">Username is already taken.</span>}; + } + } + else{ + $err = q{<span id="failure">Username must be left blank or contains alphanumeric characters, space(s) and single quotes.</span>}; + } + } + } + + if (not Email::Valid->address($mail)){ + $err = q{<span id="failure">Invalid mail address !</span>}; + } + else { + my $dbmail = DbGetLine($dbh, qq{SELECT mail from pigeons where mail='$mail';}); + chomp $dbmail; + my $samemail = $dbmail cmp $mail; + if ($samemail == 0){ + $err = q{<span id="failure">Mail is already taken.</span>}; + } + } + + if (not defined $err){ + my $str_rand_obj = String::Random->new; + my $val = $str_rand_obj->randregex('\w{64}'); + MakeGPGDir($TEST_GPGHOME); + my $pubkfile="$TEST_GPGHOME/$val-public.key.asc"; + open my $out, '>', $pubkfile or die "$!"; + print $out $gpgpubk; + close $out; + `gpg --homedir $TEST_GPGHOME --import $pubkfile`; + my $gpgmail = Mail::GPG->new( + gnupg_hash_init => {homedir=>$TEST_GPGHOME}, + debug => 0, + no_strict_7bit_encoding =>1, + ); + my $escaddr = EscapeArobase($mail); + my $keyid = `gpg --homedir $TEST_GPGHOME --with-colons -k $escaddr | grep "pub:" | cut -d':' -f5`; + if ($keyid =~ /([\w]+)/ and length($keyid) eq 16){ + $keyid = $1; + } + + if (not defined $keyid){ + $err = q{<span id="failure">Email and the public GPG key text doesn't match.</span>}; + } + else{ # this is where we can begin to insert data in db + MakeGPGDir($GNUPGHOME); + `gpg --homedir $GNUPGHOME --import $pubkfile`, + my $gpgmail = Mail::GPG->new( + gnupg_hash_init => {homedir => $GNUPGHOME}, + no_strict_7bit_encoding => 1, + debug => 0, + ) or die "$!"; + + my $rfc822date = GetRFC822Date(); + my $mimentity = MIME::Entity->build( + Date => $rfc822date, + From => $mailsender, + To => $mail, + Charset => 'utf-8', + Subjet => "Your GPIGEON Account registration was successful !", + Data => ["Hello,\n\tYour GPIGEON account has been successfully created.\n\tHere's your account details:\n\n\t\tUsername: $mail\n\t\tNickname: $nick\n\t\tPassword: $pw\t\nYou can connect through our website, https://$ENV{HOSTNAME}.\n\nThank you,\nGPIGEON Mailer"]); + my $encrypted_mime_blob = $gpgmail->mime_encrypt(entity => $mimentity, recipients => [$keyid]) or die; + my $encrypted_mime = $encrypted_mime_blob->as_string; + my $salt = `openssl rand 16`; + my $hash = argon2id_pass($pw, $salt, 3, '32M', 1, 32); + $dbh->do(qq{INSERT INTO pigeons VALUES( ?, '$mail', '$nick', '$hash', '$keyid', $adminflag)}) or die $DBI::errstr; + $dbh->disconnect; + + if ($EMAIL_NOTIF){ + 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($mail)){ + $smtp->data($encrypted_mime); + $smtp->dataend(); + $smtp->quit(); + } + else { + die $smtp->message(); + } + } + + } + rmtree($TEST_GPGHOME, {keep_root=>1, safe=>1}); + } +} + +print 'Content-Type: text/html; charset=utf-8',"\n\n", +qq{<!DOCTYPE HTML> +<html> +<head> + <link rel="icon" sizes="48x48" type="image/ico" href="/favicon.ico"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> + <meta name="viewport" content="width=device-width"> + <title>GPIGEON - Registration form</title> + <link rel="stylesheet" href="/styles.css"> +</head> +<body> + <h1>GPIGEON - Registration form</h1> + <hr> + <form method="POST"> + <table id="inviteform"> + <tbody> + <tr> + <td id="labels">Mail adress:</td> + <td>$mailfield</td> + </tr> + <tr> + <td id="labels">(Optional) Username:</td> + <td><input placeholder="Choose an username" type="text" name="username"></td> + </tr> + <tr> + <td id="labels">Password:</td> + <td><input placeholder="Type a password" type="password" name="pw" required></td> + </tr> + <tr> + <td id="labels">Password (confirmation):</td> + <td><input placeholder="Type again your password" type="password" name="pw2" required></td> + </tr> + + <br> + + <tr> + <td id="gpgpklabel">GPG public key:</td> + <td><textarea placeholder="Paste here the result of the command:\ngpg -a --export your\@mailaddre.ss" id="gpgpubk" wrap="off" name="gpgpubk" required></textarea></td> + </tr> + <tr> + <td></td> + <td id="loginerr">$err</td> + <tr id="createaccbtn"> + <td></td> + <td><input id="accbtn" type="submit" value="Create account"></td> + </tr> + </tbody> + </table> + <hr> + </form> +</body> +</html>}; diff --git a/link-tmpl-template.cgi b/link-tmpl-template.cgi index 2f5ab0b..3b612c3 100644 --- a/link-tmpl-template.cgi +++ b/link-tmpl-template.cgi @@ -150,7 +150,7 @@ qq{<!DOCTYPE html> $form_error_notif <label for="filechoice" id="msgbelow"> (Optional) file upload: - <input id="filechoice" type="file" name="file"> + <input id="filechoice" type="file" name="fupload"> </label> <input id="sendbtn" type="submit" value="Send"> </form> @@ -1,180 +1,274 @@ html{ - background-color:#87CEEB + background-color: #87CEEB } body{ - font-family:sans-serif; - width:80%; - margin:auto; - font-size:12pt; + font-family: sans-serif; + width: 80%; + margin: auto; + font-size: 12pt } h1, #msgbelow{ - display:block; - text-align:center; + display: block; + text-align: center } #linkstable tr th{ - padding:10px; - font-size:110%; - margin:0; - border: 3px solid black; - border-bottom:none; + margin: 0; + padding: 10px; + font-size: 110%; + border: 3px solid black; + border-bottom: none +} + +#adminprom, #mailnotif{ + display: block; + padding: 3px +} + +#mailnotif-check, #adminprom-check{ + float: left } #linkstable td{ - text-align:center; - padding: 5px ; + padding: 10px; + text-align: center } #linkstable input{ - padding:10px; - margin:5px; - margin-top:10px; + padding: 10px; + margin: 5px; + margin-top: 10px } #linkstable table{ - margin-top:10px; - border: 1px solid black; + margin-top: 10px; + border: 1px solid black } #linkstable td{ - border:1px solid black; + border: 1px solid black } -#logoutbtn { - display: inline; - float:right; - top: 0; - right: 0; - position:absolute; +#logoutbtn, #adminpanbtn { + display: inline; + float: right; + top: 0; + right: 0; + position: absolute +} + +#adminpanbtn { + right: 110px } #msg{ - display:block; - margin-left:auto; - margin-right:auto; + display: block; + margin-left: auto; + margin-right: auto; border: 1px solid black; overflow: -moz-scrollbars-none; - resize:vertical; - width:50%; - -ms-overflow-style:none; + resize: vertical; + width: 50%; + -ms-overflow-style: none } #msg::-webkit-scrollbar { - width: 0 !important + width: 0 !important } #success { - color:green; + color: green } #failure { - color:red; + color: red } -#loginbox #loginerr{ - border:none; - margin-right:auto; - margin-left:auto +#loginbox, #inviteform{ + border: none; + margin-right: auto; + margin-left: auto } -#loginbox input { - width:100%; +#loginbox input, #inviteform input{ + width: 100%; padding: 5px; - line-height:25px; + line-height: 25px +} + +#labels{ + text-align: right; + border: none +} +#loginbox tr, #inviteform tr{ + border: none } -#loginbox td { - text-align:right; - border:none; +#inviteform textarea { + height: 400px } -#loginbox tr { - border:none; +#gpgpklabel { + text-align: right; + display: block /*so the label is display at the top*/ } -#authbtn td { - text-align:center; +td #gpgpubk{ + display: block; + width: 400px; + height: 250px; + resize: none } -#authbtn input { - width:100px; +#authbtn td, #createaccbtn td, #loginerr{ + text-align:center } -#mailfied { - padding: 10px +#authbtn input, #createaccbtn input{ + width: 100px +} + +#mailfield { + padding: 10px +} + +#genlinkbtn-mob,#geninvbtn-mob { + display: none } #refreshbtn, #deletelinkbtn, #deleteallbtn, -#logoutbtn, #genlinkbtn, #sendbtn { - border-radius:0 - border:3px outset silver; - padding:15px; - margin:5px; +#logoutbtn, #loginbtn, #genlinkbtn, #sendbtn, +#accbtn, #adminpanbtn, #geninvbtn, #geninvbtn-mob{ + cursor: pointer; + border-radius: 0; + border: 3px outset silver; + padding: 15px; + margin: 5px +} + +#refreshbtn:active, #deletelinkbtn:active, +#deleteallbtn:active, #genlinkbtn:active, #genlinkbtn-mob:active, +#sendbtn:active, #accbtn:active, +#logoutbtn:active, #loginbtn:active, +#adminpanbtn:active{ + border: 3px inset silver } #mailfield { - padding: 10px; + padding: 10px +} + +#loginerr { + text-align: center +} + +#accbtn { + height: 50px +} + +#sendbtn , #accbtn{ + display: block; + width: 20%; + margin-left: auto; + margin-right: auto } +#linkstable a:hover{ + opacity: 0.3; + background: white +} + + @media screen and (max-width: 740px) { body { - font-size:0.8em; - } + margin: 0; + font-size: 0.8em + } - h1{ - font-size:1.5em; - } + h1{ + text-align: left; + font-size: 1.5em + } + + #inviteform, #loginbox{ + margin: 0 + } + + #inviteform td , #loginbox td{ + display: block; + text-align: left + } + + #inviteform textarea{ + margin: 0; + font-size: 9px; + width: 150px; + height: 200px + } - #linkstable th,td{ - padding:3px; - } + #linkstable td{ + margin: 0; + padding: 0px; + font-size: 10px + } - #linkstable input{ - padding:4px; - margin:2px; - margin-top:10px; + #linkstable tr, + #linkstable th, #linkstable input{ + margin: 0; + padding: 0px } - - #loginbox input{ + + #loginbox input, #inviteform input{ padding: 2px; - line-height:15px; - } - - #logoutbtn { - float:none; - top:unset; - right:unset; - position:revert; - } - - #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 - } + line-height: 15px + } + + #logoutbtn, #adminpanbtn { + float: none; + top: unset; + right: unset; + position: revert + } + + #mailfield{ + padding: 3px + } + + #msg { + width: 50%; + margin: 0 + } + + #msgbelow { + text-align: left + } + + #refreshbtn, #deletelinkbtn, #deleteallbtn, + #logoutbtn, #genlinkbtn, #geninvbtn-mob, #sendbtn, #adminpanbtn{ + padding: 8px + } + + #genlinkbtn, #geninvbtn-mob{ + display: block + } + + #geninvbtn{ + display: none + } + + #sendbtn { + margin: 0; + display: inline; + width: 100px + } + + #mailnotif, #mailnotif input, #adminprom, #adminprom input{ + display: block; + padding: 10px + } } |