Browse code

Ermögliche das Setzen des PGP-Keys beim Editieren der Adresse

Bernd Wurst authored on02/03/2018 18:26:24
Showing9 changed files
1 1
similarity index 100%
2 2
rename from images/secure.png
3 3
rename to images/key.png
4 4
new file mode 100644
... ...
@@ -0,0 +1,42 @@
1
+<?php
2
+/*
3
+This file belongs to the Webinterface of schokokeks.org Hosting
4
+
5
+Written 2008-2018 by schokokeks.org Hosting, namely
6
+  Bernd Wurst <bernd@schokokeks.org>
7
+  Hanno Böck <hanno@schokokeks.org>
8
+
9
+To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
10
+
11
+You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see 
12
+http://creativecommons.org/publicdomain/zero/1.0/
13
+
14
+Nevertheless, in case you use a significant part of this code, we ask (but not require, see the license) that you keep the authors' names in place and return your changes to the public. We would be especially happy if you tell us what you're going to do with this code.
15
+*/
16
+
17
+require_once('contacts.php');
18
+
19
+if (isset($_GET['q'])) {
20
+    $id = search_pgp_key($_GET['q']);
21
+    $result = array("status" => "notfound",
22
+        "id" => NULL);
23
+    if ($id) {
24
+        $result['status'] = 'found';
25
+        $result['id'] = $id;
26
+    }
27
+    echo json_encode($result);
28
+    die();
29
+}
30
+if (isset($_GET['id'])) {
31
+    $id = fetch_pgp_key($_GET['id']);
32
+    $result = array("status" => "notfound", "id" => NULL);
33
+    if ($id) {
34
+        $result['status'] = 'found';
35
+        $result['id'] = $id;
36
+    }
37
+    echo json_encode($result);
38
+    die();
39
+}
40
+
41
+
42
+
... ...
@@ -27,6 +27,34 @@ function check_number( field )
27 27
     }
28 28
 }
29 29
 
