
15 changed files with 933 additions and 8 deletions
@ -0,0 +1,30 @@
|
||||
gpg-mailgate-web |
||||
---------------- |
||||
|
||||
gpg-mailgate-web is a web interface designed to allow any web user |
||||
to upload their PGP public key and then have all mail sent from |
||||
your mail server be encrypted. (Note: this is not meant for email |
||||
authentication, only encryption.) |
||||
|
||||
After submitting their key to a web form, the user will be required |
||||
to confirm their email address. A cron script will register the |
||||
public key with gpg-mailgate (keyhome_only must be set to no |
||||
currently, which is the default) after email confirmation. From |
||||
then on, email to the specified address will be encrypted with |
||||
the public key. |
||||
|
||||
Installation instructions: |
||||
|
||||
1) Install gpg-mailgate. |
||||
2) Create a MySQL database for gpg-mailgate. |
||||
a) Schema file is located in schema.sql |
||||
b) Database name and account goes in /etc/gpg-mailgate.conf (and set enabled = yes) |
||||
3) Copy the contents of public_html to your web directory. |
||||
4) Move config.sample.php to config.php and edit the configuration file. |
||||
5) Copy cron.py to /usr/local/bin/gpgmw-cron.py and set up a cron job |
||||
a) Create /etc/cron.d/gpgmw with the contents: |
||||
*/3 * * * * gpgmap /usr/bin/python /usr/local/bin/gpgmw-cron.py > /dev/null |
||||
(replace gpgmap with the owner of the gpg-mailgate GPG home directory) |
||||
6) Ensure that cron is working and test your new gpg-mailgate-web installation! |
||||
|
||||
Any issues should be reported to https://github.com/uakfdotb/gpg-mailgate |
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python |
||||
|
||||
from ConfigParser import RawConfigParser |
||||
import GnuPG |
||||
import MySQLdb |
||||
|
||||
def appendLog(msg): |
||||
if cfg.has_key('logging') and cfg['logging'].has_key('file'): |
||||
log = open(cfg['logging']['file'], 'a') |
||||
log.write(msg + "\n") |
||||
log.close() |
||||
|
||||
# Read configuration from /etc/gpg-mailgate.conf |
||||
_cfg = RawConfigParser() |
||||
_cfg.read('/etc/gpg-mailgate.conf') |
||||
cfg = dict() |
||||
for sect in _cfg.sections(): |
||||
cfg[sect] = dict() |
||||
for (name, value) in _cfg.items(sect): |
||||
cfg[sect][name] = value |
||||
|
||||
if cfg.has_key('database') and cfg['database'].has_key('enabled') and cfg['database']['enabled'] == 'yes' and cfg['database'].has_key('name') and cfg['database'].has_key('host') and cfg['database'].has_key('username') and cfg['database'].has_key('password'): |
||||
connection = MySQLdb.connect(host = cfg['database']['host'], user = cfg['database']['username'], passwd = cfg['database']['password'], db = cfg['database']['name'], port = 3306) |
||||
cursor = connection.cursor() |
||||
|
||||
# import keys |
||||
cursor.execute("SELECT publickey, id, email FROM gpgmw_keys WHERE status = 0 AND confirm = '' LIMIT 100") |
||||
result_set = cursor.fetchall() |
||||
|
||||
for row in result_set: |
||||
# delete any other public keys associated with this confirmed email address |
||||
cursor.execute("DELETE FROM gpgmw_keys WHERE email = %s AND id != %s", (row[2], row[1],)) |
||||
GnuPG.delete_key(cfg['gpg']['keyhome'], row[2]) |
||||
appendLog('Deleted key for <' + row[2] + '> via import request') |
||||
|
||||
if row[0].strip(): # we have this so that user can submit blank key to remove any encryption |
||||
if GnuPG.confirm_key(row[0], row[2]): |
||||
GnuPG.add_key(cfg['gpg']['keyhome'], row[0]) # import the key to gpg |
||||
cursor.execute("UPDATE gpgmw_keys SET status = 1 WHERE id = %s", (row[1],)) # mark key as accepted |
||||
appendLog('Imported key from <' + row[2] + '>') |
||||
else: |
||||
cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) # delete key |
||||
appendLog('Import confirmation failed for <' + row[2] + '>') |
||||
|
||||
connection.commit() |
||||
|
||||
# delete keys |
||||
cursor.execute("SELECT email, id FROM gpgmw_keys WHERE status = 2 LIMIT 100") |
||||
result_set = cursor.fetchall() |
||||
|
||||
for row in result_set: |
||||
GnuPG.delete_key(cfg['gpg']['keyhome'], row[0]) |
||||
cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) |
||||
appendLog('Deleted key for <' + row[0] + '>') |
||||
connection.commit() |
||||
else: |
||||
print "Warning: doing nothing since database settings are not configured!" |
@ -0,0 +1,93 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
$config = array(); |
||||
|
||||
// |
||||
// GENERAL SITE SETTINGS |
||||
// |
||||
|
||||
//web team contact |
||||
// this email address will be displayed if there is a database error |
||||
$config['email_web'] = 'admin@example.com'; |
||||
|
||||
//address to send emails from |
||||
$config['email_from'] = 'gpg-mailgate-web@example.com'; |
||||
|
||||
//this will be used as the subject when a user requests to add a PGP key |
||||
$config['email_subject_requestpgp'] = 'Confirm your email address'; |
||||
|
||||
//site URL, without trailing slash |
||||
$config['site_url'] = 'http://example.com/gpgmw'; |
||||
|
||||
//title of the website (displayed on home page) |
||||
$config['site_title'] = 'PGP key management'; |
||||
|
||||
// |
||||
// MAIL SETTINGS |
||||
// |
||||
|
||||
//whether to send mail through SMTP (instead of PHP mail function) |
||||
$config['mail_smtp'] = false; |
||||
|
||||
//SMTP settings, if mail_smtp is enabled |
||||
$config['mail_smtp_host'] = 'localhost'; |
||||
$config['mail_smtp_port'] = 25; |
||||
$config['mail_smtp_username'] = 'gpgmw'; |
||||
$config['mail_smtp_password'] = ''; |
||||
|
||||
// |
||||
// DATABASE SETTINGS |
||||
// |
||||
|
||||
//database name (MySQL only); or see include/dbconnect.php |
||||
$config['db_name'] = 'gpgmw'; |
||||
|
||||
//database host |
||||
$config['db_host'] = 'localhost'; |
||||
|
||||
//database username |
||||
$config['db_username'] = 'gpgmw'; |
||||
|
||||
//database password |
||||
$config['db_password'] = ''; |
||||
|
||||
// |
||||
// LOCK SETTINGS |
||||
// |
||||
|
||||
//the time in seconds a user must wait before trying again; otherwise they get locked out (count not increased) |
||||
$config['lock_time_initial'] = array('requestpgp' => 10); |
||||
|
||||
//the number of tries a user has (that passes the lock_time_initial test) before being locked by overload (extended duration) |
||||
$config['lock_count_overload'] = array('requestpgp' => 3); |
||||
|
||||
//the time that overloads last |
||||
$config['lock_time_overload'] = array('requestpgp' => 900); |
||||
|
||||
//time after which locks no longer apply, assuming the lock isn't active |
||||
$config['lock_time_reset'] = 300; |
||||
|
||||
//max time to store locks in the database; this way we can clear old locks with one function |
||||
$config['lock_time_max'] = 3600; |
||||
|
||||
?> |
@ -0,0 +1,40 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
require_once("config.php"); |
||||
require_once("include/common.php"); |
||||
require_once("include/dbconnect.php"); |
||||
require_once("include/pgp.php"); |
||||
|
||||
if(isset($_REQUEST['email']) && isset($_REQUEST['confirm'])) { |
||||
$result = confirmPGP($_REQUEST['email'], $_REQUEST['confirm']); |
||||
|
||||
if($result === true) { |
||||
get_page("home", array('message' => 'Your email address has been confirmed successfully. Within a few minutes, emails from our mail server to you should be encrypted with your PGP public key.')); |
||||
} else { |
||||
get_page("home", array('message' => 'Error: failed to confirm any email address. You may have already confirmed the address, or you may have the wrong confirmation key.')); |
||||
} |
||||
} else { |
||||
get_page("home"); |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,257 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
function string_begins_with($string, $search) |
||||
{ |
||||
return (strncmp($string, $search, strlen($search)) == 0); |
||||
} |
||||
|
||||
function boolToString($bool) { |
||||
return $bool ? 'true' : 'false'; |
||||
} |
||||
|
||||
//returns an absolute path to the include directory |
||||
function includePath() { |
||||
$self = __FILE__; |
||||
$lastSlash = strrpos($self, "/"); |
||||
return substr($self, 0, $lastSlash + 1); |
||||
} |
||||
|
||||
//returns a relative path to the gpg-mailgate-web web root directory, without trailing slash |
||||
function basePath() { |
||||
$commonPath = __FILE__; |
||||
$requestPath = $_SERVER['SCRIPT_FILENAME']; |
||||
|
||||
//count the number of slashes |
||||
// number of .. needed for include level is numslashes(request) - numslashes(common) |
||||
// then add one more to get to base |
||||
$commonSlashes = substr_count($commonPath, '/'); |
||||
$requestSlashes = substr_count($requestPath, '/'); |
||||
$numParent = $requestSlashes - $commonSlashes + 1; |
||||
|
||||
$basePath = "."; |
||||
for($i = 0; $i < $numParent; $i++) { |
||||
$basePath .= "/.."; |
||||
} |
||||
|
||||
return $basePath; |
||||
} |
||||
|
||||
function uid($length) { |
||||
$characters = "0123456789abcdefghijklmnopqrstuvwxyz"; |
||||
$string = ""; |
||||
|
||||
for ($p = 0; $p < $length; $p++) { |
||||
$string .= $characters[secure_random() % strlen($characters)]; |
||||
} |
||||
|
||||
return $string; |
||||
} |
||||
|
||||
function get_page($page, $args = array()) { |
||||
//let pages use some variables |
||||
extract($args); |
||||
$config = $GLOBALS['config']; |
||||
|
||||
$basePath = basePath(); |
||||
|
||||
$themePath = $basePath . "/theme"; |
||||
$themePageInclude = "$themePath/$page.php"; |
||||
|
||||
if(file_exists("$themePath/header.php")) { |
||||
include("$themePath/header.php"); |
||||
} |
||||
|
||||
if(file_exists($themePageInclude)) { |
||||
include($themePageInclude); |
||||
} |
||||
|
||||
if(file_exists("$themePath/footer.php")) { |
||||
include("$themePath/footer.php"); |
||||
} |
||||
} |
||||
|
||||
function isAscii($str) { |
||||
return 0 == preg_match('/[^\x00-\x7F]/', $str); |
||||
} |
||||
|
||||
//returns random number from 0 to 2^24 |
||||
function secure_random() { |
||||
return hexdec(bin2hex(secure_random_bytes(3))); |
||||
} |
||||
|
||||
function gpgmw_mail($subject, $body, $to) { //returns true=ok, false=notok |
||||
$config = $GLOBALS['config']; |
||||
$from = filter_var($config['email_from'], FILTER_SANITIZE_EMAIL); |
||||
$to = filter_var($to, FILTER_SANITIZE_EMAIL); |
||||
|
||||
if($to === false || $from === false) { |
||||
return false; |
||||
} |
||||
|
||||
if(isset($config['mail_smtp']) && $config['mail_smtp']) { |
||||
require_once "Mail.php"; |
||||
|
||||
$host = $config['mail_smtp_host']; |
||||
$port = $config['mail_smtp_port']; |
||||
$username = $config['mail_smtp_username']; |
||||
$password = $config['mail_smtp_password']; |
||||
$headers = array ('From' => $from, |
||||
'To' => $to, |
||||
'Subject' => $subject, |
||||
'Content-Type' => 'text/plain'); |
||||
$smtp = Mail::factory('smtp', |
||||
array ('host' => $host, |
||||
'port' => $port, |
||||
'auth' => true, |
||||
'username' => $username, |
||||
'password' => $password)); |
||||
|
||||
$mail = $smtp->send($to, $headers, $body); |
||||
|
||||
if (PEAR::isError($mail)) { |
||||
return false; |
||||
} else { |
||||
return true; |
||||
} |
||||
} else { |
||||
$headers = "From: $from\r\n"; |
||||
$headers .= "Content-type: text/plain\r\n"; |
||||
return mail($to, $subject, $body, $headers); |
||||
} |
||||
} |
||||
|
||||
//secure_random_bytes from https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP |
||||
/* |
||||
* The function is providing, at least at the systems tested :), |
||||
* $len bytes of entropy under any PHP installation or operating system. |
||||
* The execution time should be at most 10-20 ms in any system. |
||||
*/ |
||||
function secure_random_bytes($len = 10) { |
||||
|
||||
/* |
||||
* Our primary choice for a cryptographic strong randomness function is |
||||
* openssl_random_pseudo_bytes. |
||||
*/ |
||||
$SSLstr = '4'; // http://xkcd.com/221/ |
||||
if (function_exists('openssl_random_pseudo_bytes') && |
||||
(version_compare(PHP_VERSION, '5.3.4') >= 0 || |
||||
substr(PHP_OS, 0, 3) !== 'WIN')) |
||||
{ |
||||
$SSLstr = openssl_random_pseudo_bytes($len, $strong); |
||||
if ($strong) |
||||
return $SSLstr; |
||||
} |
||||
|
||||
/* |
||||
* If mcrypt extension is available then we use it to gather entropy from |
||||
* the operating system's PRNG. This is better than reading /dev/urandom |
||||
* directly since it avoids reading larger blocks of data than needed. |
||||
* Older versions of mcrypt_create_iv may be broken or take too much time |
||||
* to finish so we only use this function with PHP 5.3 and above. |
||||
*/ |
||||
if (function_exists('mcrypt_create_iv') && |
||||
(version_compare(PHP_VERSION, '5.3.0') >= 0 || |
||||
substr(PHP_OS, 0, 3) !== 'WIN')) |
||||
{ |
||||
$str = mcrypt_create_iv($len, MCRYPT_DEV_URANDOM); |
||||
if ($str !== false) |
||||
return $str; |
||||
} |
||||
|
||||
|
||||
/* |
||||
* No build-in crypto randomness function found. We collect any entropy |
||||
* available in the PHP core PRNGs along with some filesystem info and memory |
||||
* stats. To make this data cryptographically strong we add data either from |
||||
* /dev/urandom or if its unavailable, we gather entropy by measuring the |
||||
* time needed to compute a number of SHA-1 hashes. |
||||
*/ |
||||
$str = ''; |
||||
$bits_per_round = 2; // bits of entropy collected in each clock drift round |
||||
$msec_per_round = 400; // expected running time of each round in microseconds |
||||
$hash_len = 20; // SHA-1 Hash length |
||||
$total = $len; // total bytes of entropy to collect |
||||
|
||||
$handle = @fopen('/dev/urandom', 'rb'); |
||||
if ($handle && function_exists('stream_set_read_buffer')) |
||||
@stream_set_read_buffer($handle, 0); |
||||
|
||||
do |
||||
{ |
||||
$bytes = ($total > $hash_len)? $hash_len : $total; |
||||
$total -= $bytes; |
||||
|
||||
//collect any entropy available from the PHP system and filesystem |
||||
$entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; |
||||
$entropy .= implode('', @fstat(@fopen( __FILE__, 'r'))); |
||||
$entropy .= memory_get_usage(); |
||||
if ($handle) |
||||
{ |
||||
$entropy .= @fread($handle, $bytes); |
||||
} |
||||
else |
||||
{ |
||||
// Measure the time that the operations will take on average |
||||
for ($i = 0; $i < 3; $i ++) |
||||
{ |
||||
$c1 = microtime(true); |
||||
$var = sha1(mt_rand()); |
||||
for ($j = 0; $j < 50; $j++) |
||||
{ |
||||
$var = sha1($var); |
||||
} |
||||
$c2 = microtime(true); |
||||
$entropy .= $c1 . $c2; |
||||
} |
||||
|
||||
// Based on the above measurement determine the total rounds |
||||
// in order to bound the total running time. |
||||
$rounds = (int)($msec_per_round*50 / (int)(($c2-$c1)*1000000)); |
||||
|
||||
// Take the additional measurements. On average we can expect |
||||
// at least $bits_per_round bits of entropy from each measurement. |
||||
$iter = $bytes*(int)(ceil(8 / $bits_per_round)); |
||||
for ($i = 0; $i < $iter; $i ++) |
||||
{ |
||||
$c1 = microtime(); |
||||
$var = sha1(mt_rand()); |
||||
for ($j = 0; $j < $rounds; $j++) |
||||
{ |
||||
$var = sha1($var); |
||||
} |
||||
$c2 = microtime(); |
||||
$entropy .= $c1 . $c2; |
||||
} |
||||
|
||||
} |
||||
// We assume sha1 is a deterministic extractor for the $entropy variable. |
||||
$str .= sha1($entropy, true); |
||||
} while ($len > strlen($str)); |
||||
|
||||
if ($handle) |
||||
@fclose($handle); |
||||
|
||||
return substr($str, 0, $len); |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,76 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
function dieDatabaseError($ex = NULL) { |
||||
global $config; |
||||
|
||||
if($ex == NULL) { |
||||
$pre = "Encountered database error."; |
||||
} else { |
||||
$pre = "Encountered database error: " . $ex->getMessage() . "."; |
||||
} |
||||
|
||||
die($pre . " If this is unexpected, consider <a href=\"mailto:{$config['email_web']}\">reporting it to our web team</a>. Otherwise, <a href=\"/\">click here to return to the home page.</a>"); |
||||
} |
||||
|
||||
try { |
||||
$database = new PDO('mysql:host=' . $config['db_host'] . ';dbname=' . $config['db_name'], $config['db_username'], $config['db_password'], array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); |
||||
} catch(PDOException $ex) { |
||||
dieDatabaseError($ex); |
||||
} |
||||
|
||||
function databaseQuery($command, $array = array(), $assoc = false) { |
||||
global $database; |
||||
|
||||
if(!is_array($array)) { |
||||
dieDatabaseError(); |
||||
} |
||||
|
||||
try { |
||||
$query = $database->prepare($command); |
||||
|
||||
if(!$query) { |
||||
print_r($database->errorInfo()); |
||||
dieDatabaseError(); |
||||
} |
||||
|
||||
//set fetch mode depending on parameter |
||||
if($assoc) { |
||||
$query->setFetchMode(PDO::FETCH_ASSOC); |
||||
} else { |
||||
$query->setFetchMode(PDO::FETCH_NUM); |
||||
} |
||||
|
||||
$success = $query->execute($array); |
||||
|
||||
if(!$success) { |
||||
print_r($query->errorInfo()); |
||||
dieDatabaseError(); |
||||
} |
||||
|
||||
return $query; |
||||
} catch(PDOException $ex) { |
||||
dieDatabaseError($ex); |
||||
} |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,124 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
//lock.php is basic spam-submit prevention |
||||
//lock_time_initial, lock_time_overload, lock_count_overload, lock_time_reset, and lock_time_max should be defined in $config |
||||
|
||||
//returns boolean: true=proceed, false=lock up; the difference between this and lockAction is that this can be used for repeated tasks, like admin |
||||
// then, only if action was unsuccessful would lockAction be called |
||||
function checkLock($action) { |
||||
global $config; |
||||
$lock_time_initial = $config['lock_time_initial']; |
||||
$lock_time_overload = $config['lock_time_overload']; |
||||
$lock_count_overload = $config['lock_count_overload']; |
||||
$lock_time_reset = $config['lock_time_reset']; |
||||
$lock_time_max = $config['lock_time_max']; |
||||
|
||||
if(!isset($lock_time_initial[$action])) { |
||||
return true; //well we can't do anything... |
||||
} |
||||
|
||||
$ip = $_SERVER['REMOTE_ADDR']; |
||||
|
||||
$result = databaseQuery("SELECT id, time, num FROM gpgmw_locks WHERE ip = ? AND action = ?", array($ip, $action), true); |
||||
if($row = $result->fetch()) { |
||||
$id = $row['id']; |
||||
$time = $row['time']; |
||||
$count = $row['num']; //>=0 count means it's a regular initial lock; -1 count means overload lock |
||||
|
||||
if($count >= 0) { |
||||
if(time() <= $time + $lock_time_initial[$action]) { |
||||
return false; |
||||
} |
||||
} else { |
||||
if(time() <= $time + $lock_time_overload[$action]) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
//returns boolean: true=proceed, false=lock up |
||||
function lockAction($action) { |
||||
global $config; |
||||
$lock_time_initial = $config['lock_time_initial']; |
||||
$lock_time_overload = $config['lock_time_overload']; |
||||
$lock_count_overload = $config['lock_count_overload']; |
||||
$lock_time_reset = $config['lock_time_reset']; |
||||
$lock_time_max = $config['lock_time_max']; |
||||
|
||||
if(!isset($lock_time_initial[$action])) { |
||||
return true; //well we can't do anything... |
||||
} |
||||
|
||||
$ip = $_SERVER['REMOTE_ADDR']; |
||||
$replace_id = -1; |
||||
|
||||
//first find records with ip/action |
||||
$result = databaseQuery("SELECT id, time, num FROM gpgmw_locks WHERE ip = ? AND action = ?", array($ip, $action), true); |
||||
if($row = $result->fetch()) { |
||||
$id = $row['id']; |
||||
$time = $row['time']; |
||||
$count = $row['num']; //>=0 count means it's a regular initial lock; -1 count means overload lock |
||||
|
||||
if($count >= 0) { |
||||
if(time() <= $time + $lock_time_initial[$action]) { |
||||
return false; |
||||
} else if(time() > $time + $lock_time_reset) { |
||||
//this entry is old, but use it to replace |
||||
$replace_id = $id; |
||||
} else { |
||||
//increase the count; maybe initiate an OVERLOAD |
||||
$count = $count + 1; |
||||
if($count >= $lock_count_overload[$action]) { |
||||
databaseQuery("UPDATE gpgmw_locks SET num = '-1', time = ? WHERE ip = ?", array(time(), $ip)); |
||||
return false; |
||||
} else { |
||||
databaseQuery("UPDATE gpgmw_locks SET num = ?, time = ? WHERE ip = ?", array($count, time(), $ip)); |
||||
} |
||||
} |
||||
} else { |
||||
if(time() <= $time + $lock_time_overload[$action]) { |
||||
return false; |
||||
} else { |
||||
//their overload is over, so this entry is old |
||||
$replace_id = $id; |
||||
} |
||||
} |
||||
} else { |
||||
databaseQuery("INSERT INTO gpgmw_locks (ip, time, action, num) VALUES (?, ?, ?, '1')", array($ip, time(), $action)); |
||||
} |
||||
|
||||
if($replace_id != -1) { |
||||
databaseQuery("UPDATE gpgmw_locks SET num = '1', time = ? WHERE id = ?", array(time(), $replace_id)); |
||||
} |
||||
|
||||
//some housekeeping |
||||
$delete_time = time() - $lock_time_max; |
||||
databaseQuery("DELETE FROM gpgmw_locks WHERE time <= ?", array($delete_time)); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,88 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
//returns true on success or error message on failure |
||||
function requestPGP($email, $key) { |
||||
require_once(includePath() . "/lock.php"); |
||||
global $config; |
||||
|
||||
if(!checkLock('requestpgp')) { |
||||
return "please wait a bit before trying again"; |
||||
} |
||||
|
||||
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { |
||||
return "invalid email address"; |
||||
} |
||||
|
||||
if(strlen($email) > 256 || strlen($key) > 1024 * 32) { |
||||
return "email address or key too long"; |
||||
} |
||||
|
||||
if(!isAscii($key)) { |
||||
return "only keys encoded with ASCII armor are accepted (gpg --armor)"; |
||||
} |
||||
|
||||
//housekeeping |
||||
databaseQuery("DELETE FROM gpgmw_keys WHERE time < DATE_SUB(NOW(), INTERVAL 48 HOUR) AND confirm != '' AND status = 0"); |
||||
|
||||
//if we already have an unaccepted key for this user, only replace if one day has elapsed since the last request |
||||
// this may prevent spam |
||||
$result = databaseQuery("SELECT HOUR(TIMEDIFF(time, NOW())), id FROM gpgmw_keys WHERE email = ? AND status = 0", array($email)); |
||||
|
||||
if($row = $result->fetch()) { |
||||
if($row[0] < 24) { |
||||
return "there is already a key in the queue for this email address; please wait twenty-four hours between submitting keys, or confirm the previous key and then resubmit"; |
||||
} else { |
||||
databaseQuery('DELETE FROM gpgmw_keys WHERE id = ?', array($row[1])); |
||||
} |
||||
} |
||||
|
||||
//well, it looks good, let's submit it |
||||
lockAction('requestpgp'); |
||||
$confirm = uid(32); |
||||
$result = gpgmw_mail($config['email_subject_requestpgp'], "Please confirm your email address to complete the submission process. You can do so by clicking the link below\n\n{$config['site_url']}/confirm.php?email=" . urlencode($email) . "&confirm=$confirm\n\nThanks,\ngpg-mailgate-web", $email); |
||||
|
||||
if(!$result) { |
||||
return "failed to send email"; |
||||
} |
||||
|
||||
databaseQuery("INSERT INTO gpgmw_keys (email, publickey, confirm) VALUES (?, ?, ?)", array($email, $key, $confirm)); |
||||
return true; |
||||
} |
||||
|
||||
//returns false on failure or true on success |
||||
function confirmPGP($email, $confirm) { |
||||
if(!lockAction('confirmpgp')) { |
||||
return "try again later"; |
||||
} |
||||
|
||||
$result = databaseQuery("SELECT id FROM gpgmw_keys WHERE confirm = ? AND email = ?", array($confirm, $email)); |
||||
|
||||
if($row = $result->fetch()) { |
||||
databaseQuery("UPDATE gpgmw_keys SET confirm = '' WHERE id = ?", array($row[0])); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,40 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
|
||||
require_once("config.php"); |
||||
require_once("include/common.php"); |
||||
require_once("include/dbconnect.php"); |
||||
require_once("include/pgp.php"); |
||||
|
||||
if(isset($_POST['email']) && isset($_POST['key'])) { |
||||
$result = requestPGP($_POST['email'], $_POST['key']); |
||||
|
||||
if($result === true) { |
||||
get_page("home", array('message' => 'Key submission successful. Please check your email to confirm your email address.')); |
||||
} else { |
||||
get_page("home", array('message' => 'Error: ' . $result . '.')); |
||||
} |
||||
} else { |
||||
get_page("home"); |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,52 @@
|
||||
<?php |
||||
/* |
||||
|
||||
gpg-mailgate |
||||
|
||||
This file is part of the gpg-mailgate source code. |
||||
|
||||
gpg-mailgate 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. |
||||
|
||||
gpg-mailgate source code 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 gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
*/ |
||||
?> |
||||
|
||||
<html> |
||||
<head> |
||||
<title>gpg-mailgate-web</title> |
||||
</head> |
||||
<body> |
||||
<h1><?= $config['site_title'] ?></h1>
|
||||
|
||||
<? if(!empty($message)) { ?> |
||||
<p><b><i><?= htmlspecialchars($message) ?></i></b></p>
|
||||
<? } ?> |
||||
|
||||
<p>Use the form below to submit an ASCII-armored PGP public key. After submission, you will receive an email asking you to confirm your email address. Note that this is not a keyserver.</p> |
||||
|
||||
<form method="POST"> |
||||
<table> |
||||
<tr> |
||||
<td>Your email address (must match key)</td> |
||||
<td><input type="text" name="email" /></td> |
||||
</tr> |
||||
<tr> |
||||
<td>ASCII-armored PGP public key</td> |
||||
<td><textarea name="key" rows="10" cols="80"></textarea></td> |
||||
</tr> |
||||
</table> |
||||
<input type="submit" value="Submit key" /> |
||||
</form> |
||||
|
||||
</body> |
||||
</html> |
@ -0,0 +1,10 @@
|
||||
-- confirm is empty once an email address has been confirmed, and otherwise is the confirmation key |
||||
-- status |
||||
-- initializes to 0 |
||||
-- is set to 1 after a public key with (confirm='', status=0) has been imported |
||||
-- is set to 2 if a key should be deleted (will be deleted based on email address) |
||||
-- publickey is the ASCII-armored PGP public key; can be cleared to save space if status > 0 |
||||
CREATE TABLE gpgmw_keys (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, email VARCHAR(256), publickey TEXT, confirm VARCHAR(32), status INT NOT NULL DEFAULT 0, time TIMESTAMP DEFAULT CURRENT_TIMESTAMP); |
||||
|
||||
-- see include/lock.php for documentation |
||||
CREATE TABLE gpgmw_locks (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, ip VARCHAR(16), time INT, action VARCHAR(16), num INT); |
Loading…
Reference in new issue