Browse Source

Add PGP keys to user profiles

spaghetti 8 years ago
parent
commit
43b5ec894d
2 changed files with 94 additions and 111 deletions
  1. 25
    14
      sections/user/edit.php
  2. 69
    97
      sections/user/take_edit.php

+ 25
- 14
sections/user/edit.php View File

9
   SELECT
9
   SELECT
10
     m.Username,
10
     m.Username,
11
     m.TwoFactor,
11
     m.TwoFactor,
12
+    m.PublicKey,
12
     m.Email,
13
     m.Email,
13
     m.IRCKey,
14
     m.IRCKey,
14
     m.Paranoia,
15
     m.Paranoia,
24
     JOIN users_info AS i ON i.UserID = m.ID
25
     JOIN users_info AS i ON i.UserID = m.ID
25
     LEFT JOIN permissions AS p ON p.ID = m.PermissionID
26
     LEFT JOIN permissions AS p ON p.ID = m.PermissionID
26
   WHERE m.ID = '".db_string($UserID)."'");
27
   WHERE m.ID = '".db_string($UserID)."'");
27
-list($Username, $TwoFactor, $Email, $IRCKey, $Paranoia, $Info, $Avatar, $StyleID, $StyleURL, $SiteOptions, $UnseededAlerts, $Class, $InfoTitle) = $DB->next_record(MYSQLI_NUM, array(4, 9));
28
+list($Username, $TwoFactor, $PublicKey, $Email, $IRCKey, $Paranoia, $Info, $Avatar, $StyleID, $StyleURL, $SiteOptions, $UnseededAlerts, $Class, $InfoTitle) = $DB->next_record(MYSQLI_NUM, array(5, 10));
28
 
29
 
29
 $TwoFA = new TwoFactorAuth();
30
 $TwoFA = new TwoFactorAuth();
30
 
31
 
56
 }
57
 }
57
 
58
 
58
 if ($SiteOptions) {
59
 if ($SiteOptions) {
59
-  $SiteOptions = json_decode($SiteOptions, true);
60
+  $SiteOptions = json_decode($SiteOptions, true) ?? [];
60
 } else {
61
 } else {
61
   $SiteOptions = [];
62
   $SiteOptions = [];
62
 }
63
 }
162
         <td class="label tooltip" title="Select changes that you want made to your chosen stylesheet"><strong>Stylesheet additions</strong></td>
163
         <td class="label tooltip" title="Select changes that you want made to your chosen stylesheet"><strong>Stylesheet additions</strong></td>
163
         <td> <?
164
         <td> <?