30
+
31
+function receive_pgpidcheck(result) {
32
+    if (result.status == 'found') {
33
+        $('#pgpid').val(result.id);
34
+        $("#pgpid_feedback").html('<img src="../../images/ok.png" style="height: 16px; width: 16px;" />');
35
+    } else {
36
+        $('#pgpkey').closest('tr').show();
37
+        $("#pgpid_feedback").html('<img src="../../images/error.png" style="height: 16px; width: 16px;" /><br>Es wurde kein PGP-Key zu dieser ID gefunden. Bitte geben Sie unten den kompletten Key ein.');
38
+
39
+    }
40
+}
41
+
42
+
43
+function receive_pgpid(result) {
44
+    if (result.status == 'found' && ! $('#pgpid').val()) {
45
+        $('#pgpid').val(result.id);
46
+        $("#pgpid_feedback").html('<img src="../../images/ok.png" style="height: 16px; width: 16px;" /><br>Es wurde ein PGP-Key auf einem Keyserver gefunden. Falls Sie einen anderen (oder gar keinen) PGP-Key nutzen möchten, ändern Sie dies bitte hier.');
47
+    }
48
+}
49
+
50
+function pgpid_change() {
51
+    val = $('#pgpid').val().replace(/\s/g, "");;
52
+    if (val.length == 8 || val.length == 16 || val.length == 40) {
53
+        $.getJSON("ajax_pgp?id="+encodeURIComponent(val), receive_pgpidcheck)
54
+    }
55
+}
56
+
57
+
30 58
 function email_change() {
31 59
     var new_email = $('#email').val();
32 60
     if (new_email != old_email) {
... ...
@@ -34,16 +62,21 @@ function email_change() {
34 62
     } else {
35 63
         $('#designated-row').hide();
36 64
     }
65
+    if (new_email && ! $('#pgpid').val()) {
66
+        $.getJSON("ajax_pgp?q="+encodeURIComponent(new_email), receive_pgpid)
67
+    }
37 68
 }
38 69
 
39 70
 $(function() {
40
-    $('#telefon').on("change paste", check_number("telefon") );
41
-    $('#mobile').on("change paste", check_number("mobile") );
42
-    $('#telefax').on("change paste", check_number("telefax") );
71
+    $('#telefon').on("focusout", check_number("telefon") );
72
+    $('#mobile').on("focusout", check_number("mobile") );
73
+    $('#telefax').on("focusout", check_number("telefax") );
43 74
     
44 75
     if ($('#designated-row')) {
45 76
         $('#designated-row').hide();
46
-        $('#email').on("change paste", email_change);
47 77
         old_email = $('#email').val();
48 78
     }
79
+    $('#email').on("focusout", email_change);
80
+    $('#pgpid').on("focusout", pgpid_change);
81
+    $('#pgpkey').closest('tr').hide();
49 82
 });
... ...
@@ -76,10 +76,14 @@ $html .= '<tr class="'.($odd == true ? 'odd' : 'even').'"><td><label for="telefo
76 76
 $odd = !$odd;
77 77
 
78 78
 if ($domains) {
79
-    $html .= '<tr class="'.($odd == true ? 'odd' : 'even').'" id="designated-row"><td><label for="designated"><strong>Inhaberwechsel:</strong></label></td><td><input type="checkbox" name="designated" id="designated" value="yes"><label for="designated">Die Änderung der E-Mail-Adresse bewirkt rechtlich einen Inhaberwechsel. Ich bestätige, dass mir eine explizite Zustimmung des alten und neuen Inhabers für diese Änderung vorliegt. Eine Speicherung der Änderungen ist nur mit dieser Zustimmung möglich.</label></td></tr>';
80
-    $odd = !$odd;
79
+    $html .= '<tr class="odd" id="designated-row"><td><label for="designated"><strong>Inhaberwechsel:</strong></label></td><td><input type="checkbox" name="designated" id="designated" value="yes"><label for="designated">Die Änderung der E-Mail-Adresse bewirkt rechtlich einen Inhaberwechsel. Ich bestätige, dass mir eine explizite Zustimmung des alten und neuen Inhabers für diese Änderung vorliegt. Eine Speicherung der Änderungen ist nur mit dieser Zustimmung möglich.</label></td></tr>';
81 80
 }
82 81
 
82
+$html .= '<tr class="'.($odd == true ? 'odd' : 'even').'"><td><label for="pgpid">PGP-Key-ID:</label></td><td><input type="text" name="pgpid" id="pgpid" value="'.$c['pgp_id'].'"><span id="pgpid_feedback"></span></td></tr>';
83
+$odd = !$odd;
84
+$html .= '<tr class="'.($odd == true ? 'odd' : 'even').'"><td><label for="pgpkey">PGP-Key (ASCII-Armored):</label></td><td><textarea name="pgpkey" id="pgpkey">'.$c['pgp_key'].'</textarea></td></tr>';
85
+$odd = !$odd;
86
+
83 87
 $html .= '<tr class="even"><td>&nbsp;</td><td><input type="submit" value="Speichern" /></td></tr>';
84 88
 $html .= '</table>';
85 89
 
... ...
@@ -15,6 +15,7 @@ Nevertheless, in case you use a significant part of this code, we ask (but not r
15 15
 */
16 16
 
17 17
 require_once('inc/debug.php');
18
+require_once('inc/security.php');
18 19
 require_role(array(ROLE_CUSTOMER));
19 20
 require_once('class/domain.php');
20 21
 
... ...
@@ -306,6 +307,59 @@ function delete_contact($id) {
306 307
 }
307 308
 
308 309
 
310
+function search_pgp_key($search) {
311
+    if (! check_emailaddr($search)) {
312
+        # Keine Ausgabe weil diese Funktion im AJAX-Call verwendet wird
313
+        return NULL;
314
+    }
315
+    $output = array();
316
+    exec('LC_ALL=C /usr/bin/gpg --batch --with-colons --keyserver hkp://pool.sks-keyservers.net --search-key '.escapeshellarg($search), $output);
317
+    DEBUG($output);
318
+    $keys = array();
319
+    foreach($output AS $row) {
320
+        if (substr($row, 0, 4) === 'pub:') {
321
+            $parts = explode(':', $row);
322
+            if ($parts[5] && ($parts[5] < time())) {
323
+                // abgelaufener key
324
+                continue;
325
+            }
326
+            // array-key = create-timestamp
327
+            // array-value = key-id
328
+            $keys[$parts[4]] = $parts[1];
329
+        }
330
+    }
331
+    if (count($keys) == 0) {
332
+        return NULL;
333
+    }
334
+    ksort($keys, SORT_NUMERIC);
335
+    DEBUG(end($keys));
336
+    // liefert den neuesten Key
337
+    return end($keys);
338
+}
339
+
340
+
341
+function fetch_pgp_key($pgp_id) {
342
+    $output = array();
343
+    $ret = NULL;
344
+    DEBUG('/usr/bin/gpg --batch --keyserver hkp://pool.sks-keyservers.net --recv-key '.escapeshellarg($pgp_id));
345
+    exec('/usr/bin/gpg --batch --keyserver hkp://pool.sks-keyservers.net --recv-key '.escapeshellarg($pgp_id), $output, $ret);
346
+    DEBUG($output);
347
+    DEBUG($ret);
348
+    if ($ret == 0) {
349
+        exec('/usr/bin/gpg --batch --with-colons --list-keys '.escapeshellarg($pgp_id), $output);
350
+        DEBUG($output);
351
+        foreach ($output AS $row) {
352
+            if (substr($row, 0, 4) === 'fpr:') {
353
+                $parts = explode(':', $row);
354
+                // Fingerprint
355
+                return $parts[9];
356
+            }
357
+        }
358
+    }
359
+    return NULL;
360
+}
361
+
362
+
309 363
 function domainlist_by_contact($c) {
310 364
     $cid = (int) $_SESSION['customerinfo']['customerno'];
311 365
     $result = db_query("SELECT id FROM kundendaten.domains WHERE (owner=? OR admin_c=?) AND kunde=?", array($c['id'], $c['id'], $cid));
... ...
@@ -333,9 +387,16 @@ function contact_as_string($contact)
333 387
         $email = "<strike>$email</strike><br/>".filter_input_general($new_email).footnote('Die E-Mail-Adresse wurde noch nicht bestätigt');
334 388
     }
335 389
     $email = implode("<br>\n", array_filter(array($email, filter_input_general($contact['phone']), filter_input_general($contact['fax']), filter_input_general($contact['mobile']))));
336
- 
337
-
338
-    $contact_string = "<p class=\"contact-id\">#{$contact['id']}</p><p class=\"contact-address\"><strong>$name</strong>$adresse</p><p class=\"contact-contact\">$email</p>";
390
+    $pgp = '';
391
+    if ($contact['pgp_id']) {
392
+        $pgpid = $contact['pgp_id'];
393
+        if (strlen($pgpid) > 20) {
394
+            $pgpid = substr($pgpid, 0, 20).' '.substr($pgpid, 20);
395
+        }
396
+        $pgp = '<p class="contact-pgp">'.other_icon('key.png').' PGP ID:<br>'.$pgpid.'</p>';
397
+    }
398
+  
399
+    $contact_string = "<p class=\"contact-id\">#{$contact['id']}</p><p class=\"contact-address\"><strong>$name</strong>$adresse</p><p class=\"contact-contact\">$email</p>$pgp";
339 400
     return $contact_string;
340 401
 }
341 402
 
... ...
@@ -60,7 +60,7 @@ foreach ($liste as $id) {
60 60
     } else {
61 61
         $usage = "Zur Zeit unbenutzt";
62 62
     }
63
-    output(internal_link('useas', display_contact($contact, "<p class=\"contact-usage\">$usage</p>", $cssclass), 'id='.$contact['id'], 'class="contacts-choose"'));
63
+   output(internal_link('useas', display_contact($contact, "<p class=\"contact-usage\">$usage</p>", $cssclass), 'id='.$contact['id'], 'class="contacts-choose"'));
64 64
 }
