Exemplo n.º 1
0
function searchUsers($get)
{
    /***
     *
     ***/
    global $udb, $login_status;
    $q = $udb->sanitize($get['q']);
    $response = array('search' => $q);
    $search = array('username' => $q, 'name' => $q, 'dblink' => $q);
    $cols = array('username', 'name', 'dblink', "email_verified", "alternate_email_verified", "admin_flag", "alternate_email");
    if (!empty($get['cols'])) {
        if (checkUserColumnExists($get['cols'], false)) {
            # Replace the defaults
            $colList = explode(',', $get['cols']);
            $search = array();
            foreach ($colList as $col) {
                $col = trim($col);
                # If the column exists, we don't have to sanitize it
                # $col = $db->sanitize($col);
                $search[$col] = $q;
                $cols[] = $col;
            }
        } else {
            $response['notice'] = 'Invalid columns; defaults used';
            $response["detail"] = checkUserColumnExists($get["cols"], false, true);
        }
    }
    $response['status'] = true;
    $result = $udb->getQueryResults($search, $cols, 'OR', true, true);
    $suFlag = $login_status['detail']['userdata']['su_flag'];
    $isSu = boolstr($suFlag);
    $adminFlag = $login_status['detail']['userdata']['admin_flag'];
    $isAdmin = boolstr($adminFlag);
    foreach ($result as $k => $entry) {
        $clean = array('email' => $entry['username'], 'uid' => $entry['dblink'], "has_verified_email" => boolstr($entry["email_verified"]) || boolstr($entry["alternate_email_verified"]));
        if ($isAdmin) {
            $clean["is_admin"] = boolstr($entry["admin_flag"]);
            $clean["alternate_email"] = $entry["alternate_email"];
            $tmpUser = new UserFunctions($clean["email"]);
            $clean["unrestricted"] = $tmpUser->meetsRestrictionCriteria();
        }
        $nameXml = $entry['name'];
        $xml = new Xml();
        $xml->setXml($nameXml);
        $clean['first_name'] = htmlspecialchars_decode($xml->getTagContents('fname'));
        $clean['last_name'] = htmlspecialchars_decode($xml->getTagContents('lname'));
        $clean['full_name'] = htmlspecialchars_decode($xml->getTagContents('name'));
        $clean['handle'] = $xml->getTagContents('dname');
        $result[$k] = $clean;
    }
    $response['result'] = $result;
    $response['count'] = sizeof($result);
    returnAjax($response);
}
        $deferredJS .= "console.log('Needs phone? '," . strbool($needPhone) . "," . DBHelper::staticSanitize($user->getPhone()) . ");\n";
        $altPhone = "<p>Congratulations! Your phone number is verified.</p>";
    } catch (Exception $e) {
        $needPhone = false;
        $deferredJS .= "console.warn('An exception was thrown checking for SMS-ability:','" . $e->getMessage() . "');\n";
        $altPhone = "<p>You don't have a phone number registered with us. Please go to account settings and add a phone number.</p>";
    }
    $verifyphone_link = $needPhone ? "<li><a href='?q=verify'>Verify Phone</a></li>" : null;
    $phone_verify_form = $needPhone ? $phone_verify_template : $altPhone;
} catch (Exception $e) {
    # There have been no cookies set.
    $logged_in = false;
    $twofactor = "Please log in.";
}
if ($logged_in) {
    $xml->setXml($_COOKIE[$cookieperson]);
    $full_name = $xml->getTagContents("<name>");
    $first_name = $xml->getTagContents("<fname>");
    $display_name = $xml->getTagContents("<dname>");
    if (empty($first_name)) {
        $first_name = $_COOKIE[$cookieperson];
    }
} else {
    if ($captive_login) {
        header("Refresh: 0; url={$baseurl}");
        $deferredJS .= "\nwindow.location.href=\"{$baseurl}\";";
    }
}
// $random = "<li><a href='#' id='totp_help'>Help with Two-Factor Authentication</a></li>";
try {
    $has2fa = strbool($user->has2FA());
 private function changeUserPassword($oldPassword, $newPassword = null, $isResetPassword = false)
 {
     /***
      * Replace the password stored.
      * If there are any encrypted fields, decrypt them and re-encrypt them in the process.
      * Trash the encrypted fields if we're resetting.
      * Update the cookies.
      *
      * @param string|array $oldPassword If the password is being
      *                                  reset, then $oldPassword
      *                                  should be an array with the
      *                                  keys "key" and
      *                                  "verify". Otherwise, it should
      *                                  be the plain-text string of
      *                                  the old password.
      * @param string $newPassword If $isResetPassword is true,
      *                            this field can be "true" to
      *                            email the new password.
      *
      * @param bool $isResetPassword Is the password being reset?
      ***/
     try {
         if ($isResetPassword === true) {
             $userdata = $this->getUser();
             if (empty($userdata)) {
                 throw new Exception('Base user not set');
             }
             $doEmailPassword = $newPassword === true;
             # We can't verify the old password, so we have to verify the
             # reset token provided under $oldPassword instead
             if (!is_array($oldPassword)) {
                 throw new Exception('Bad credential format');
             }
             $key = $oldPassword['key'];
             $verify = $oldPassword['verify'];
             if (empty($key) or empty($verify)) {
                 throw new Exception('Not all required credentials were provided');
             }
             # Now, we verify the supplied credentials
             $pw_data = json_decode($userdata[$this->pwColumn], true);
             $salt = $pw_data['salt'];
             # Pull the secret from the temp column
             $secret = $this->getSecret(true);
             $string = self::decryptThis($key, $secret, $this->getIV());
             $test_string = $salt . $string;
             $match_token = substr(hash('md5', $test_string), 0, 8);
             if ($match_token != $verify) {
                 # The computed token doesn't match the provided one
                 // $testPass = "******";
                 // $method = self::getPreferredCipherMethod();
                 // $iv = self::getIV();
                 // $testPass = md5($testPass);
                 // $foo = openssl_encrypt("FooBar", $method, $testPass, 0, $iv);
                 // $foo64 = base64_encode($foo);
                 // $bar64 = openssl_decrypt(base64_decode($foo64), $method, $testPass, 0, $iv);
                 // $bar = openssl_decrypt($foo, $method, $testPass, 0, $iv);
                 // $barTrim = rtrim($bar, "\0");
                 // $barTrim64 = rtrim($bar64, "\0");
                 // $testPass = substr($testPass, 0, 8);
                 // $faz = self::encryptThis("FooBar", $testPass, $this->getIV());
                 // $baz = self::decryptThis($faz, $testPass);
                 #throw( new Exception('Invalid reset tokens (got '.$string.' and match '.$match_token.' from '.$salt.' and '.$secret.' [input->'.$key.':'.$verify.' with iv '.$this->getIV().']). Tested '.$foo.' decoding to '.$bar.' with '.$method. " (64: $foo64 to $bar64 to $barTrim64 vs ".$barTrim.") Also $faz -> $baz and " . openssl_error_string() ) );
                 throw new Exception('Invalid reset tokens');
             }
             # The token matches -- let's make them a new password and
             # provide it.
             if (!class_exists('Stronghash')) {
                 require_once dirname(__FILE__) . '/../core/stronghash/php-stronghash.php';
             }
             $newPassword = self::createRandomUserPassword();
             $hash = new Stronghash();
             $pw1 = $hash->hasher($newPassword);
             $pwStore = json_encode($pw1);
             # We don't need or want to recalculate a hardlink. The old
             # salt isn't used anywhere where the old value is relevant.
             $algo = $pw1['algo'];
             $rounds = $pw1['rounds'];
             # We need to update the "data" column with the $algo and
             # $rounds data
             $data = $userdata['data'];
             $xml = new Xml();
             $xml->setXml($data);
             $data = $xml->updateTag('<rounds>', $this->sanitize($rounds));
             $data = $xml->updateTag('<algo>', $this->sanitize($algo));
             /*
              * We can't use writeToUser() since it requires user
              * validation, which we don't have by definition, so we're
              * going to manually construct the query here.
              */
             $query = 'UPDATE `' . $this->getTable() . '` SET `' . $this->pwColumn . '`="' . $this->sanitize($pwStore, true) . '", `data`="' . $data . '" WHERE `' . $this->userColumn . "`='" . $this->getUsername() . "'";
             $l = $this->openDB();
             mysqli_query($l, 'BEGIN');
             $r = mysqli_query($l, $query);
             $finish_query = $r ? 'COMMIT' : 'ROLLBACK';
             $callback = array('status' => $r, 'action' => $finish_query, 'new_password' => $newPassword, 'new_password_length' => strlen($newPassword), 'minimum_length' => $this->getMinPasswordLength(), 'maximum_length' => 8192);
             if ($finish_query == 'ROLLBACK') {
                 $callback['error'] = mysqli_error($l);
                 $callback['new_password'] = null;
             }
             $r2 = mysqli_query($l, $finish_query);
             $callback['status'] = $r && $r2;
             if ($r2 !== true) {
                 $callback['error'] = 'Unable to commit your password reset';
             }
             if ($callback['status'] === true) {
                 $verifySetPw = $this->lookupUser($this->getUsername(), $newPassword, false);
                 $callback['verification_data'] = $verifySetPw['status'];
                 # It all worked, remove the secret
                 $this->setTempSecret();
                 if ($doEmailPassword === true) {
                     $mail = $this->getMailObject();
                     $mail->Subject = '[' . $this->getDomain() . '] New Password';
                     $mail->Body = "<p>You've successfully reset the password to " . $this->getDomain() . ". Here is your new password:.</p><pre>{$newPassword}</pre><p>If you didn't request a password change, please log in and change your password IMMEDIATELY, and we suggest adding two-factor authentication.</p>.";
                     $mail->addAddress($this->getUsername());
                     $status = $mail->send();
                     $mailDetail = array('status' => $status, 'method' => 'email');
                     if (!$status) {
                         $mailDetail['error'] = $mail->ErrorInfo;
                     }
                     $callback['mail_details'] = $mailDetail;
                 }
             }
             $callback['mail_requested'] = $doEmailPassword;
             return $callback;
         } else {
             # We want to look at the current user, and make sure it's OK
             # before re-assigning the password
             $userLookup = $this->lookupUser($this->getUsername(), $oldPassword);
             # If this user checks out, now we can overwrite their old password
             if ($userLookup['status'] === false) {
                 # Bad user
                 throw new Exception('Invalid original credentials');
             }
             $currentUser = $userLookup['data'];
             if (strlen($newPassword) < $this->getMinPasswordLength()) {
                 throw new Exception('New password is too short. It should be at least ' . $this->getMinPasswordLenght() . ' characters');
             }
             $currentUser = $userLookup['data'];
             if (strlen($newPassword) < $this->getMinPasswordLength()) {
                 throw new Exception('New password is too short. It should be at least ' . $this->getMinPasswordLength() . ' characters');
             }
             if (strlen($newPassword) > 8192) {
                 throw new Exception('New password is too long. It should be less than 8192 characters');
             }
             if (!class_exists('Stronghash')) {
                 require_once dirname(__FILE__) . '/../core/stronghash/php-stronghash.php';
             }
             $hash = new Stronghash();
             $hashedPw = $hash->hasher($newPassword);
             $pwStore = json_encode($hashedPw);
             # We don't need or want to recalculate a hardlink. The old
             # salt isn't used anywhere where the old value is relevant.
             $algo = $hashedPw['algo'];
             $rounds = $hashedPw['rounds'];
             # We need to update the "data" column with the $algo and
             # $rounds data
             $xml = new Xml();
             $xml->setXml($data);
             $data = $currentUser['data'];
             $backupData = $data;
             $backupPassword = $currentUser[$this->pwColumn];
             $data = $xml->updateTag('<rounds>', $this->sanitize($rounds));
             $data = $xml->updateTag('<algo>', $this->sanitize($algo));
             /*
              * We can't use writeToUser() since it requires user
              * validation, and the second part of the update will always fail.
              * So, we're going to manually construct the query here.
              */
             $l = $this->openDB();
             $query = 'UPDATE `' . $this->getTable() . '` SET `' . $this->pwColumn . '`="' . mysqli_real_escape_string($l, $pwStore) . '", `data`="' . mysqli_real_escape_string($l, $data) . '" WHERE `' . $this->userColumn . "`='" . $this->getUsername() . "'";
             mysqli_query($l, 'BEGIN');
             $r = mysqli_query($l, $query);
             $finish_query = $r ? 'COMMIT' : 'ROLLBACK';
             $callback = array('status' => $r, 'action' => $finish_query, 'new_password' => $newPassword);
             if ($finish_query == 'ROLLBACK') {
                 $callback['error'] = mysqli_error($l);
             }
             $r2 = mysqli_query($l, $finish_query);
             $callback['status'] = $r && $r2;
             if ($callback['status']) {
                 $verifySetPw = $this->lookupUser($this->getUsername(), $newPassword, false);
                 $callback['verification_data'] = $verifySetPw['status'];
                 if (!$verifySetPw['status']) {
                     # verify setting with a lookup
                     # if bad, revert to old
                     # if reset, try again
                     $revert = array();
                     $query2 = 'UPDATE `' . $this->getTable() . '` SET `' . $this->pwColumn . '`="' . $backupPassword . '", `data`="' . $backupData . '" WHERE `' . $this->userColumn . "`='" . $this->getUsername() . "'";
                     mysqli_query($l, 'BEGIN');
                     $r = mysqli_query($l, $query2);
                     $finish_query = $r ? 'COMMIT' : 'ROLLBACK';
                     $revert['action'] = $finish_query;
                     if ($finish_query == 'ROLLBACK') {
                         $revert['error'] = mysqli_error($l);
                     }
                     $r2 = mysqli_query($l, $finish_query);
                     $revert['status'] = $r && $r2;
                     $revert['debug'] = array('new_data' => $data, 'new_password' => $pwStore, 'original_query' => $query, 'restored_to' => $backupPassword, 'old_data' => $backupData);
                     $callback['revert_status'] = $revert;
                     $callback['original_status'] = $callback['status'];
                     $callback['status'] = false;
                 }
             }
             return $callback;
         }
     } catch (Exception $e) {
         # Bad user
         throw new Exception('Invalid user credentials - ' . $e->getMessage());
     }
 }