[opw-web] Record the IP address when the user accepts a contract



commit fbffdce478fa92061704cdbf275e1a31928773de
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Mon Nov 16 23:16:57 2015 -0500

    Record the IP address when the user accepts a contract
    
    It just might possibly be useful to record the source IP for an
    E-signature (though /most likely/ it has no legal meaning.) So do it.
    In the case of X-Forwarded-From, a config option is added to skip
    the immediate proxy if the site is behind a reverse proxy, and then
    all forwarding addresses are recorded, since we don't know what part
    of the chain is trustworthy.

 classes/class_config.php                  |    3 ++
 classes/class_core.php                    |   21 +++++++++++++
 config.sample.php                         |    4 ++
 lang/en-gb.php                            |    4 ++-
 modules/mod_contract.php                  |   46 +++++++++++++++++++++++++---
 schema.sql                                |    2 +
 skins/easterngreen/html/tpl_contract.html |    2 +-
 7 files changed, 75 insertions(+), 7 deletions(-)
---
diff --git a/classes/class_config.php b/classes/class_config.php
index 4a59ee6..bd9ece7 100644
--- a/classes/class_config.php
+++ b/classes/class_config.php
@@ -40,6 +40,8 @@ class config
     var $per_page;
     var $show_debug;
 
+    var $skip_proxy_ip;
+
     var $ldap_server;
     var $ldap_port;
     var $ldap_base_dn;
@@ -123,6 +125,7 @@ class config
             $this->lang_name        = isset($lang_name) ? $lang_name : 'en-gb';
             $this->per_page         = isset($per_page) ? $per_page : 10;
             $this->show_debug       = isset($show_debug) ? $show_debug : false;
+            $this->skip_proxy_ip    = isset($skip_proxy_ip) ? $skip_proxy_ip : false;
 
             $this->ldap_server      = isset($ldap_server) ? $ldap_server : '';
             $this->ldap_port        = isset($ldap_port) ? $ldap_port : '';
diff --git a/classes/class_core.php b/classes/class_core.php
index 12ea72a..a24689a 100644
--- a/classes/class_core.php
+++ b/classes/class_core.php
@@ -132,6 +132,27 @@ class core
             return 'http://';
     }
 
