/** * Generate a random string of characters. * * @param int $length The length of the string to generate. * @param string $characters The allowed characters in the string. See {@link betterRandomString()} for character options. * @return string Returns a random string of characters. */ function randomString($length, $characters = 'A0') { return betterRandomString($length, $characters); }
/** * Send forgot password email. * * @param string $Email * @return bool */ public function passwordRequest($Email) { if (!$Email) { return false; } $Users = $this->getWhere(['Email' => $Email])->resultObject(); if (count($Users) == 0) { // Check for the username. $Users = $this->getWhere(['Name' => $Email])->resultObject(); } $this->EventArguments['Users'] =& $Users; $this->EventArguments['Email'] = $Email; $this->fireEvent('BeforePasswordRequest'); if (count($Users) == 0) { $this->Validation->addValidationResult('Name', "Couldn't find an account associated with that email/username."); return false; } $NoEmail = true; foreach ($Users as $User) { if (!$User->Email) { continue; } $Email = new Gdn_Email(); // Instantiate in loop to clear previous settings $PasswordResetKey = betterRandomString(20, 'Aa0'); $PasswordResetExpires = strtotime('+1 hour'); $this->saveAttribute($User->UserID, 'PasswordResetKey', $PasswordResetKey); $this->saveAttribute($User->UserID, 'PasswordResetExpires', $PasswordResetExpires); $AppTitle = c('Garden.Title'); $Email->subject('[' . $AppTitle . '] ' . t('Reset Your Password')); $Email->to($User->Email); $emailTemplate = $Email->getEmailTemplate()->setTitle(t('Reset Your Password'))->setMessage(sprintf(t('We\'ve received a request to change your password.'), $AppTitle))->setButton(externalUrl('/entry/passwordreset/' . $User->UserID . '/' . $PasswordResetKey), t('Change My Password')); $Email->setEmailTemplate($emailTemplate); try { $Email->send(); } catch (Exception $e) { if (debug()) { throw $e; } } $NoEmail = false; } if ($NoEmail) { $this->Validation->addValidationResult('Name', 'There is no email address associated with that account.'); return false; } return true; }
/** * Allows the configuration of basic setup information in Garden. This * should not be functional after the application has been set up. * * @since 2.0.0 * @access public * @param string $RedirectUrl Where to send user afterward. */ private function configure($RedirectUrl = '') { // Create a model to save configuration settings $Validation = new Gdn_Validation(); $ConfigurationModel = new Gdn_ConfigurationModel($Validation); $ConfigurationModel->setField(array('Garden.Locale', 'Garden.Title', 'Garden.WebRoot', 'Garden.Cookie.Salt', 'Garden.Cookie.Domain', 'Database.Name', 'Database.Host', 'Database.User', 'Database.Password', 'Garden.Registration.ConfirmEmail', 'Garden.Email.SupportName')); // Set the models on the forms. $this->Form->setModel($ConfigurationModel); // If seeing the form for the first time... if (!$this->Form->isPostback()) { // Force the webroot using our best guesstimates $ConfigurationModel->Data['Database.Host'] = 'localhost'; $this->Form->setData($ConfigurationModel->Data); } else { // Define some validation rules for the fields being saved $ConfigurationModel->Validation->applyRule('Database.Name', 'Required', 'You must specify the name of the database in which you want to set up Vanilla.'); // Let's make some user-friendly custom errors for database problems $DatabaseHost = $this->Form->getFormValue('Database.Host', '~~Invalid~~'); $DatabaseName = $this->Form->getFormValue('Database.Name', '~~Invalid~~'); $DatabaseUser = $this->Form->getFormValue('Database.User', '~~Invalid~~'); $DatabasePassword = $this->Form->getFormValue('Database.Password', '~~Invalid~~'); $ConnectionString = GetConnectionString($DatabaseName, $DatabaseHost); try { $Connection = new PDO($ConnectionString, $DatabaseUser, $DatabasePassword); } catch (PDOException $Exception) { switch ($Exception->getCode()) { case 1044: $this->Form->addError(t('The database user you specified does not have permission to access the database. Have you created the database yet? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 1045: $this->Form->addError(t('Failed to connect to the database with the username and password you entered. Did you mistype them? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 1049: $this->Form->addError(t('It appears as though the database you specified does not exist yet. Have you created it yet? Did you mistype the name? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 2005: $this->Form->addError(t("Are you sure you've entered the correct database host name? Maybe you mistyped it? The database reported: <code>%s</code>"), strip_tags($Exception->getMessage())); break; default: $this->Form->addError(sprintf(t('ValidateConnection'), strip_tags($Exception->getMessage()))); break; } } $ConfigurationModel->Validation->applyRule('Garden.Title', 'Required'); $ConfigurationFormValues = $this->Form->formValues(); if ($ConfigurationModel->validate($ConfigurationFormValues) !== true || $this->Form->errorCount() > 0) { // Apply the validation results to the form(s) $this->Form->setValidationResults($ConfigurationModel->validationResults()); } else { $Host = array_shift(explode(':', Gdn::request()->requestHost())); $Domain = Gdn::request()->domain(); // Set up cookies now so that the user can be signed in. $ExistingSalt = c('Garden.Cookie.Salt', false); $ConfigurationFormValues['Garden.Cookie.Salt'] = $ExistingSalt ? $ExistingSalt : betterRandomString(16, 'Aa0'); $ConfigurationFormValues['Garden.Cookie.Domain'] = ''; // Don't set this to anything by default. # Tim - 2010-06-23 // Additional default setup values. $ConfigurationFormValues['Garden.Registration.ConfirmEmail'] = true; $ConfigurationFormValues['Garden.Email.SupportName'] = $ConfigurationFormValues['Garden.Title']; $ConfigurationModel->save($ConfigurationFormValues, true); // If changing locale, redefine locale sources: $NewLocale = 'en-CA'; // $this->Form->getFormValue('Garden.Locale', false); if ($NewLocale !== false && Gdn::config('Garden.Locale') != $NewLocale) { $Locale = Gdn::locale(); $Locale->set($NewLocale); } // Install db structure & basic data. $Database = Gdn::database(); $Database->init(); $Drop = false; $Explicit = false; try { include PATH_APPLICATIONS . DS . 'dashboard' . DS . 'settings' . DS . 'structure.php'; } catch (Exception $ex) { $this->Form->addError($ex); } if ($this->Form->errorCount() > 0) { return false; } // Create the administrative user $UserModel = Gdn::userModel(); $UserModel->defineSchema(); $UsernameError = t('UsernameError', 'Username can only contain letters, numbers, underscores, and must be between 3 and 20 characters long.'); $UserModel->Validation->applyRule('Name', 'Username', $UsernameError); $UserModel->Validation->applyRule('Name', 'Required', t('You must specify an admin username.')); $UserModel->Validation->applyRule('Password', 'Required', t('You must specify an admin password.')); $UserModel->Validation->applyRule('Password', 'Match'); $UserModel->Validation->applyRule('Email', 'Email'); if (!($AdminUserID = $UserModel->SaveAdminUser($ConfigurationFormValues))) { $this->Form->setValidationResults($UserModel->validationResults()); } else { // The user has been created successfully, so sign in now. saveToConfig('Garden.Installed', true, array('Save' => false)); Gdn::session()->start($AdminUserID, true); saveToConfig('Garden.Installed', false, array('Save' => false)); } if ($this->Form->errorCount() > 0) { return false; } // Assign some extra settings to the configuration file if everything succeeded. $ApplicationInfo = array(); include CombinePaths(array(PATH_APPLICATIONS . DS . 'dashboard' . DS . 'settings' . DS . 'about.php')); // Detect Internet connection for CDNs $Disconnected = !(bool) @fsockopen('ajax.googleapis.com', 80); saveToConfig(array('Garden.Version' => val('Version', val('Dashboard', $ApplicationInfo, array()), 'Undefined'), 'Garden.Cdns.Disable' => $Disconnected, 'Garden.CanProcessImages' => function_exists('gd_info'), 'EnabledPlugins.GettingStarted' => 'GettingStarted', 'EnabledPlugins.HtmLawed' => 'HtmLawed')); } } return $this->Form->errorCount() == 0 ? true : false; }
/** * Set the TransientKey attribute on a user. * * @param $UserID * @param string $ExplicitKey * @return string */ public function setTransientKey($UserID, $ExplicitKey = '') { $Key = $ExplicitKey == '' ? betterRandomString(16, 'Aa0') : $ExplicitKey; $this->saveAttribute($UserID, 'TransientKey', $Key); return $Key; }
/** * Create a user. * * @since 2.0.0 * @access public */ public function add() { $this->permission('Garden.Users.Add'); // Page setup $this->addJsFile('user.js'); $this->title(t('Add User')); $this->setHighlightRoute('dashboard/user'); $RoleModel = new RoleModel(); $AllRoles = $RoleModel->getArray(); $RoleData = $RoleModel->GetAssignable(); // By default, people with access here can freely assign all roles $this->RoleData = $RoleData; $UserModel = new UserModel(); $this->User = false; // Set the model on the form. $this->Form->setModel($UserModel); try { // These are all the 'effective' roles for this add action. This list can // be trimmed down from the real list to allow subsets of roles to be edited. $this->EventArguments['RoleData'] =& $this->RoleData; $this->fireEvent("BeforeUserAdd"); if ($this->Form->authenticatedPostBack(true)) { // These are the new roles the creating user wishes to apply to the target // user, adjusted for his ability to affect those roles $RequestedRoles = $this->Form->getFormValue('RoleID'); if (!is_array($RequestedRoles)) { $RequestedRoles = array(); } $RequestedRoles = array_flip($RequestedRoles); $UserNewRoles = array_intersect_key($this->RoleData, $RequestedRoles); // Put the data back into the forum object as if the user had submitted // this themselves $this->Form->setFormValue('RoleID', array_keys($UserNewRoles)); $noPassword = (bool) $this->Form->getFormValue('NoPassword'); if ($noPassword) { $this->Form->setFormValue('Password', betterRandomString(15, 'Aa0')); $this->Form->setFormValue('HashMethod', 'Random'); } $NewUserID = $this->Form->save(array('SaveRoles' => true, 'NoConfirmEmail' => true)); if ($NewUserID !== false) { $this->setData('UserID', $NewUserID); if ($noPassword) { $password = T('No password'); } else { $password = $this->Form->getValue('Password', ''); } $UserModel->sendWelcomeEmail($NewUserID, $password, 'Add'); $this->informMessage(t('The user has been created successfully')); $this->RedirectUrl = url('dashboard/user'); } elseif ($noPassword) { $this->Form->setFormValue('Password', ''); $this->Form->setFormValue('HashMethod', ''); } $this->UserRoleData = $UserNewRoles; } else { // Set the default roles. $this->UserRoleData = RoleModel::getDefaultRoles(RoleModel::TYPE_MEMBER); } } catch (Exception $Ex) { $this->Form->addError($Ex); } $this->render(); }
/** * Used by $this->Stash() to create & manage sessions for users & guests. * * This is a stop-gap solution until full session management for users & * guests can be imlemented. */ private function _getStashSession($ValueToStash) { $CookieName = c('Garden.Cookie.Name', 'Vanilla'); $Name = $CookieName . '-sid'; // Grab the entire session record $SessionID = val($Name, $_COOKIE, ''); // If there is no session, and no value for saving, return; if ($SessionID == '' && $ValueToStash == '') { return false; } $Session = Gdn::SQL()->select()->from('Session')->where('SessionID', $SessionID)->get()->firstRow(); if (!$Session) { $SessionID = betterRandomString(32); $TransientKey = substr(md5(mt_rand()), 0, 11) . '!'; // Save the session information to the database. Gdn::SQL()->insert('Session', array('SessionID' => $SessionID, 'UserID' => Gdn::session()->UserID, 'TransientKey' => $TransientKey, 'DateInserted' => Gdn_Format::toDateTime(), 'DateUpdated' => Gdn_Format::toDateTime())); Trace("Inserting session stash {$SessionID}"); $Session = Gdn::SQL()->select()->from('Session')->where('SessionID', $SessionID)->get()->firstRow(); // Save a session cookie $Path = c('Garden.Cookie.Path', '/'); $Domain = c('Garden.Cookie.Domain', ''); $Expire = 0; // If the domain being set is completely incompatible with the current domain then make the domain work. $CurrentHost = Gdn::request()->host(); if (!stringEndsWith($CurrentHost, trim($Domain, '.'))) { $Domain = ''; } safeCookie($Name, $SessionID, $Expire, $Path, $Domain); $_COOKIE[$Name] = $SessionID; } $Session->Attributes = @unserialize($Session->Attributes); if (!$Session->Attributes) { $Session->Attributes = array(); } return $Session; }
/** * Get server list with mapping keys. */ public function shardMap() { static $servers = null; if (is_null($servers)) { $serverList = $this->servers(); $numShards = count($serverList); $servers = array(); if ($this->canAutoShard()) { // Use getServerByKey to determine server keys // Here we loop until we have found keys for all the servers $i = $numShards * 10; do { $i--; // limited iterations $shardKey = betterRandomString(6, 'a0'); $shardServer = $this->memcache->getServerByKey($shardKey); $shardServerName = $shardServer['host']; if ($shardServerName) { $servers[$shardServerName] = $shardKey; } } while ($i > 0 && count($servers) < $numShards); } if (!count($servers)) { // Use random server keys and hope for the best foreach ($serverList as $server) { $serverName = $server['host']; $servers[$serverName] = betterRandomString(6, 'a0'); } } } return $servers; }
/** * * * @throws Exception */ public function ping() { $start = microtime(true); $this->setData('pong', true); $this->MasterView = 'empty'; $this->CssClass = 'Home'; $valid = true; // Test the cache. if (Gdn::cache()->activeEnabled()) { $k = betterRandomString(20); Gdn::cache()->store($k, 1); Gdn::cache()->increment($k, 1); $v = Gdn::cache()->get($k); if ($v !== 2) { $valid = false; $this->setData('cache', false); } else { $this->setData('cache', true); } } else { $this->setData('cache', 'disabled'); } // Test the db. try { $users = Gdn::sql()->get('User', 'UserID', 'asc', 1); $this->setData('database', true); } catch (Exception $ex) { $this->setData('database', false); $valid = false; } $this->EventArguments['Valid'] =& $valid; $this->fireEvent('Ping'); if (!$valid) { $this->statusCode(500); } $time = microtime(true) - $start; $this->setData('time', Gdn_Format::timespan($time)); $this->setData('time_s', $time); $this->setData('valid', $valid); $this->title('Ping'); $this->render(); }
/** * Used by $this->stash() to create & manage sessions for users & guests. * * This is a stop-gap solution until full session management for users & * guests can be implemented. * * @param Gdn_SQLDriver $sql Local clone of the sql driver. * @param string $valueToStash The value of the stash to set. * * @return bool|Gdn_DataSet Current session. */ private function getStashSession($sql, $valueToStash) { $cookieName = c('Garden.Cookie.Name', 'Vanilla'); $name = $cookieName . '-sid'; // Grab the entire session record. $sessionID = val($name, $_COOKIE, ''); // If there is no session, and no value for saving, return. if ($sessionID == '' && $valueToStash == '') { return false; } $session = $sql->select()->from('Session')->where('SessionID', $sessionID)->get()->firstRow(); if (!$session) { $sessionID = betterRandomString(32); $transientKey = substr(md5(mt_rand()), 0, 11) . '!'; // Save the session information to the database. $sql->insert('Session', ['SessionID' => $sessionID, 'UserID' => Gdn::session()->UserID, 'TransientKey' => $transientKey, 'DateInserted' => Gdn_Format::toDateTime(), 'DateUpdated' => Gdn_Format::toDateTime()]); trace("Inserting session stash {$sessionID}"); $session = $sql->select()->from('Session')->where('SessionID', $sessionID)->get()->firstRow(); // Save a session cookie. $path = c('Garden.Cookie.Path', '/'); $domain = c('Garden.Cookie.Domain', ''); $expire = 0; // If the domain being set is completely incompatible with the // current domain then make the domain work. $currentHost = Gdn::request()->host(); if (!stringEndsWith($currentHost, trim($domain, '.'))) { $domain = ''; } safeCookie($name, $sessionID, $expire, $path, $domain); $_COOKIE[$name] = $sessionID; } $session->Attributes = dbdecode($session->Attributes); if (!$session->Attributes) { $session->Attributes = []; } return $session; }