164
           foreach($Stylesheets as $Style) {
165
           foreach($Stylesheets as $Style) {
165
-            $StyleAdditions = explode('|',$Style['Additions']);
166
+            $StyleAdditions = explode('|', $Style['Additions']);
166
             ?> <ul class="nobullet style_addition<?=$Style['ID']==$Stylesheets[$LoggedUser['StyleID']]['ID']?'':' hidden'?>" id="style_addition_<?=$Style['Name']?>"> <?
167
             ?> <ul class="nobullet style_addition<?=$Style['ID']==$Stylesheets[$LoggedUser['StyleID']]['ID']?'':' hidden'?>" id="style_addition_<?=$Style['Name']?>"> <?
167
             foreach($StyleAdditions as $i => $Addition) {
168
             foreach($StyleAdditions as $i => $Addition) {
168
               if ($Addition) { ?>
169
               if ($Addition) { ?>
169
                 <li>
170
                 <li>
170
                 <input type="checkbox" name="style_additions[]" value="<?=$Addition?>" id="addition_<?=$Addition?>"<?=(in_array($Addition, $SiteOptions['StyleAdditions']??[])?' checked="checked"':'')?>>
171
                 <input type="checkbox" name="style_additions[]" value="<?=$Addition?>" id="addition_<?=$Addition?>"<?=(in_array($Addition, $SiteOptions['StyleAdditions']??[])?' checked="checked"':'')?>>
171
-                  <label for="addition_<?=$Addition?>"><?=explode('|',$Style['ProperAdditions'])[$i]?></label>
172
+                  <label for="addition_<?=$Addition?>"><?=explode('|', $Style['ProperAdditions'])[$i]?></label>
172
                 </li>
173
                 </li>
173
            <? }
174
            <? }
174
             }
175
             }
738
           <strong>Access Settings</strong>
739
           <strong>Access Settings</strong>
739
         </td>
740
         </td>
740
       </tr>
741
       </tr>
742
+      <tr id="acc_currentpassword_tr">
743
+        <td class="label"><strong>Current Password</strong></td>
744
+        <td>
745
+          <div class="field_div">
746
+            <input type="password" size="40" name="cur_pass" id="cur_pass" maxlength="307200" value="" />
747
+          </div>
748
+          <strong class="important_text">When changing any of the settings in this section, you must enter your current password in this field before saving your changes</strong>
749
+        </td>
750
+      </tr>
741
       <tr id="acc_resetpk_tr">
751
       <tr id="acc_resetpk_tr">
742
         <td class="label tooltip_interactive" title="For information about the function of your passkey, please &lt;a href=&quot;<?=site_url()?>wiki.php?action=article&amp;amp;name=Passkey&quot;&gt;read this wiki article&lt;/a&gt;." data-title-plain="For information about the function of your passkey, please read the &quot;Passkey&quot; wiki article."><strong>Reset passkey</strong></td>
752
         <td class="label tooltip_interactive" title="For information about the function of your passkey, please &lt;a href=&quot;<?=site_url()?>wiki.php?action=article&amp;amp;name=Passkey&quot;&gt;read this wiki article&lt;/a&gt;." data-title-plain="For information about the function of your passkey, please read the &quot;Passkey&quot; wiki article."><strong>Reset passkey</strong></td>
743
         <td>
753
         <td>
754
           <div class="field_div">
764
           <div class="field_div">
755
             <input type="text" size="50" name="irckey" id="irckey" value="<?=display_str($IRCKey)?>" />
765
             <input type="text" size="50" name="irckey" id="irckey" value="<?=display_str($IRCKey)?>" />
756
           </div>
766
           </div>
757
-          <p class="min_padding">If set, this key will be used instead of your site password when authenticating with <?=BOT_NICK?> on the <a href="wiki.php?action=article&amp;name=IRC">site's IRC network</a>. <span style="white-space: nowrap;">Please note:</span></p>
767
+          <p class="min_padding">This key will be used when authenticating with <?=BOT_NICK?> on the <a href="wiki.php?action=article&amp;name=IRC">site's IRC network</a>. <span style="white-space: nowrap;">Please note:</span></p>
758
           <ul>
768
           <ul>
759
             <li>This value is stored in plaintext and should not be your password.</li>
769
             <li>This value is stored in plaintext and should not be your password.</li>
760
             <li>IRC keys must be between 6 and 32 characters.</li>
770
             <li>IRC keys must be between 6 and 32 characters.</li>
767
           <div class="field_div">
777
           <div class="field_div">
768
             <input type="email" size="50" name="email" id="email" value="<?=display_str($Email)?>" />
778
             <input type="email" size="50" name="email" id="email" value="<?=display_str($Email)?>" />
769
           </div>
779
           </div>
770
-          <p class="min_padding">When changing your email address, you must enter your current password in the "Current password" field before saving your changes.</p>
780
+        </td>
781
+      </tr>
782
+      <tr id="acc_publickey_tr">
783
+        <td class="label tooltip" title="This is your PGP public key. The matching private key can be used to prove ownership of your account should you lose access to your password or 2FA key. Only add a PGP key if you have taken proper precautions like creating a revocation certificate"><strong>PGP Public Key</strong></td>
784
+        <td>
785
+          <div class="field_div">
786
+            <textarea name="publickey" id="publickey" cols="64" rows="8"><?=display_str($PublicKey)?></textarea>
787
+          </div>
771
         </td>
788
         </td>
772
       </tr>
789
       </tr>
773
       <tr id="acc_2fa_tr">
790
       <tr id="acc_2fa_tr">
778
             <? if (!empty($TwoFactor)) { ?>
795
             <? if (!empty($TwoFactor)) { ?>
779
             <p class="min_padding">2FA is enabled for this account with the following secret:</p>
796
             <p class="min_padding">2FA is enabled for this account with the following secret:</p>
780
             <? } ?>
797
             <? } ?>
781
-            <img src="<?=$TwoFA->getQRCodeImageAsDataUri(SITE_NAME, $TwoFASecret)?>">
798
+            <img src="<?=$TwoFA->getQRCodeImageAsDataUri(SITE_NAME, $TwoFASecret)?>"><br>
782
             <input type="text" size="20" name="twofasecret" id="twofasecret" value="<?=$TwoFASecret?>" readonly><br>
799
             <input type="text" size="20" name="twofasecret" id="twofasecret" value="<?=$TwoFASecret?>" readonly><br>
783
             <? if (empty($TwoFactor)) { ?>
800
             <? if (empty($TwoFactor)) { ?>
784
             <input type="text" size="20" maxlength="6" name="twofa" id="twofa" placeholder="Verification Code">
801
             <input type="text" size="20" maxlength="6" name="twofa" id="twofa" placeholder="Verification Code">
785
             <p class="min_padding">To enable 2FA, scan the above QR code (or add the secret below it) to your 2FA client of choice, and enter a verification code it generates. Note that the verification code must not have expired when you save your profile.</p>
802
             <p class="min_padding">To enable 2FA, scan the above QR code (or add the secret below it) to your 2FA client of choice, and enter a verification code it generates. Note that the verification code must not have expired when you save your profile.</p>
786
-            <p class="min_padding">When setting up 2FA, you must enter your current password in the "Current password" field before saving your changes.</p>
787
             <p class="min_padding"><strong class="important_text">WARNING</strong>: Losing your 2FA key can make your account unrecoverable. Only enable it if you're sure you can handle it.
803
             <p class="min_padding"><strong class="important_text">WARNING</strong>: Losing your 2FA key can make your account unrecoverable. Only enable it if you're sure you can handle it.
788
             <? } else { ?>
804
             <? } else { ?>
789
             <label><input type="checkbox" name="disable2fa" id="disable2fa" />
805
             <label><input type="checkbox" name="disable2fa" id="disable2fa" />
790
             Disable 2FA</label>
806
             Disable 2FA</label>
791
-            <p class="min_padding">When disabling 2FA, you must enter your current password in the "Current Password" field before saving your changes</p>
792
             <? } ?>
807
             <? } ?>
793
           </div>
808
           </div>
794
         </td>
809
         </td>
795
       </tr>
810
       </tr>
796
       <tr id="acc_password_tr">
811
       <tr id="acc_password_tr">
797
-        <td class="label"><strong>Change password</strong></td>
812
+        <td class="label"><strong>Password</strong></td>
798
         <td>
813
         <td>
799
-          <div class="field_div">
800
-            <label>Current password:<br>
801
-            <input type="password" size="40" name="cur_pass" id="cur_pass" maxlength="307200" value="" /></label>
802
-          </div>
803
           <div class="field_div">
814
           <div class="field_div">
804
             <label>New password:<br />
815
             <label>New password:<br />
805
             <input type="password" size="40" name="new_pass_1" id="new_pass_1" maxlength="307200" value="" /> <strong id="pass_strength"></strong></label>
816
             <input type="password" size="40" name="new_pass_1" id="new_pass_1" maxlength="307200" value="" /> <strong id="pass_strength"></strong></label>

+ 69
- 97
sections/user/take_edit.php View File

37
   $Val->SetFields('searchtype', 1, "number", "You forgot to select your default search preference.", ['minlength' => 0, 'maxlength' => 1]);
37
   $Val->SetFields('searchtype', 1, "number", "You forgot to select your default search preference.", ['minlength' => 0, 'maxlength' => 1]);
38
 }
38
 }
