/**
  * Attempts to log an Author in given a username and password.
  * If the password is not hashed, it will be hashed using the sha1
  * algorithm. The username and password will be sanitized before
  * being used to query the Database. If an Author is found, they
  * will be logged in and the sanitized username and password (also hashed)
  * will be saved as values in the `$Cookie`.
  *
  * @see toolkit.General#hash()
  * @param string $username
  *  The Author's username. This will be sanitized before use.
  * @param string $password
  *  The Author's password. This will be sanitized and then hashed before use
  * @param boolean $isHash
  *  If the password provided is already hashed, setting this parameter to
  *  true will stop it becoming rehashed. By default it is false.
  * @return boolean
  *  True if the Author was logged in, false otherwise
  */
 public function login($username, $password, $isHash = false)
 {
     $username = self::Database()->cleanValue($username);
     $password = self::Database()->cleanValue($password);
     if (strlen(trim($username)) > 0 && strlen(trim($password)) > 0) {
         $author = AuthorManager::fetch('id', 'ASC', 1, null, sprintf("\n\t\t\t\t\t\t`username` = '%s'\n\t\t\t\t\t", $username));
         if (!empty($author) && Cryptography::compare($password, current($author)->get('password'), $isHash)) {
             $this->Author = current($author);
             // Only migrate hashes if there is no update available as the update might change the tbl_authors table.
             if (!Administration::instance()->isUpgradeAvailable() && Cryptography::requiresMigration($this->Author->get('password'))) {
                 $this->Author->set('password', Cryptography::hash($password));
                 self::Database()->update(array('password' => $this->Author->get('password')), 'tbl_authors', " `id` = '" . $this->Author->get('id') . "'");
             }
             $this->Cookie->set('username', $username);
             $this->Cookie->set('pass', $this->Author->get('password'));
             self::Database()->update(array('last_seen' => DateTimeObj::get('Y-m-d H:i:s')), 'tbl_authors', sprintf(" `id` = %d", $this->Author->get('id')));
             return true;
         }
     }
     return false;
 }
 /**
  * Attempts to log an Author in given a username and password.
  * If the password is not hashed, it will be hashed using the sha1
  * algorithm. The username and password will be sanitized before
  * being used to query the Database. If an Author is found, they
  * will be logged in and the sanitized username and password (also hashed)
  * will be saved as values in the `$Cookie`.
  *
  * @see toolkit.Cryptography#hash()
  * @throws DatabaseException
  * @param string $username
  *  The Author's username. This will be sanitized before use.
  * @param string $password
  *  The Author's password. This will be sanitized and then hashed before use
  * @param boolean $isHash
  *  If the password provided is already hashed, setting this parameter to
  *  true will stop it becoming rehashed. By default it is false.
  * @return boolean
  *  True if the Author was logged in, false otherwise
  */
 public static function login($username, $password, $isHash = false)
 {
     $username = trim(self::Database()->cleanValue($username));
     $password = trim(self::Database()->cleanValue($password));
     if (strlen($username) > 0 && strlen($password) > 0) {
         $author = AuthorManager::fetch('id', 'ASC', 1, null, sprintf("`username` = '%s'", $username));
         if (!empty($author) && Cryptography::compare($password, current($author)->get('password'), $isHash)) {
             self::$Author = current($author);
             // Only migrate hashes if there is no update available as the update might change the tbl_authors table.
             if (self::isUpgradeAvailable() === false && Cryptography::requiresMigration(self::$Author->get('password'))) {
                 self::$Author->set('password', Cryptography::hash($password));
                 self::Database()->update(array('password' => self::$Author->get('password')), 'tbl_authors', sprintf(" `id` = %d", self::$Author->get('id')));
             }
             self::$Cookie->set('username', $username);
             self::$Cookie->set('pass', self::$Author->get('password'));
             self::Database()->update(array('last_seen' => DateTimeObj::get('Y-m-d H:i:s')), 'tbl_authors', sprintf(" `id` = %d", self::$Author->get('id')));
             // Only set custom author language in the backend
             if (class_exists('Administration', false)) {
                 Lang::set(self::$Author->get('language'));
             }
             return true;
         }
     }
     return false;
 }
 private static function __install()
 {
     $fields = $_POST['fields'];
     $start = time();
     Symphony::Log()->writeToLog(PHP_EOL . '============================================', true);
     Symphony::Log()->writeToLog('INSTALLATION PROCESS STARTED (' . DateTimeObj::get('c') . ')', true);
     Symphony::Log()->writeToLog('============================================', true);
     // MySQL: Establishing connection
     Symphony::Log()->pushToLog('MYSQL: Establishing Connection', E_NOTICE, true, true);
     try {
         Symphony::Database()->connect($fields['database']['host'], $fields['database']['user'], $fields['database']['password'], $fields['database']['port'], $fields['database']['db']);
     } catch (DatabaseException $e) {
         self::__abort('There was a problem while trying to establish a connection to the MySQL server. Please check your settings.', $start);
     }
     // MySQL: Setting prefix & character encoding
     Symphony::Database()->setPrefix($fields['database']['tbl_prefix']);
     Symphony::Database()->setCharacterEncoding();
     Symphony::Database()->setCharacterSet();
     // MySQL: Importing schema
     Symphony::Log()->pushToLog('MYSQL: Importing Table Schema', E_NOTICE, true, true);
     try {
         Symphony::Database()->import(file_get_contents(INSTALL . '/includes/install.sql'), true);
     } catch (DatabaseException $e) {
         self::__abort('There was an error while trying to import data to the database. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(), $start);
     }
     // MySQL: Creating default author
     Symphony::Log()->pushToLog('MYSQL: Creating Default Author', E_NOTICE, true, true);
     try {
         Symphony::Database()->insert(array('id' => 1, 'username' => Symphony::Database()->cleanValue($fields['user']['username']), 'password' => Cryptography::hash(Symphony::Database()->cleanValue($fields['user']['password'])), 'first_name' => Symphony::Database()->cleanValue($fields['user']['firstname']), 'last_name' => Symphony::Database()->cleanValue($fields['user']['lastname']), 'email' => Symphony::Database()->cleanValue($fields['user']['email']), 'last_seen' => NULL, 'user_type' => 'developer', 'primary' => 'yes', 'default_area' => NULL, 'auth_token_active' => 'no'), 'tbl_authors');
     } catch (DatabaseException $e) {
         self::__abort('There was an error while trying create the default author. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(), $start);
     }
     // Configuration: Populating array
     $conf = Symphony::Configuration()->get();
     foreach ($conf as $group => $settings) {
         foreach ($settings as $key => $value) {
             if (isset($fields[$group]) && isset($fields[$group][$key])) {
                 $conf[$group][$key] = $fields[$group][$key];
             }
         }
     }
     // Create manifest folder structure
     Symphony::Log()->pushToLog('WRITING: Creating ‘manifest’ folder (/manifest)', E_NOTICE, true, true);
     if (!General::realiseDirectory(DOCROOT . '/manifest', $conf['directory']['write_mode'])) {
         self::__abort('Could not create ‘manifest’ directory. Check permission on the root folder.', $start);
     }
     Symphony::Log()->pushToLog('WRITING: Creating ‘logs’ folder (/manifest/logs)', E_NOTICE, true, true);
     if (!General::realiseDirectory(DOCROOT . '/manifest/logs', $conf['directory']['write_mode'])) {
         self::__abort('Could not create ‘logs’ directory. Check permission on /manifest.', $start);
     }
     Symphony::Log()->pushToLog('WRITING: Creating ‘cache’ folder (/manifest/cache)', E_NOTICE, true, true);
     if (!General::realiseDirectory(DOCROOT . '/manifest/cache', $conf['directory']['write_mode'])) {
         self::__abort('Could not create ‘cache’ directory. Check permission on /manifest.', $start);
     }
     Symphony::Log()->pushToLog('WRITING: Creating ‘tmp’ folder (/manifest/tmp)', E_NOTICE, true, true);
     if (!General::realiseDirectory(DOCROOT . '/manifest/tmp', $conf['directory']['write_mode'])) {
         self::__abort('Could not create ‘tmp’ directory. Check permission on /manifest.', $start);
     }
     // Writing configuration file
     Symphony::Log()->pushToLog('WRITING: Configuration File', E_NOTICE, true, true);
     Symphony::Configuration()->setArray($conf);
     if (!Symphony::Configuration()->write(CONFIG, $conf['file']['write_mode'])) {
         self::__abort('Could not create config file ‘' . CONFIG . '’. Check permission on /manifest.', $start);
     }
     // Writing htaccess file
     Symphony::Log()->pushToLog('CONFIGURING: Frontend', E_NOTICE, true, true);
     $rewrite_base = ltrim(preg_replace('/\\/install$/i', NULL, dirname($_SERVER['PHP_SELF'])), '/');
     $htaccess = str_replace('<!-- REWRITE_BASE -->', $rewrite_base, file_get_contents(INSTALL . '/includes/htaccess.txt'));
     if (!General::writeFile(DOCROOT . "/.htaccess", $htaccess, $conf['file']['write_mode'], 'a')) {
         self::__abort('Could not write ‘.htaccess’ file. Check permission on ' . DOCROOT, $start);
     }
     // Writing /workspace folder
     if (!is_dir(DOCROOT . '/workspace')) {
         // Create workspace folder structure
         Symphony::Log()->pushToLog('WRITING: Creating ‘workspace’ folder (/workspace)', E_NOTICE, true, true);
         if (!General::realiseDirectory(DOCROOT . '/workspace', $conf['directory']['write_mode'])) {
             self::__abort('Could not create ‘workspace’ directory. Check permission on the root folder.', $start);
         }
         Symphony::Log()->pushToLog('WRITING: Creating ‘data-sources’ folder (/workspace/data-sources)', E_NOTICE, true, true);
         if (!General::realiseDirectory(DOCROOT . '/workspace/data-sources', $conf['directory']['write_mode'])) {
             self::__abort('Could not create ‘workspace/data-sources’ directory. Check permission on the root folder.', $start);
         }
         Symphony::Log()->pushToLog('WRITING: Creating ‘events’ folder (/workspace/events)', E_NOTICE, true, true);
         if (!General::realiseDirectory(DOCROOT . '/workspace/events', $conf['directory']['write_mode'])) {
             self::__abort('Could not create ‘workspace/events’ directory. Check permission on the root folder.', $start);
         }
         Symphony::Log()->pushToLog('WRITING: Creating ‘pages’ folder (/workspace/pages)', E_NOTICE, true, true);
         if (!General::realiseDirectory(DOCROOT . '/workspace/pages', $conf['directory']['write_mode'])) {
             self::__abort('Could not create ‘workspace/pages’ directory. Check permission on the root folder.', $start);
         }
         Symphony::Log()->pushToLog('WRITING: Creating ‘utilities’ folder (/workspace/utilities)', E_NOTICE, true, true);
         if (!General::realiseDirectory(DOCROOT . '/workspace/utilities', $conf['directory']['write_mode'])) {
             self::__abort('Could not create ‘workspace/utilities’ directory. Check permission on the root folder.', $start);
         }
     } else {
         Symphony::Log()->pushToLog('An existing ‘workspace’ directory was found at this location. Symphony will use this workspace.', E_NOTICE, true, true);
         // MySQL: Importing workspace data
         Symphony::Log()->pushToLog('MYSQL: Importing Workspace Data...', E_NOTICE, true, true);
         if (is_file(DOCROOT . '/workspace/install.sql')) {
             try {
                 Symphony::Database()->import(file_get_contents(DOCROOT . '/workspace/install.sql'), $fields['database']['use-server-encoding'] != 'yes' ? true : false, true);
             } catch (DatabaseException $e) {
                 self::__abort('There was an error while trying to import data to the database. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(), $start);
             }
         }
     }
     // Write extensions folder
     if (!is_dir(DOCROOT . '/extensions')) {
         // Create extensions folder
         Symphony::Log()->pushToLog('WRITING: Creating ‘extensions’ folder (/extensions)', E_NOTICE, true, true);
         if (!General::realiseDirectory(DOCROOT . '/extensions', $conf['directory']['write_mode'])) {
             self::__abort('Could not create ‘extension’ directory. Check permission on the root folder.', $start);
         }
     }
     // Install existing extensions
     Symphony::Log()->pushToLog('CONFIGURING: Installing existing extensions', E_NOTICE, true, true);
     $disabled_extensions = array();
     foreach (new DirectoryIterator(EXTENSIONS) as $e) {
         if ($e->isDot() || $e->isFile() || !is_file($e->getRealPath() . '/extension.driver.php')) {
             continue;
         }
         $handle = $e->getBasename();
         try {
             if (!ExtensionManager::enable($handle)) {
                 $disabled_extensions[] = $handle;
                 Symphony::Log()->pushToLog('Could not enable the extension ‘' . $handle . '’.', E_NOTICE, true, true);
             }
         } catch (Exception $ex) {
             $disabled_extensions[] = $handle;
             Symphony::Log()->pushToLog('Could not enable the extension ‘' . $handle . '’. ' . $ex->getMessage(), E_NOTICE, true, true);
         }
     }
     // Loading default language
     if (isset($_REQUEST['lang']) && $_REQUEST['lang'] != 'en') {
         Symphony::Log()->pushToLog('CONFIGURING: Default language', E_NOTICE, true, true);
         $language = Lang::Languages();
         $language = $language[$_REQUEST['lang']];
         // Is the language extension enabled?
         if (in_array('lang_' . $language['handle'], ExtensionManager::listInstalledHandles())) {
             Symphony::Configuration()->set('lang', $_REQUEST['lang'], 'symphony');
             if (!Symphony::Configuration()->write(CONFIG, $conf['file']['write_mode'])) {
                 Symphony::Log()->pushToLog('Could not write default language ‘' . $language['name'] . '’ to config file.', E_NOTICE, true, true);
             }
         } else {
             Symphony::Log()->pushToLog('Could not enable the desired language ‘' . $language['name'] . '’.', E_NOTICE, true, true);
         }
     }
     // Installation completed. Woo-hoo!
     Symphony::Log()->writeToLog('============================================', true);
     Symphony::Log()->writeToLog(sprintf('INSTALLATION COMPLETED: Execution Time - %d sec (%s)', max(1, time() - $start), date('d.m.y H:i:s')), true);
     Symphony::Log()->writeToLog('============================================' . PHP_EOL . PHP_EOL . PHP_EOL, true);
     return $disabled_extensions;
 }
 public function __actionEdit()
 {
     if (!($author_id = (int) $this->_context[1])) {
         redirect(SYMPHONY_URL . '/system/authors/');
     }
     $isOwner = $author_id == Administration::instance()->Author->get('id');
     if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
         $fields = $_POST['fields'];
         $this->_Author = AuthorManager::fetchByID($author_id);
         $authenticated = false;
         if ($fields['email'] != $this->_Author->get('email')) {
             $changing_email = true;
         }
         // Check the old password was correct
         if (isset($fields['old-password']) && strlen(trim($fields['old-password'])) > 0 && Cryptography::compare(trim($fields['old-password']), $this->_Author->get('password'))) {
             $authenticated = true;
         } else {
             if (Administration::instance()->Author->isDeveloper()) {
                 $authenticated = true;
             }
         }
         $this->_Author->set('id', $author_id);
         if ($this->_Author->isPrimaryAccount() || $isOwner && Administration::instance()->Author->isDeveloper()) {
             $this->_Author->set('user_type', 'developer');
             // Primary accounts are always developer, Developers can't lower their level
         } elseif (Administration::instance()->Author->isDeveloper() && isset($fields['user_type'])) {
             $this->_Author->set('user_type', $fields['user_type']);
             // Only developer can change user type
         }
         $this->_Author->set('email', $fields['email']);
         $this->_Author->set('username', $fields['username']);
         $this->_Author->set('first_name', General::sanitize($fields['first_name']));
         $this->_Author->set('last_name', General::sanitize($fields['last_name']));
         $this->_Author->set('language', $fields['language']);
         if (trim($fields['password']) != '') {
             $this->_Author->set('password', Cryptography::hash($fields['password']));
             $changing_password = true;
         }
         // Don't allow authors to set the Section Index as a default area
         // If they had it previously set, just save `null` which will redirect
         // the Author (when logging in) to their own Author record
         if ($this->_Author->get('user_type') == 'author' && $fields['default_area'] == '/blueprints/sections/') {
             $this->_Author->set('default_area', null);
         } else {
             $this->_Author->set('default_area', $fields['default_area']);
         }
         $this->_Author->set('auth_token_active', $fields['auth_token_active'] ? $fields['auth_token_active'] : 'no');
         if ($this->_Author->validate($this->_errors)) {
             if (!$authenticated && ($changing_password || $changing_email)) {
                 if ($changing_password) {
                     $this->_errors['old-password'] = __('Wrong password. Enter old password to change it.');
                 } elseif ($changing_email) {
                     $this->_errors['old-password'] = __('Wrong password. Enter old one to change email address.');
                 }
             } elseif (($fields['password'] != '' || $fields['password-confirmation'] != '') && $fields['password'] != $fields['password-confirmation']) {
                 $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
             } elseif ($this->_Author->commit()) {
                 Symphony::Database()->delete('tbl_forgotpass', " `expiry` < '" . DateTimeObj::getGMT('c') . "' OR `author_id` = '" . $author_id . "' ");
                 if ($isOwner) {
                     Administration::instance()->login($this->_Author->get('username'), $this->_Author->get('password'), true);
                 }
                 /**
                  * After editing an author, provided with the Author object
                  *
                  * @delegate AuthorPostEdit
                  * @since Symphony 2.2
                  * @param string $context
                  * '/system/authors/'
                  * @param Author $author
                  * An Author object
                  */
                 Symphony::ExtensionManager()->notifyMembers('AuthorPostEdit', '/system/authors/', array('author' => $this->_Author));
                 redirect(SYMPHONY_URL . '/system/authors/edit/' . $author_id . '/saved/');
             } else {
                 $this->pageAlert(__('Unknown errors occurred while attempting to save.') . '<a href="' . SYMPHONY_URL . '/system/log/">' . __('Check your activity log') . '</a>.', Alert::ERROR);
             }
         } else {
             if (is_array($this->_errors) && !empty($this->_errors)) {
                 $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
             }
         }
     } else {
         if (@array_key_exists('delete', $_POST['action'])) {
             /**
              * Prior to deleting an author, provided with the Author ID.
              *
              * @delegate AuthorPreDelete
              * @since Symphony 2.2
              * @param string $context
              * '/system/authors/'
              * @param integer $author_id
              *  The ID of Author ID that is about to be deleted
              */
             Symphony::ExtensionManager()->notifyMembers('AuthorPreDelete', '/system/authors/', array('author_id' => $author_id));
             if (!$isOwner) {
                 AuthorManager::delete($author_id);
                 redirect(SYMPHONY_URL . '/system/authors/');
             } else {
                 $this->pageAlert(__('You cannot remove yourself as you are the active Author.'), Alert::ERROR);
             }
         }
     }
 }
 /**
  * Given a string, this function will encode the password
  * using the PBKDF2 algorithm.
  *
  * @param string $password
  * @return string
  */
 public function encodePassword($password)
 {
     require_once TOOLKIT . '/class.cryptography.php';
     return Cryptography::hash($password);
 }
 /**
  * Uses `SHA1` or `MD5` to create a hash based on some input
  * This function is currently very basic, but would allow
  * future expansion. Salting the hash comes to mind.
  *
  * @param string $input
  * the string to be hashed
  * @param string $algorithm
  * a valid PHP function handle
  * @return string
  * the hashed string
  */
 public static function hash($input, $algorithm = 'sha1')
 {
     return Cryptography::hash($input, $algorithm);
 }