+    // Returns a space separated list of the chain of contacting IP addresses,
+    // with the closest address or proxy last.
+    function get_remote_addrs()
+    {
+        global $config;
+
+        $ips = '';
+
+        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
+            $ips .= $_SERVER['X_FORWARDED_FOR'];
+
+        if (!$config->skip_proxy_ip && isset($_SERVER['REMOTE_ADDR'])) {
+            if ($ips != '')
+                $ips .= ' ';
+
+            $ips .= $_SERVER['REMOTE_ADDR'];
+        }
+
+        return $ips;
+    }
+
     // Method to replace square brackets with normal braces
     function rss_encode(&$data)
     {
diff --git a/config.sample.php b/config.sample.php
index 529d1e4..d4b8e10 100644
--- a/config.sample.php
+++ b/config.sample.php
@@ -75,6 +75,10 @@ $per_page = 20;
 // Show debug info in the footer
 $show_debug = true;
 
+// Whether when recording the source IP for a request, the immediate
+// remote address should be skipped
+$skip_proxy_ip = false;
+
 // LDAP server address
 $ldap_server = "";
 
diff --git a/lang/en-gb.php b/lang/en-gb.php
index 3568ac2..5d2bd3d 100644
--- a/lang/en-gb.php
+++ b/lang/en-gb.php
@@ -371,6 +371,7 @@ $lang_data = array(
     'review_contract_notice_student'   => 'Please review the following terms of participation as an intern 
in Outreachy. If they are acceptable to you, please type your full name then click on "Accept Agreement" at 
the bottom of the page.',
     'review_contract_notice_mentor'    => 'Please review the following terms of participation as a mentor in 
Outreachy. If they are acceptable to you, please type your full name then click on "Accept Agreement" at the 
bottom of the page.',
     'view_contract_notice'      => 'You accepted the following agreement on: ',
+    'contract_from_notice'      => ', from IP address: ',
     'view_contract_notice_name' => 'You gave your full name as',
     'type_your_name'            => 'Please type your full name',
     'accept_contract'           => "Accept Agreement",
@@ -381,6 +382,7 @@ $lang_data = array(
     'contract_preview_message'           => "This is a preview and not yet saved.",
     'contract_edit_message'     => "Please enter the text of the agreement below using <a 
href='http://daringfireball.net/projects/markdown/syntax'>Markdown</a> syntax",
     'formatted_result'          => "Formatted result",
-    'preview'                   => "Preview"
+    'preview'                   => "Preview",
+    'via'                       => 'via'
 );
 
diff --git a/modules/mod_contract.php b/modules/mod_contract.php
index 46ad28a..3d17bd0 100644
--- a/modules/mod_contract.php
+++ b/modules/mod_contract.php
@@ -144,7 +144,10 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
         $pdf->SetFont('helvetica', '');
         $pdf->write(0, "Full name: " . $row["fullname"] . "\n");
         $pdf->write(0, "Username: " . $row["username"] . "\n");
-        $pdf->write(0, "Role: " . get_role_string($row['role'], $row['has_project']) . "\n");
+
+        $role_string = get_role_string($row['role'], $row['has_project']);
+
+        $pdf->write(0, "Role: " . $role_string . "\n");
         $pdf->write(0, "Email: " . $row["email"] . "\n");
         $pdf->write(0, "\n");
 
@@ -160,10 +163,28 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
         // Now show the signature information
         $pdf->SetFontSize(11);
         $pdf->write(0, "\n");
-        $pdf->write(0, 'E-Signed by "' . $row['contract_entered_name'] . '" on ' . date('M d, Y h:m:s', 
$row['contract_accepted_time']) . ' using ' .$config->site_url);
+        $contract = 'E-Signed';
+        $contract .= ' by "' . $row['contract_entered_name'] . '"';
+        $contract .= ' on ' . date('M d, Y h:m:s', $row['contract_accepted_time']);
+        if ($row['contract_accepted_from'] != '')
+            $contract .= ' from ' . str_replace(' ', ' via ', $row['contract_accepted_from']);
+        $contract .= ' using ' .$config->site_url;
+
+        $pdf->write(0, $contract);
 
         // Insert into the archive
-        $zipfile->addFromString($folder_name . "/" . $row['username'] . '.pdf', $pdf->Output('', 'S'));
+
+        // YYYY-MM-DD_FULL-NAME_Outreachy-2015-05_TYPE-agreement.pdf
+        $file_name = date('Y-M-d', $row['contract_accepted_time']);
+        $file_name .= '_';
+        //        $file_name .= preg_replace('/[^a-zA-Z]+/', '-', $row['contract_entered_name']);
+        $file_name .= $row['contract_entered_name'];
+        $file_name .= '_Outreachy-';
+        $file_name .= date('Y-n', $program_data['start_time']);
+        $file_name .= $role_string;
+        $file_name .= '-agreement.pdf';
+
+        $zipfile->addFromString($folder_name . "/" . $file_name, $pdf->Output('', 'S'));
     }
 
     $zipfile->close();
@@ -184,6 +205,7 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
         $is_student = $action == 'sample_student';
         $is_mentor = $action == 'sample_mentor';
         $contract_accepted_time =  0;
+        $contract_accepted_from = '';
         $contract_entered_name = '';
         $contract_id = NULL;
     } else {        $is_sample = false;
@@ -208,6 +230,7 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
         $user->restrict($role_data['has_project']);
 
         $contract_accepted_time =  $role_data['contract_accepted_time'];
+        $contract_accepted_from = $role_data['contract_accepted_from'];
         $contract_entered_name =  $role_data['contract_entered_name'];
 
         $user->restrict($contract_accepted_time != 0 ||
@@ -250,11 +273,20 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
         $contract_name = trim($core->variable('contract_name', ''));
         $user->restrict($contract_name != '');
 
+        $contract_accepted_from = $core->get_remote_addrs();
+
+        // The most remote addresses are spoofable, so the most reliable
+        // part of the remote addresses is the *end* part, so truncate at
+        // te beginning.
+        if (strlen($contract_accepted_from) > 255)
+          $contract_accepted_from = "... " + substr($contract_accepted_from, -251);
+
         if (!$is_sample) {
             $sql = "UPDATE {$db->prefix}roles " .
                       "SET contract_accepted_time = UNIX_TIMESTAMP(), " .
                       "    contract_id = :contract_id, " .
-                      "    contract_entered_name = :contract_name " .
+                      "    contract_entered_name = :contract_name, " .
+                      "    contract_accepted_from = :contract_accepted_from " .
                     "WHERE username = :username " .
                       "AND program_id = :program_id";
 
@@ -262,7 +294,8 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
                        array('username' => $username,
                              'program_id' => $program_id,
                              'contract_id' => $contract_id,
-                             'contract_name' => $contract_name));
+                             'contract_name' => $contract_name,
+                             'contract_accepted_from' => $contract_accepted_from));
         }
 
         if ($return_url != '')