39
 
39
 
40
-$Err = $Val->ValidateForm($_POST);
41
-
42
-if (!apcu_exists('DBKEY')) {
43
-  $Err = "Cannot edit profile until database fully decrypted.";
40
+$ValErr = $Val->ValidateForm($_POST);
41
+if ($ValErr) {
42
+  error($ValErr);
44
 }
43
 }
45
 
44
 
46
-if ($Err) {
47
-  error($Err);
48
-  header("Location: user.php?action=edit&userid=$UserID");
49
-  die();
45
+if (!apcu_exists('DBKEY')) {
46
+  error("Cannot edit profile until database fully decrypted");
50
 }
47
 }
51
 
48
 
52
 // Begin building $Paranoia
49
 // Begin building $Paranoia
136
 
133
 
137
 // End building $Paranoia
134
 // End building $Paranoia
138
 
135
 
139
-
140
-// Email change
141
 $DB->query("
136
 $DB->query("
142
-  SELECT Email
137
+  SELECT Email, PassHash, TwoFactor, PublicKey, IRCKey
143
   FROM users_main
138
   FROM users_main
144
   WHERE ID = $UserID");
139
   WHERE ID = $UserID");
145
-list($CurEmail) = $DB->next_record();
140
+list($CurEmail, $CurPassHash, $CurTwoFA, $CurPublicKey, $CurIRCKey) = $DB->next_record();
141
+
142
+function require_password($Setting = false) {
143
+  global $CurPassHash;
144
+  if (empty($_POST['cur_pass'])) {
145
+    error('A setting you changed requires you to enter your current password'.($Setting ? ' (Setting: '.$Setting.')' : ''));
146
+  }
147
+  if (!Users::check_password($_POST['cur_pass'], $CurPassHash)) {
148
+    error('The password you entered was incorrect'.($Setting ? ' (Required by setting: '.$Setting.')' : ''));
149
+  }
150
+}
151
+
152
+// Email change
146
 $CurEmail = DBCrypt::decrypt($CurEmail);
153
 $CurEmail = DBCrypt::decrypt($CurEmail);
147
 if ($CurEmail != $_POST['email']) {
154
 if ($CurEmail != $_POST['email']) {
148
-  if (!check_perms('users_edit_profiles')) { // Non-admins have to authenticate to change email
149
-    $DB->query("
150
-      SELECT PassHash
151
-      FROM users_main
152
-      WHERE ID = '".db_string($UserID)."'");
153
-    list($PassHash)=$DB->next_record();
154
-    if (!Users::check_password($_POST['cur_pass'], $PassHash)) {
155
-      $Err = 'You did not enter the correct password.';
156
-    }
155
+
156
+  // Non-admins have to authenticate to change email
157
+  if (!check_perms('users_edit_profiles')) {
158
+    require_password("Change Email");
157
   }
159
   }
158
-  if (!$Err) {
159
-    $NewEmail = db_string($_POST['email']);
160
 
160
 
161
+  $NewEmail = db_string($_POST['email']);
161
 
162
 
162
-    //This piece of code will update the time of their last email change to the current time *not* the current change.
163
-    $ChangerIP = db_string($LoggedUser['IP']);
164
-    $DB->query("
165
-      UPDATE users_history_emails
166
-      SET Time = '".sqltime()."'
167
-      WHERE UserID = '$UserID'
168
-        AND Time IS NULL");
169
-    $DB->query("
170
-      INSERT INTO users_history_emails
171
-        (UserID, Email, Time, IP)
172
-      VALUES
173
-        ('$UserID', '".DBCrypt::encrypt($NewEmail)."', NULL, '".DBCrypt::encrypt($_SERVER['REMOTE_ADDR'])."')");
163
+  // Update the time of their last email change to the current time *not* the current change.
164
+  $ChangerIP = db_string($LoggedUser['IP']);
165
+  $DB->query("
166
+    UPDATE users_history_emails
167
+    SET Time = '".sqltime()."'
168
+    WHERE UserID = '$UserID'
169
+      AND Time IS NULL");
170
+  $DB->query("
171
+    INSERT INTO users_history_emails
172
+      (UserID, Email, Time, IP)
173
+    VALUES
174
+      ('$UserID', '".DBCrypt::encrypt($NewEmail)."', NULL, '".DBCrypt::encrypt($_SERVER['REMOTE_ADDR'])."')");
174
 
175
 
175
-  } else {
176
-    error($Err);
177
-    header("Location: user.php?action=edit&userid=$UserID");
178
-    die();
179
-  }
180
 }
176
 }
181
-//End email change
182
 
177
 
183
-//2FA activation
184
-if (!empty($_POST['twofa'])) {
178
+// PGP Key
179
+if ($CurPublicKey != $_POST['publickey']) {
180
+  require_password("Change Public Key");
185
   $DB->query("
181
   $DB->query("
186
-    SELECT TwoFactor, PassHash
187
-    FROM users_main
182
+    UPDATE users_main
183
+    SET PublicKey = '".db_string($_POST['publickey'])."'
188
     WHERE ID = $UserID");
184
     WHERE ID = $UserID");
189
-  list($TwoFactor, $PassHash) = $DB->next_record();
190
-  if (empty($TwoFactor)) {
191
-    if (!Users::check_password($_POST['cur_pass'], $PassHash)) {
192
-      error('You did not enter the correct password.');
193
-      header("Location: user.php?action=edit&userid=$UserID");
194
-      die();
195
-    }
196
-    require_once SERVER_ROOT.'/classes/twofa.class.php';
197
-    $TwoFA = new TwoFactorAuth(SITE_NAME);
198
-    if ($TwoFA->verifyCode($_POST['twofasecret'], $_POST['twofa'])) {
199
-      $DB->query("
200
-        UPDATE users_main
201
-        SET TwoFactor='".db_string($_POST['twofasecret'])."'
202
-        WHERE ID = $UserID");
203
-    } else {
204
-      error('Invalid 2FA verification code.');
205
-      header("Location: user.php?action=edit&userid=$UserID");
206
-      die();
207
-    }
185
+}
186
+
187
+// 2FA activation
188
+if (!empty($_POST['twofa']) && empty($CurTwoFA)) {
189
+  require_password("Enable 2-Factor");
190
+  require_once SERVER_ROOT.'/classes/twofa.class.php';
191
+  $TwoFA = new TwoFactorAuth(SITE_NAME);
192
+  if ($TwoFA->verifyCode($_POST['twofasecret'], $_POST['twofa'])) {
193
+    $DB->query("
194
+      UPDATE users_main
195
+      SET TwoFactor='".db_string($_POST['twofasecret'])."'
196
+      WHERE ID = $UserID");
197
+  } else {
198
+    error('Invalid 2FA verification code.');
208
   }
199
   }
209
 }
200
 }
210
 
201
 
211
-//2FA deactivation
202
+// 2FA deactivation
212
 if (isset($_POST['disable2fa'])) {
203
 if (isset($_POST['disable2fa'])) {
213
-  $DB->query("
214
-    SELECT PassHash
215
-    FROM users_main
216
-    WHERE ID = $UserID");
217
-  list($PassHash) = $DB->next_record();
218
-  if (!Users::check_password($_POST['cur_pass'], $PassHash)) {
219
-      error('You did not enter the correct password.');
220
-      header("Location: user.php?action=edit&userid=$UserID");
221
-      die();
222
-  }
204
+  require_password("Disable 2-Factor");
223
   $DB->query("
205
   $DB->query("
224
     UPDATE users_main
206
     UPDATE users_main
225
-    SET TwoFactor=NULL
207
+    SET TwoFactor = NULL
226
     WHERE ID = $UserID");
208
     WHERE ID = $UserID");
227
 }
209
 }
228
-//End 2FA
229
 
210
 
230
-if (!$Err && ($_POST['cur_pass'] || $_POST['new_pass_1'] || $_POST['new_pass_2'])) {
231
-  $DB->query("
232
-    SELECT PassHash
233
-    FROM users_main
234
-    WHERE ID = '".db_string($UserID)."'");
235
-  list($PassHash) = $DB->next_record();
236
-
237
-  if (Users::check_password($_POST['cur_pass'], $PassHash)) {
238
-    if ($_POST['new_pass_1'] && $_POST['new_pass_2']) {
239
-      $ResetPassword = true;
240
-    }
241
-  } else {
242
-    $Err = 'You did not enter the correct password.';
243
-  }
211
+if (!empty($_POST['new_pass_1']) && !empty($_POST['new_pass_2'])) {
212
+  require_password("Change Password");
213
+  $ResetPassword = true;
244
 }
214
 }
245
 
215
 
246
-if ($LoggedUser['DisableAvatar'] && $_POST['avatar'] != $U['Avatar']) {
247
-  $Err = 'Your avatar privileges have been revoked.';
216
+if ($CurIRCKey != $_POST['irckey']) {
217
+  require_password("Change IRC Key");
248
 }
218
 }
249
 
219
 
250
-if ($Err) {
251
-  error($Err);
252
-  header("Location: user.php?action=edit&userid=$UserID");
253
-  die();
220
+if (isset($_POST['resetpasskey'])) {
221
+  require_password("Reset Passkey");
222
+}
223
+
224
+if ($LoggedUser['DisableAvatar'] && $_POST['avatar'] != $U['Avatar']) {
225
+  error('Your avatar privileges have been revoked.');
254
 }
226
 }
255
 
227
 
256
 if (!empty($LoggedUser['DefaultSearch'])) {
228
 if (!empty($LoggedUser['DefaultSearch'])) {

Loading…
Cancel
Save