From e4aaaf56ea53a10c893f5d73c17103c9b12c8c7e Mon Sep 17 00:00:00 2001
From: Ineiev
Date: Fri, 10 Feb 2017 15:10:55 +0300
Subject: [PATCH] Encrypt message with GPG key when available.
---
frontend/perl/encrypt-to-user/index.pl | 134 ++++++++++++++++++++++++++++++++
frontend/php/account/lostpw-confirm.php | 34 ++++++++
frontend/php/my/admin/index.php | 18 ++++-
3 files changed, 185 insertions(+), 1 deletion(-)
create mode 100644 frontend/perl/encrypt-to-user/index.pl
diff --git a/frontend/perl/encrypt-to-user/index.pl b/frontend/perl/encrypt-to-user/index.pl
new file mode 100644
index 0000000..13e4dd9
--- /dev/null
+++ b/frontend/perl/encrypt-to-user/index.pl
@@ -0,0 +1,134 @@
+#! /usr/bin/perl
+# Encrypt a message to specified savane user.
+#
+# Copyright 2017 (c) Ineiev
+#
+# This file is part of Savane.
+#
+# Savane is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# Savane 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+use strict;
+use DBI;
+use File::Temp qw(tempdir tempfile);
+use Getopt::Long;
+my $getopt;
+my $help;
+my $user;
+my $sys_dbname;
+my $sys_dbhost;
+my $sys_dbuser;
+my $sys_dbparams;
+my $sys_dbpasswd;
+
+eval {
+ $getopt = GetOptions("help" => \$help,
+ "user=s" => \$user,
+ "dbname=s" => \$sys_dbname,
+ "dbhost:s" => \$sys_dbhost,
+ "dbuser=s" => \$sys_dbuser,
+ "dbparams:s" => \$sys_dbparams,
+ "dbpasswd:s" => \$sys_dbpasswd);
+};
+
+sub print_help {
+ print STDERR <connect('DBI:mysql:database='.$sys_dbname
+ .':host='.$sys_dbhost
+ .$sys_dbparams,
+ $sys_dbuser, $sys_dbpasswd,
+ { RaiseError => 1, AutoCommit => 1});
+
+## Encrypt to user GPG key if available
+# arg1 : user id
+# arg2 : message
+# return encrypted message when encryption succeeded,
+# empty string encryption failed.
+sub UserEncrypt {
+ my ($user, $message) = @_;
+ my $key = $dbd->selectrow_array("SELECT gpg_key FROM user WHERE user_id=".$user);
+
+ return "" unless $key ne "";
+
+ my ($mh, $mname) = tempfile(UNLINK => 1);
+ my $temp_dir = tempdir(CLEANUP => 1);
+ my $input;
+ my $key_id = "";
+ my $msg = "";
+
+ print $mh $message;
+
+ open($input, '|-', 'gpg --homedir='.$temp_dir.' -q --import');
+ print $input $key;
+ close($input);
+
+# Get the first ID of a public key with encryption capability.
+ open($input, '-|', 'gpg --homedir='.$temp_dir.
+ ' --list-keys --with-colons 2> /dev/null');
+ while(<$input>)
+ {
+ if(!/^pub/)
+ {
+ next;
+ }
+ my @fields = split /:/;
+ if(@fields[11] !~ /[eE]/)
+ {
+ next;
+ }
+ $key_id = @fields[4];
+ last unless $key_id eq "";
+ }
+ close($input);
+ return "" unless $key_id ne "";
+ open($input, '-|', 'gpg --homedir='.$temp_dir.
+ ' --trust-model always --batch -a --encrypt -r '
+ .$key_id." -o - ".$mname);
+ while(<$input>)
+ {
+ $msg = $msg.$_;
+ }
+ return "" unless $msg ne "";
+ return $msg;
+}
+
+my $msg = "";
+
+while(<>)
+ {
+ $msg = $msg.$_;
+ }
+
+print UserEncrypt($user, $msg);
+
+exit 0;
diff --git a/frontend/php/account/lostpw-confirm.php b/frontend/php/account/lostpw-confirm.php
index a4dc5cd..44223e1 100644
--- a/frontend/php/account/lostpw-confirm.php
+++ b/frontend/php/account/lostpw-confirm.php
@@ -4,6 +4,7 @@
# Copyright 1999-2000 (c) The SourceForge Crew
# Copyright 2004-2005 (c) Mathieu Roy
# Joxean Koret
+# Copyright 2017 (c) Ineiev
#
# This file is part of Savane.
#
@@ -24,6 +25,7 @@ require_once('../include/init.php');
require_once('../include/sane.php');
require_once('../include/session.php');
require_once('../include/sendmail.php');
+require_once('../include/database.php');
register_globals_off();
@@ -140,6 +142,34 @@ $message_for_admin =
. gmdate('D, d M Y H:i:s \G\M\T')
. "\n";
+$encrypted_message = "";
+if(user_get_preference("email_encrypted", $row_user['user_id']))
+ {
+ $cmd = '/usr/bin/perl ../../perl/encrypt-to-user/index.pl '
+ .'--user="'.$row_user['user_id'].'" '
+ .'--dbuser="'.$sys_dbuser.'" '
+ .'--dbname="'.$sys_dbname.'" '
+ .'--dbpasswd="'.$sys_dbpasswd.'" '
+ .'--dbhost="'.$sys_dbhost.'"';
+
+ $d_spec = array(
+ 0 => array("pipe", "r"), 1 => array("pipe", "w"),
+ 2 => array("file", "/dev/null", "a"));
+
+ $gpg_proc = proc_open($cmd, $d_spec, $pipes, NULL, $_ENV);
+ fwrite($pipes[0], $message);
+ fclose($pipes[0]);
+ $encrypted_message = stream_get_contents($pipes[1]);
+ fclose($pipes[1]);
+ $gpg_result = proc_close($gpg_proc);
+
+ if($gpg_result != 0 or $encrypted_message == FALSE)
+ $encrypted_message = "";
+ }
+
+if($encrypted_message != "")
+ $message = $encrypted_message;
+
sendmail_mail($GLOBALS['sys_mail_replyto']."@".$GLOBALS['sys_mail_domain'],
$row_user['email'],
$GLOBALS['sys_default_domain']." Verification",
@@ -159,6 +189,10 @@ $HTML->header(array('title'=>_("Lost Password Confirmation")));
print '
'._("An email has been sent to the address you have on file.").'
';
print '
'._("Follow the instructions in the email to change your account password.").'
';
+if($encrypted_message != "")
+ {
+ print '
'._("Note that it was encrypted with your registered GPG key.").'
';
+ }
;
$HTML->footer(array());
diff --git a/frontend/php/my/admin/index.php b/frontend/php/my/admin/index.php
index 3b19a28..cbf5e80 100644
--- a/frontend/php/my/admin/index.php
+++ b/frontend/php/my/admin/index.php
@@ -3,6 +3,7 @@
# Copyright 1999-2000 (c) The SourceForge Crew
# Copyright 2002-2006 (c) Mathieu Roy
# Copyright (C) 2007 Sylvain Beucler
+# Copyright (C) 2017 Ineiev
#
# This file is part of Savane.
#
@@ -30,7 +31,7 @@ extract(sane_import('post',
'form_keep_only_one_session',
'form_timezone', 'user_theme', 'theme_rotate_jump',
'form_reverse_comments_order', 'form_stone_age_menu', 'form_nonfixed_feedback',
- 'form_use_bookmarks', 'form_email_hide',
+ 'form_use_bookmarks', 'form_email_hide', 'form_email_encrypted'
)));
if ($update and $user_theme != "random" and $user_theme != "rotate")
@@ -79,6 +80,12 @@ if ($update)
else
{ user_unset_preference("use_bookmarks"); }
+ # Encryption preferences
+ if ($form_email_encrypted == "1")
+ { user_set_preference("email_encrypted", 1); }
+ else
+ { user_unset_preference("email_encrypted"); }
+
# Relative position feedback
if ($form_nonfixed_feedback == "1")
{ user_set_preference("nonfixed_feedback", 1); }
@@ -287,6 +294,15 @@ print ''._("When checked, the only way for users to get in touch with you would be to use the form available to logged-in users. It is generally a bad idea to choose this option, especially if you are a project administrator.").'';
+print ' '
+._("Encrypt emails when resetting password");
+
+print '
'
+._("When checked, Savannah will encrypt email messages
+with your registered public GPG key when resetting password is requested.
+If no suitable key is available, the messages still go unencrypted.")
+.'