65 65
 output("</div><br />");
66 66
 addnew('edit', 'Neue Adresse erstellen', 'id=new');
... ...
@@ -136,7 +136,19 @@ if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'delete') {
136 136
         $c['fax'] = NULL;
137 137
     }
138 138
 
139
-    // FIXME: PGP-ID/Key fehlen
139
+    
140
+    if (isset($_REQUEST['pgpid'])) {
141
+        $pgpid = preg_replace('/[^0-9a-fA-F]/', '', $_REQUEST['pgpid']);
142
+        DEBUG('PGP-ID: '.$pgpid.' / Länge: '.strlen($pgpid));
143
+        if (strlen($pgpid) == 8 || strlen($pgpid) == 16 || strlen($pgpid) == 40) {
144
+            $c['pgp_id'] = $_REQUEST['pgpid'];
145
+            if (isset($_REQUEST['pgpkey']) && $_REQUEST['pgpkey']) {
146
+                $c['pgp_key'] = $_REQUEST['pgpkey'];
147
+            }
148
+        } else {
149
+            warning('Ihre PGP-ID wurde nicht übernommen, da sie syntaktisch falsch erscheint');
150
+        }
151
+    }
140 152
 
141 153
 
142 154
     if (isset($_REQUEST['domainholder']) && $_REQUEST['domainholder'] == 1) {
... ...
@@ -52,7 +52,7 @@ if ($_SESSION['role'] & ROLE_SYSTEMUSER) {
52 52
     $shortcuts[] = array( 'section' => 'Webserver', 
53 53
                           'weight'  => 80, 
54 54
                           'file'    => 'certs', 
55
-                          'icon'    => 'secure.png', 
55
+                          'icon'    => 'key.png', 
56 56
                           'title'   => 'HTTPS-Zertifikate',
57 57
                           'alert'   => $alert );
58 58
   }
... ...
@@ -129,7 +129,7 @@ if (count($vhosts) > 0)
129 129
     }
130 130
     elseif ($vhost['cert'])
131 131
     {
132
-      output("<td>".other_icon("secure.png", "HTTPS mit eigenem Zertifikat")."</td>");
132
+      output("<td>".other_icon("key.png", "HTTPS mit eigenem Zertifikat")."</td>");
133 133
     }
134 134
     elseif (strstr($vhost['options'], "letsencrypt")) {
135 135
       // Letsencrypt gewählt aber noch nicht aktiv