@@ -270,14 +303,17 @@ if ($action == 'edit_student' || $action == 'edit_mentor') {
     }
 
     $contract_html = Michelf\Markdown::defaultTransform($contract_contents);
+    $via = ' ' . $lang->get('via') . ' ';
 
     $skin->assign(array(
          'view_visibility'   => $skin->visibility($has_accepted),
          'review_visibility' => $skin->visibility(!$has_accepted),
+         'from_visibility' => $skin->visibility($contract_accepted_from != ''),
          'program_mentor_visibility' => $skin->visibility($is_mentor),
          'program_student_visibility' => $skin->visibility($is_student),
          'contract_accepted_time' => date('M d, Y h:m:s', $contract_accepted_time),
          'contract_entered_name' => htmlspecialchars($contract_entered_name),
+         'contract_accepted_from' => htmlspecialchars(str_replace(' ', $via, $contract_accepted_from)),
          'contract_html' => $contract_html,
                  ));
 
diff --git a/schema.sql b/schema.sql
index 729f7db..81b1dfe 100644
--- a/schema.sql
+++ b/schema.sql
@@ -82,6 +82,7 @@ CREATE TABLE `opw_participants` (
 /* alter table opw_roles add `contract_id` mediumint(10) unsigned ; */
 /* alter table opw_roles add foreign key (`contract_id`) references opw_contracts(id) ; */
 /* alter table opw_roles add `contract_entered_name` varchar(255) NOT NULL DEFAULT '' ; */
+/* alter table opw_roles add `contract_accepted_from` varchar(255) NOT NULL DEFAULT '' ; */
 CREATE TABLE `opw_roles` (
   `id` mediumint(10) NOT NULL AUTO_INCREMENT,
   `username` varchar(255) NOT NULL DEFAULT '',
@@ -90,6 +91,7 @@ CREATE TABLE `opw_roles` (
   `role` char(1) NOT NULL DEFAULT 's',
   `contract_approved` tinyint(1) NOT NULL DEFAULT 0,
   `contract_accepted_time` int(11) unsigned NOT NULL DEFAULT 0,
+  `contract_accepted_from` varchar(255) NOT NULL DEFAULT '',
   `contract_entered_name` varchar(255) NOT NULL DEFAULT '',
   `contract_id` mediumint(10) unsigned,
   PRIMARY KEY (`id`),
diff --git a/skins/easterngreen/html/tpl_contract.html b/skins/easterngreen/html/tpl_contract.html
index 1fc9bca..47c1bd0 100644
--- a/skins/easterngreen/html/tpl_contract.html
+++ b/skins/easterngreen/html/tpl_contract.html
@@ -7,7 +7,7 @@
   </div>
 </div>
 <div class="alert [[view_visibility]]">
-  {{view_contract_notice}} [[contract_accepted_time]]. {{view_contract_notice_name}}: 
[[contract_entered_name]]
+  {{view_contract_notice}} [[contract_accepted_time]]<span 
class="[[from_visibility]]">{{contract_from_notice}} [[contract_accepted_from]]</span>. 
{{view_contract_notice_name}}: [[contract_entered_name]]
 </div>
 <div id="contractText" class="contract-text" onscroll="checkSensitive()">[[contract_html]]</div>
 <div class="[[review_visibility]]">


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]