public function getResetPasswordToken()
 {
     global $db;
     $db->execute("DELETE FROM password_resets WHERE expires < now()");
     $token = fCryptography::randomString(15);
     $db->execute("INSERT INTO password_resets (key, user_id, expires)\n                                    VALUES (%s, %s, now() + INTERVAL '1 day')", $token, $this->getId());
     return $token;
 }
Esempio n. 2
0
 /**
  * Hash a string for storage. Automatically generates a salt.
  * 
  * @param string $password 		The string to hash
  * 
  * @return string 				A crypt()-compatible string
  */
 public static function hash($password, $work_factor = 0)
 {
     if (version_compare(PHP_VERSION, '5.3') < 0) {
         throw new Exception('Bcrypt requires PHP 5.3 or above');
     }
     if ($work_factor < 4 || $work_factor > 31) {
         $work_factor = self::$work_factor;
     }
     // $salt =
     // 	'$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' .
     // 	substr(strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'), 0, 22);
     $salt = '$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' . fCryptography::randomString(22);
     return crypt($password, $salt);
 }
Esempio n. 3
0
 /**
  * Returns a request token that should be placed in each HTML form to prevent [http://en.wikipedia.org/wiki/Cross-site_request_forgery cross-site request forgery]
  * 
  * This method will return a random 15 character string that should be
  * placed in a hidden `input` element on every HTML form. When the form
  * contents are being processed, the token should be retrieved and passed
  * into ::validateCSRFToken().
  * 
  * The value returned by this method is stored in the session and then
  * checked by the validate method, which helps prevent cross site request
  * forgeries and (naive) automated form submissions.
  * 
  * Tokens generated by this method are single use, so a user must request
  * the page that generates the token at least once per submission.
  * 
  * @param  string $url  The URL to generate a token for, default to the current page
  * @return string  The token to be submitted with the form
  */
 public static function generateCSRFToken($url = NULL)
 {
     if ($url === NULL) {
         $url = fURL::get();
     }
     $token = fCryptography::randomString(16);
     fSession::add(__CLASS__ . '::' . $url . '::csrf_tokens', $token);
     return $token;
 }
    fURL::redirect('/members');
}
if (isset($_POST['submit'])) {
    try {
        fRequest::validateCSRFToken($_POST['token']);
        $validator = new fValidation();
        $validator->addRequiredFields('password', 'email');
        $validator->addEmailFields('email');
        $validator->validate();
        $users = fRecordSet::build('User', array('email=' => strtolower($_POST['email'])));
        if ($users->count() == 0) {
            throw new fValidationException('Invalid username or password.');
        }
        $rec = $users->getRecords();
        $user = $rec[0];
        if (!fCryptography::checkPasswordHash($_POST['password'], $user->getPassword())) {
            throw new fValidationException('Invalid username or password.');
        }
        fSession::set('user', $user->getId());
        if (fRequest::get('persistent_login', 'boolean')) {
            fSession::enablePersistence();
        }
        if (isset($_POST['forward'])) {
            fURL::redirect('http://' . $_SERVER['SERVER_NAME'] . $_POST['forward']);
        } else {
            fURL::redirect('/members');
        }
        exit;
    } catch (fValidationException $e) {
        echo "<p>" . $e->printMessage() . "</p>";
    } catch (fSQLException $e) {
Esempio n. 5
0
        fMessaging::create('error', User::makeUrl('list'), 'The user requested, ' . fHTML::encode($user_id) . ', could not be found');
        fURL::redirect(User::makeUrl('list'));
    } catch (fExpectedException $e) {
        fMessaging::create('error', fURL::get(), $e->getMessage());
    }
    include VIEW_PATH . '/add_edit_user.php';
    // --------------------------------- //
} elseif ('add' == $action) {
    $user = new User();
    if (fRequest::isPost()) {
        try {
            $user->populate();
            if ($GLOBALS['ALLOW_HTTP_AUTH']) {
                $password = '******';
            } else {
                $password = fCryptography::hashPassword($user->getPassword());
            }
            $user->setPassword($password);
            fRequest::validateCSRFToken(fRequest::get('token'));
            $user->store();
            if ($user->getUserId() == 1) {
                $user->setRole('admin');
                $user->store();
            }
            fMessaging::create('affected', User::makeURL('login'), $user->getUsername());
            fMessaging::create('success', User::makeURL('login'), 'The user ' . $user->getUsername() . ' was successfully created');
            fURL::redirect(User::makeURL('login'));
        } catch (fExpectedException $e) {
            fMessaging::create('error', fURL::get(), $e->getMessage());
        }
    }
}
?>
<h2>Edit Your Membership Account</h2>
<?php 
if (isset($_POST['submit'])) {
    try {
        fRequest::validateCSRFToken($_POST['token']);
        $validator = new fValidation();
        $validator->addRequiredFields('fullname', 'email', 'address', 'length');
        $validator->addEmailFields('email');
        $validator->validate();
        if ($_POST['newpassword'] != '') {
            if ($_POST['newpassword'] != $_POST['newpasswordconfirm']) {
                throw new fValidationException('Passwords do not match');
            }
            $user->setPassword(fCryptography::hashPassword($_POST['newpassword']));
        }
        $user->setEmail(strtolower(trim($_POST['email'])));
        $user->setFullName(trim($_POST['fullname']));
        $user->setAddress(trim($_POST['address']));
        $user->setSubscriptionPeriod($_POST['length']);
        $user->setEmergencyName(trim($_POST['emergency_name']));
        $user->setEmergencyPhone(trim($_POST['emergency_phone']));
        $user->store();
        fURL::redirect('?saved');
        exit;
    } catch (fValidationException $e) {
        echo "<p>" . $e->printMessage() . "</p>";
    } catch (fSQLException $e) {
        echo "<p>An unexpected error occurred, please try again later</p>";
        trigger_error($e);
Esempio n. 7
0
 /**
  * Returns a request token that should be placed in each HTML form to prevent [http://en.wikipedia.org/wiki/Cross-site_request_forgery cross-site request forgery]
  * 
  * This method will return a random 15 character string that should be
  * placed in a hidden `input` element on every HTML form. When the form
  * contents are being processed, the token should be retrieved and passed
  * into ::validateCSRFToken().
  * 
  * The value returned by this method is stored in the session and then
  * checked by the validate method, which helps prevent cross site request
  * forgeries and (naive) automated form submissions.
  * 
  * Tokens generated by this method are single use, so a user must request
  * the page that generates the token at least once per submission.
  * 
  * @param  string $url  The URL to generate a token for, default to the current page
  * @return string  The token to be submitted with the form
  */
 public static function generateCSRFToken($url = NULL)
 {
     if ($url === NULL) {
         $url = fURL::get();
     }
     $token = fCryptography::randomString(16);
     $tokens = fSession::get($url . '::csrf_tokens', array(), __CLASS__ . '::');
     $tokens[] = $token;
     fSession::set($url . '::csrf_tokens', $tokens, __CLASS__ . '::');
     return $token;
 }
Esempio n. 8
0
 public function testRandomString()
 {
     $random_string = fCryptography::randomString(8, 'alpha');
     $this->assertEquals(8, strlen($random_string));
     $this->assertEquals(TRUE, ctype_alpha($random_string));
 }
 /**
  * Generates a new random value for the column
  *
  * @internal
  *
  * @param  fActiveRecord $object            The fActiveRecord instance
  * @param  array         &$values           The current values
  * @param  array         &$old_values       The old values
  * @param  array         &$related_records  Any records related to this record
  * @param  array         &$cache            The cache array for the record
  * @param  string        $method_name       The method that was called
  * @param  array         $parameters        The parameters passed to the method
  * @return string  The newly generated random value
  */
 public static function generate($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters)
 {
     list($action, $subject) = fORM::parseMethod($method_name);
     $column = fGrammar::underscorize($subject);
     $class = get_class($object);
     $table = fORM::tablize($class);
     $schema = fORMSchema::retrieve($class);
     $db = fORMDatabase::retrieve($class, 'read');
     $settings = self::$random_columns[$class][$column];
     // Check to see if this is a unique column
     $unique_keys = $schema->getKeys($table, 'unique');
     $is_unique_column = FALSE;
     foreach ($unique_keys as $unique_key) {
         if ($unique_key == array($column)) {
             $is_unique_column = TRUE;
             $sql = "SELECT %r FROM %r WHERE %r = %s";
             do {
                 $value = fCryptography::randomString($settings['length'], $settings['type']);
             } while ($db->query($sql, $column, $table, $column, $value)->countReturnedRows());
         }
     }
     // If is is not a unique column, just generate a value
     if (!$is_unique_column) {
         $value = fCryptography::randomString($settings['length'], $settings['type']);
     }
     fActiveRecord::assign($values, $old_values, $column, $value);
     return $value;
 }
Esempio n. 10
0
include 'inc/init.php';
$action = fRequest::get('action');
// --------------------------------- //
if ('log_out' == $action) {
    fAuthorization::destroyUserInfo();
    fSession::destroy();
    fMessaging::create('success', User::makeUrl('login'), 'You were successfully logged out');
    fURL::redirect(User::makeUrl('login'));
    // --------------------------------- //
} else {
    if (!fAuthorization::checkLoggedIn()) {
        if (fRequest::isPost()) {
            try {
                $user = new User(array('username' => fRequest::get('username')));
                $valid_pass = fCryptography::checkPasswordHash(fRequest::get('password'), $user->getPassword());
                if (!$valid_pass) {
                    throw new fValidationException('The login or password entered is invalid');
                }
                fAuthorization::setUserToken($user->getEmail());
                fAuthorization::setUserAuthLevel($user->getRole());
                fSession::set('user_id', $user->getUserId());
                fSession::set('user_name', $user->getUsername());
                fURL::redirect(fAuthorization::getRequestedURL(TRUE, 'index.php'));
            } catch (fExpectedException $e) {
                fMessaging::create('error', fURL::get(), $e->getMessage());
            }
        }
        include VIEW_PATH . '/log_in.php';
    } else {
        fURL::redirect('index.php');
Esempio n. 11
0
 /**
  * Initiates the connection to the server
  * 
  * @return void
  */
 private function connect()
 {
     if ($this->connection) {
         return;
     }
     $fqdn = fEmail::getFQDN();
     fCore::startErrorCapture(E_WARNING);
     $host = $this->secure ? 'tls://' . $this->host : $this->host;
     $this->connection = fsockopen($host, $this->port, $error_int, $error_string, $this->timeout);
     foreach (fCore::stopErrorCapture('#ssl#i') as $error) {
         throw new fConnectivityException('There was an error connecting to the server. A secure connection was requested, but was not available. Try a non-secure connection instead.');
     }
     if (!$this->connection) {
         throw new fConnectivityException('There was an error connecting to the server');
     }
     stream_set_timeout($this->connection, $this->timeout);
     $response = $this->read('#^220 #');
     if (!$this->find($response, '#^220[ -]#')) {
         throw new fConnectivityException('Unknown SMTP welcome message, %1$s, from server %2$s on port %3$s', join("\r\n", $response), $this->host, $this->port);
     }
     // Try sending the ESMTP EHLO command, but fall back to normal SMTP HELO
     $response = $this->write('EHLO ' . $fqdn, '#^250 #m');
     if ($this->find($response, '#^500#')) {
         $response = $this->write('HELO ' . $fqdn, 1);
     }
     // If STARTTLS is available, use it
     if (!$this->secure && extension_loaded('openssl') && $this->find($response, '#^250[ -]STARTTLS#')) {
         $response = $this->write('STARTTLS', '#^220 #');
         $affirmative = $this->find($response, '#^220[ -]#');
         if ($affirmative) {
             do {
                 if (isset($res)) {
                     sleep(0.1);
                 }
                 $res = stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT);
             } while ($res === 0);
         }
         if (!$affirmative || $res === FALSE) {
             throw new fConnectivityException('Error establishing secure connection');
         }
         $response = $this->write('EHLO ' . $fqdn, '#^250 #m');
     }
     $this->max_size = 0;
     if ($match = $this->find($response, '#^250[ -]SIZE\\s+(\\d+)$#')) {
         $this->max_size = $match[0][1];
     }
     $this->pipelining = (bool) $this->find($response, '#^250[ -]PIPELINING$#');
     $auth_methods = array();
     if ($match = $this->find($response, '#^250[ -]AUTH[ =](.*)$#')) {
         $auth_methods = array_map('strtoupper', explode(' ', $match[0][1]));
     }
     if (!$auth_methods || !$this->username) {
         return;
     }
     if (in_array('DIGEST-MD5', $auth_methods)) {
         $response = $this->write('AUTH DIGEST-MD5', 1);
         $this->handleErrors($response);
         $match = $this->find($response, '#^334 (.*)$#');
         $challenge = base64_decode($match[0][1]);
         preg_match_all('#(?<=,|^)(\\w+)=("[^"]+"|[^,]+)(?=,|$)#', $challenge, $matches, PREG_SET_ORDER);
         $request_params = array();
         foreach ($matches as $_match) {
             $request_params[$_match[1]] = $_match[2][0] == '"' ? substr($_match[2], 1, -1) : $_match[2];
         }
         $missing_qop_auth = !isset($request_params['qop']) || !in_array('auth', explode(',', $request_params['qop']));
         $missing_nonce = empty($request_params['nonce']);
         if ($missing_qop_auth || $missing_nonce) {
             throw new fUnexpectedException('The SMTP server %1$s on port %2$s claims to support DIGEST-MD5, but does not seem to provide auth functionality', $this->host, $this->port);
         }
         if (!isset($request_params['realm'])) {
             $request_params['realm'] = '';
         }
         // Algorithm from http://www.ietf.org/rfc/rfc2831.txt
         $realm = $request_params['realm'];
         $nonce = $request_params['nonce'];
         $cnonce = fCryptography::randomString('32', 'hexadecimal');
         $nc = '00000001';
         $digest_uri = 'smtp/' . $this->host;
         $a1 = md5($this->username . ':' . $realm . ':' . $this->password, TRUE) . ':' . $nonce . ':' . $cnonce;
         $a2 = 'AUTHENTICATE:' . $digest_uri;
         $response = md5(md5($a1) . ':' . $nonce . ':' . $nc . ':' . $cnonce . ':auth:' . md5($a2));
         $response_params = array('charset=utf-8', 'username="******"', 'realm="' . $realm . '"', 'nonce="' . $nonce . '"', 'nc=' . $nc, 'cnonce="' . $cnonce . '"', 'digest-uri="' . $digest_uri . '"', 'response=' . $response, 'qop=auth');
         $response = $this->write(base64_encode(join(',', $response_params)), 2);
     } elseif (in_array('CRAM-MD5', $auth_methods)) {
         $response = $this->write('AUTH CRAM-MD5', 1);
         $match = $this->find($response, '#^334 (.*)$#');
         $challenge = base64_decode($match[0][1]);
         $response = $this->write(base64_encode($this->username . ' ' . fCryptography::hashHMAC('md5', $challenge, $this->password)), 1);
     } elseif (in_array('LOGIN', $auth_methods)) {
         $response = $this->write('AUTH LOGIN', 1);
         $this->write(base64_encode($this->username), 1);
         $response = $this->write(base64_encode($this->password), 1);
     } elseif (in_array('PLAIN', $auth_methods)) {
         $response = $this->write('AUTH PLAIN ' . base64_encode($this->username . "" . $this->username . "" . $this->password), 1);
     }
     if ($this->find($response, '#^535[ -]#')) {
         throw new fValidationException('The username and password provided were not accepted for the SMTP server %1$s on port %2$s', $this->host, $this->port);
     }
     if (!array_filter($response)) {
         throw new fConnectivityException('No response was received for the authorization request');
     }
 }
Esempio n. 12
0
 /**
  * Generate a new random key for this user.
  * 
  * @return string 		128-character generated key
  */
 public function generateKey()
 {
     $sfUsers = sfCore::getClass('sfUsers');
     do {
         $key = fCryptography::randomString(64);
     } while ($sfUsers::keyExists($key));
     sfCore::$db->query("UPDATE `swoosh_users` SET `key`=%s WHERE `id`=%i", $key, $this->id);
     $this->key = $key;
     return $key;
 }
Esempio n. 13
0
 $user->populate();
 $has_error = false;
 if ($GLOBALS['ALLOW_HTTP_AUTH']) {
     $password = '******';
 } else {
     $new_password = fRequest::get('new_password');
     $confirm_password = fRequest::get('confirm_password');
     if ($new_password != $confirm_password) {
         fMessaging::create('error', fURL::get(), "The two passwords don't match, the user was not created.");
         $has_error = true;
     } else {
         if ($new_password == "") {
             fMessaging::create('error', fURL::get(), "An empty password is forbidden, the user was not created.");
             $has_error = true;
         } else {
             $password = fCryptography::hashPassword($new_password);
         }
     }
 }
 fRequest::validateCSRFToken(fRequest::get('token'));
 if (!$has_error) {
     $user->setPassword($password);
     $user->store();
     if ($user->getUserId() == 1) {
         $user->setRole('admin');
         $user->store();
     }
     fMessaging::create('affected', User::makeURL('login'), $user->getUsername());
     fMessaging::create('success', User::makeURL('login'), 'The user ' . $user->getUsername() . ' was successfully created');
     fURL::redirect(User::makeURL('login'));
 }
Esempio n. 14
0
 /**
  * Generates a new random value for the 
  * 
  * @internal
  * 
  * @param  fActiveRecord $object            The fActiveRecord instance
  * @param  array         &$values           The current values
  * @param  array         &$old_values       The old values
  * @param  array         &$related_records  Any records related to this record
  * @param  array         &$cache            The cache array for the record
  * @param  string        $method_name       The method that was called
  * @param  array         $parameters        The parameters passed to the method
  * @return string  The encoded number
  */
 public static function generate($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters)
 {
     list($action, $column) = fORM::parseMethod($method_name);
     $class = get_class($object);
     $table = fORM::tablize($class);
     $settings = self::$random_columns[$class][$column];
     // Check to see if this is a unique column
     $unique_keys = fORMSchema::retrieve()->getKeys($table, 'unique');
     $is_unique_column = FALSE;
     foreach ($unique_keys as $unique_key) {
         if ($unique_key == array($column)) {
             $is_unique_column = TRUE;
             do {
                 $value = fCryptography::randomString($settings['length'], $settings['type']);
                 // See if this is unique
                 $sql = "SELECT " . $column . " FROM " . $table . " WHERE " . $column . " = " . fORMDatabase::retrieve()->escape('string', $value);
             } while (fORMDatabase::retrieve()->query($sql)->countReturnedRows());
         }
     }
     // If is is not a unique column, just generate a value
     if (!$is_unique_column) {
         $value = fCryptography::randomString($settings['length'], $settings['type']);
     }
     fActiveRecord::assign($values, $old_values, $column, $value);
 }
Esempio n. 15
0
 /**
  * Initializes fEmail for creating message ids
  * 
  * @return fEmail
  */
 public function __construct()
 {
     $this->message_id = '<' . fCryptography::randomString(10, 'hexadecimal') . '.' . time() . '@' . self::getFQDN() . '>';
 }
Esempio n. 16
0
 /**
  * Called to generate and store a random anti-CSRF token for a form.
  *
  * Multiple forms can be catered for within a session if needed.
  **/
 public static function generate($form_name)
 {
     $tok = sha1(fCryptography::randomString(32));
     wire()->session->set($form_name . '.CSRFToken', $tok);
     return $tok;
 }
Esempio n. 17
0
 /**
  * Sends the email
  * 
  * The return value is the message id, which should be included as the
  * `Message-ID` header of the email. While almost all SMTP servers will not
  * modify this value, testing has indicated at least one (smtp.live.com
  * for Windows Live Mail) does.
  * 
  * @throws fValidationException  When ::validate() throws an exception
  * 
  * @param  fSMTP $connection  The SMTP connection to send the message over
  * @return string  The message id for the message - see method description for details
  */
 public function send($connection = NULL)
 {
     $this->validate();
     // The mail() function on Windows doesn't support names in headers so
     // we must strip them down to just the email address
     if ($connection === NULL && fCore::checkOS('windows')) {
         $vars = array('bcc_emails', 'bounce_to_email', 'cc_emails', 'from_email', 'reply_to_email', 'sender_email', 'to_emails');
         foreach ($vars as $var) {
             if (!is_array($this->{$var})) {
                 if (preg_match(self::NAME_EMAIL_REGEX, $this->{$var}, $match)) {
                     $this->{$var} = $match[2];
                 }
             } else {
                 $new_emails = array();
                 foreach ($this->{$var} as $email) {
                     if (preg_match(self::NAME_EMAIL_REGEX, $email, $match)) {
                         $email = $match[2];
                     }
                     $new_emails[] = $email;
                 }
                 $this->{$var} = $new_emails;
             }
         }
     }
     $to = trim($this->buildMultiAddressHeader("", $this->to_emails));
     $message_id = '<' . fCryptography::randomString(32, 'hexadecimal') . '@' . self::$local_hostname . '>';
     $top_level_boundary = $this->createBoundary();
     $headers = $this->createHeaders($top_level_boundary, $message_id);
     $subject = str_replace(array("\r", "\n"), '', $this->subject);
     $subject = $this->makeEncodedWord($subject);
     $body = $this->createBody($top_level_boundary);
     if ($this->smime_encrypt || $this->smime_sign) {
         list($headers, $body) = $this->createSMIMEBody($to, $subject, $headers, $body);
     }
     // Remove extra line breaks
     $headers = trim($headers);
     $body = trim($body);
     if ($connection) {
         $to_emails = $this->extractEmails($this->to_emails);
         $to_emails = array_merge($to_emails, $this->extractEmails($this->cc_emails));
         $to_emails = array_merge($to_emails, $this->extractEmails($this->bcc_emails));
         $from = $this->bounce_to_email ? $this->bounce_to_email : current($this->extractEmails(array($this->from_email)));
         $connection->send($from, $to_emails, "To: " . $to . "\r\nSubject: " . $subject . "\r\n" . $headers, $body);
         return $message_id;
     }
     // Sendmail when not in safe mode will allow you to set the envelope from address via the -f parameter
     $parameters = NULL;
     if (!fCore::checkOS('windows') && $this->bounce_to_email) {
         preg_match(self::EMAIL_REGEX, $this->bounce_to_email, $matches);
         $parameters = '-f ' . $matches[0];
         // Windows takes the Return-Path email from the sendmail_from ini setting
     } elseif (fCore::checkOS('windows') && $this->bounce_to_email) {
         $old_sendmail_from = ini_get('sendmail_from');
         preg_match(self::EMAIL_REGEX, $this->bounce_to_email, $matches);
         ini_set('sendmail_from', $matches[0]);
     }
     // This is a gross qmail fix that is a last resort
     if (self::$popen_sendmail || self::$convert_crlf) {
         $to = str_replace("\r\n", "\n", $to);
         $subject = str_replace("\r\n", "\n", $subject);
         $body = str_replace("\r\n", "\n", $body);
         $headers = str_replace("\r\n", "\n", $headers);
     }
     // If the user is using qmail and wants to try to fix the \r\r\n line break issue
     if (self::$popen_sendmail) {
         $sendmail_command = ini_get('sendmail_path');
         if ($parameters) {
             $sendmail_command .= ' ' . $parameters;
         }
         $sendmail_process = popen($sendmail_command, 'w');
         fprintf($sendmail_process, "To: %s\n", $to);
         fprintf($sendmail_process, "Subject: %s\n", $subject);
         if ($headers) {
             fprintf($sendmail_process, "%s\n", $headers);
         }
         fprintf($sendmail_process, "\n%s\n", $body);
         $error = pclose($sendmail_process);
         // This is the normal way to send mail
     } else {
         if ($parameters) {
             $error = !mail($to, $subject, $body, $headers, $parameters);
         } else {
             $error = !mail($to, $subject, $body, $headers);
         }
     }
     if (fCore::checkOS('windows') && $this->bounce_to_email) {
         ini_set('sendmail_from', $old_sendmail_from);
     }
     if ($error) {
         throw new fConnectivityException('An error occured while trying to send the email entitled %s', $this->subject);
     }
     return $message_id;
 }