diff options
Diffstat (limited to 'phpBB/phpbb')
33 files changed, 639 insertions, 98 deletions
diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index 38755ccf99..b59f0e60ec 100644 --- a/phpBB/phpbb/auth/auth.php +++ b/phpBB/phpbb/auth/auth.php @@ -927,11 +927,11 @@ class auth */ function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0) { - global $config, $db, $user, $phpbb_root_path, $phpEx, $phpbb_container; + global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container; - $method = trim(basename($config['auth_method'])); + $provider_collection = $phpbb_container->get('auth.provider_collection'); - $provider = $phpbb_container->get('auth.provider.' . $method); + $provider = $provider_collection->get_provider(); if ($provider) { $login = $provider->login($username, $password); diff --git a/phpBB/phpbb/auth/provider/apache.php b/phpBB/phpbb/auth/provider/apache.php index 9137a77210..aa5bf64335 100644 --- a/phpBB/phpbb/auth/provider/apache.php +++ b/phpBB/phpbb/auth/provider/apache.php @@ -137,7 +137,7 @@ class apache extends \phpbb\auth\provider\base return array( 'status' => LOGIN_SUCCESS_CREATE_PROFILE, 'error_msg' => false, - 'user_row' => user_row_apache($php_auth_user, $php_auth_pw), + 'user_row' => $this->user_row($php_auth_user, $php_auth_pw), ); } @@ -185,7 +185,7 @@ class apache extends \phpbb\auth\provider\base } // create the user if he does not exist yet - user_add(user_row_apache($php_auth_user, $php_auth_pw)); + user_add($this->user_row($php_auth_user, $php_auth_pw)); $sql = 'SELECT * FROM ' . USERS_TABLE . " diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index 722eeffa9a..d8c5fb72de 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -87,7 +87,7 @@ class db extends \phpbb\auth\provider\base $username_clean = utf8_clean_string($username); - $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts + $sql = 'SELECT * FROM ' . USERS_TABLE . " WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; $result = $this->db->sql_query($sql); @@ -123,7 +123,7 @@ class db extends \phpbb\auth\provider\base 'username_clean' => $username_clean, ); $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data); - $result = $this->db->sql_query($sql); + $this->db->sql_query($sql); } else { @@ -175,7 +175,7 @@ class db extends \phpbb\auth\provider\base } // Check password ... - if ($this->passwords_manager->check($password, $row['user_password'])) + if ($this->passwords_manager->check($password, $row['user_password'], $row)) { // Check for old password hash... if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32) @@ -232,7 +232,7 @@ class db extends \phpbb\auth\provider\base // Give status about wrong password... return array( 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, - 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD', + 'error_msg' => 'LOGIN_ERROR_PASSWORD', 'user_row' => $row, ); } diff --git a/phpBB/phpbb/auth/provider_collection.php b/phpBB/phpbb/auth/provider_collection.php index a74a2135dc..8e7e9e2cc1 100644 --- a/phpBB/phpbb/auth/provider_collection.php +++ b/phpBB/phpbb/auth/provider_collection.php @@ -38,6 +38,7 @@ class provider_collection extends \phpbb\di\service_collection /** * Get an auth provider. * + * @param string $provider_name The name of the auth provider * @return object Default auth provider selected in config if it * does exist. Otherwise the standard db auth * provider. @@ -46,11 +47,12 @@ class provider_collection extends \phpbb\di\service_collection * auth provider exist. The db auth provider * should always exist in a phpBB installation. */ - public function get_provider() + public function get_provider($provider_name = '') { - if ($this->offsetExists('auth.provider.' . basename(trim($this->config['auth_method'])))) + $provider_name = ($provider_name !== '') ? $provider_name : basename(trim($this->config['auth_method'])); + if ($this->offsetExists('auth.provider.' . $provider_name)) { - return $this->offsetGet('auth.provider.' . basename(trim($this->config['auth_method']))); + return $this->offsetGet('auth.provider.' . $provider_name); } // Revert to db auth provider if selected method does not exist else if ($this->offsetExists('auth.provider.db')) diff --git a/phpBB/phpbb/avatar/manager.php b/phpBB/phpbb/avatar/manager.php index 42ae61a9a2..8d83152ed6 100644 --- a/phpBB/phpbb/avatar/manager.php +++ b/phpBB/phpbb/avatar/manager.php @@ -326,17 +326,41 @@ class manager $driver->delete($avatar_data); } - $result = self::$default_row; + $result = $this->prefix_avatar_columns($prefix, self::$default_row); - foreach ($result as $key => $value) + $sql = 'UPDATE ' . $table . ' + SET ' . $db->sql_build_array('UPDATE', $result) . ' + WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id']; + $db->sql_query($sql); + + // Make sure we also delete this avatar from the users + if ($prefix === 'group_') { - $result[$prefix . $key] = $value; - unset($result[$key]); + $result = $this->prefix_avatar_columns('user_', self::$default_row); + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $result) . " + WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'"; + $db->sql_query($sql); } + } - $sql = 'UPDATE ' . $table . ' - SET ' . $db->sql_build_array('UPDATE', $result) . ' - WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id']; - $db->sql_query($sql); + /** + * Prefix avatar columns + * + * @param string $prefix Column prefix + * @param array $data Column data + * + * @return array Column data with prefixed column names + */ + public function prefix_avatar_columns($prefix, $data) + { + foreach ($data as $key => $value) + { + $data[$prefix . $key] = $value; + unset($data[$key]); + } + + return $data; } } diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php index ea446d7bc3..584f3afec1 100644 --- a/phpBB/phpbb/captcha/plugins/recaptcha.php +++ b/phpBB/phpbb/captcha/plugins/recaptcha.php @@ -26,8 +26,10 @@ class recaptcha extends captcha_abstract var $challenge; var $response; - // PHP4 Constructor - function phpbb_recaptcha() + /** + * Constructor + */ + public function __construct() { global $request; $this->recaptcha_server = $request->is_secure() ? $this->recaptcha_server_secure : $this->recaptcha_server; diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index 187e455d48..52e6947c2c 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -44,6 +44,9 @@ class helper /* @var \phpbb\symfony_request */ protected $symfony_request; + /* @var \phpbb\request\request_interface */ + protected $request; + /** * @var \phpbb\filesystem The filesystem object */ @@ -70,16 +73,18 @@ class helper * @param \phpbb\controller\provider $provider Path provider * @param \phpbb\extension\manager $manager Extension manager object * @param \phpbb\symfony_request $symfony_request Symfony Request object + * @param \phpbb\request\request_interface $request phpBB request object * @param \phpbb\filesystem $filesystem The filesystem object * @param string $phpbb_root_path phpBB root path * @param string $php_ext PHP file extension */ - public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext) + public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext) { $this->template = $template; $this->user = $user; $this->config = $config; $this->symfony_request = $symfony_request; + $this->request = $request; $this->filesystem = $filesystem; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; @@ -153,7 +158,7 @@ class helper } } - $base_url = $this->filesystem->clean_path($base_url); + $base_url = $this->request->escape($this->filesystem->clean_path($base_url), true); $context->setBaseUrl($base_url); @@ -197,6 +202,6 @@ class helper */ public function get_current_url() { - return generate_board_url(true) . $this->symfony_request->getRequestUri(); + return generate_board_url(true) . $this->request->escape($this->symfony_request->getRequestUri(), true); } } diff --git a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php index 13071e9891..328c08f1ec 100644 --- a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php +++ b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php @@ -25,9 +25,13 @@ class captcha_plugins extends \phpbb\db\migration\migration public function update_data() { $captcha_plugin = $this->config['captcha_plugin']; - if (strpos($this->config['captcha_plugin'], 'phpbb_captcha_') === 0) + if (strpos($captcha_plugin, 'phpbb_captcha_') === 0) { - $captcha_plugin = substr($this->config['captcha_plugin'], strlen('phpbb_captcha_')); + $captcha_plugin = substr($captcha_plugin, strlen('phpbb_captcha_')); + } + else if (strpos($captcha_plugin, 'phpbb_') === 0) + { + $captcha_plugin = substr($captcha_plugin, strlen('phpbb_')); } return array( diff --git a/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php b/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php index d5f9076196..8211457dc6 100644 --- a/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php +++ b/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php @@ -29,7 +29,8 @@ class reset_missing_captcha_plugin extends \phpbb\db\migration\migration { return array( array('if', array( - (!is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)), + (is_dir($this->phpbb_root_path . 'includes/captcha/plugins/') && + !is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)), array('config.update', array('captcha_plugin', 'phpbb_captcha_nogd')), )), ); diff --git a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php index 5a3a1d5de7..e8d3a3af64 100644 --- a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php +++ b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php @@ -92,7 +92,7 @@ class style_update_p1 extends \phpbb\db\migration\migration else { $sql = 'SELECT s.style_id, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_id - FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "stles_theme c + FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "styles_theme c WHERE t.template_id = s.template_id AND c.theme_id = s.theme_id"; } diff --git a/phpBB/phpbb/db/migration/data/v31x/m_softdelete_global.php b/phpBB/phpbb/db/migration/data/v31x/m_softdelete_global.php new file mode 100644 index 0000000000..dd7e20e762 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/m_softdelete_global.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class m_softdelete_global extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v311'); + } + + public function update_data() + { + return array( + // Make m_softdelete global. The add method will take care of updating + // it if it already exists. + array('permission.add', array('m_softdelete', true)), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/style_update.php b/phpBB/phpbb/db/migration/data/v31x/style_update.php new file mode 100644 index 0000000000..bb030bbe6d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/style_update.php @@ -0,0 +1,136 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class style_update extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\gold'); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'update_installed_styles'))), + ); + } + + public function update_installed_styles() + { + // Get all currently available styles + $styles = $this->find_style_dirs(); + $style_paths = $style_ids = array(); + + $sql = 'SELECT style_path, style_id + FROM ' . $this->table_prefix . 'styles'; + $result = $this->db->sql_query($sql); + while ($styles_row = $this->db->sql_fetchrow()) + { + if (in_array($styles_row['style_path'], $styles)) + { + $style_paths[] = $styles_row['style_path']; + $style_ids[] = $styles_row['style_id']; + } + } + $this->db->sql_freeresult($result); + + // Install prosilver if no style is available and prosilver can be installed + if (empty($style_paths) && in_array('prosilver', $styles)) + { + // Try to parse config file + $cfg = parse_cfg_file($this->phpbb_root_path . 'styles/prosilver/style.cfg'); + + // Stop running this if prosilver cfg file can't be read + if (empty($cfg)) + { + throw new \RuntimeException('No styles available and could not fall back to prosilver.'); + } + + $style = array( + 'style_name' => 'prosilver', + 'style_copyright' => '© phpBB Limited', + 'style_active' => 1, + 'style_path' => 'prosilver', + 'bbcode_bitfield' => 'kNg=', + 'style_parent_id' => 0, + 'style_parent_tree' => '', + ); + + // Add to database + $this->db->sql_transaction('begin'); + + $sql = 'INSERT INTO ' . $this->table_prefix . 'styles + ' . $this->db->sql_build_array('INSERT', $style); + $this->db->sql_query($sql); + + $style_id = $this->db->sql_nextid(); + $style_ids[] = $style_id; + + $this->db->sql_transaction('commit'); + + // Set prosilver to default style + $this->config->set('default_style', $style_id); + } + else if (empty($styles) && empty($available_styles)) + { + throw new \RuntimeException('No valid styles available'); + } + + // Make sure default style is available + if (!in_array($this->config['default_style'], $style_ids)) + { + $this->config->set('default_style', array_pop($style_ids)); + } + + // Reset users to default style if their user_style is nonexistent + $sql = 'UPDATE ' . $this->table_prefix . "users + SET user_style = {$this->config['default_style']} + WHERE " . $this->db->sql_in_set('user_style', $style_ids, true, true); + $this->db->sql_query($sql); + } + + /** + * Find all directories that have styles + * Copied from acp_styles + * + * @return array Directory names + */ + protected function find_style_dirs() + { + $styles = array(); + $styles_path = $this->phpbb_root_path . 'styles/'; + + $dp = @opendir($styles_path); + if ($dp) + { + while (($file = readdir($dp)) !== false) + { + $dir = $styles_path . $file; + if ($file[0] == '.' || !is_dir($dir)) + { + continue; + } + + if (file_exists("{$dir}/style.cfg")) + { + $styles[] = $file; + } + } + closedir($dp); + } + + return $styles; + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v311.php b/phpBB/phpbb/db/migration/data/v31x/v311.php new file mode 100644 index 0000000000..00844dd4c0 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v311.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v311 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\gold', + '\phpbb\db\migration\data\v31x\style_update', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v312.php b/phpBB/phpbb/db/migration/data/v31x/v312.php new file mode 100644 index 0000000000..bf49935f4d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v312.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v312 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v312rc1', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.2')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v312rc1.php b/phpBB/phpbb/db/migration/data/v31x/v312rc1.php new file mode 100644 index 0000000000..d4b133fc01 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v312rc1.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v312rc1 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v311', + '\phpbb\db\migration\data\v31x\m_softdelete_global', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.2-RC1')), + ); + } +} diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index 621a808a03..d03496eae3 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -59,6 +59,13 @@ class migrator protected $migrations = array(); /** + * Array of migrations that have been determined to be fulfillable + * + * @var array + */ + protected $fulfillable_migrations = array(); + + /** * 'name,' 'class,' and 'state' of the last migration run * * 'effectively_installed' set and set to true if the migration was effectively_installed @@ -653,7 +660,7 @@ class migrator */ public function unfulfillable($name) { - if (isset($this->migration_state[$name])) + if (isset($this->migration_state[$name]) || isset($this->fulfillable_migrations[$name])) { return false; } @@ -674,6 +681,7 @@ class migrator return $unfulfillable; } } + $this->fulfillable_migrations[$name] = true; return false; } diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php index 0781d7425e..c8d25f23a2 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/tools.php @@ -2643,7 +2643,7 @@ class tools AND cols.id = ix.id WHERE ix.id = object_id('{$table_name}') AND cols.name = '{$column_name}' - AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique) ? '1' : '0'; + AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0'); } else { @@ -2657,7 +2657,7 @@ class tools AND cols.object_id = ix.object_id WHERE ix.object_id = object_id('{$table_name}') AND cols.name = '{$column_name}' - AND ix.is_unique = " . ($unique) ? '1' : '0'; + AND ix.is_unique = " . ($unique ? '1' : '0'); } break; diff --git a/phpBB/phpbb/di/extension/config.php b/phpBB/phpbb/di/extension/config.php index 27ebc94bae..7984a783df 100644 --- a/phpBB/phpbb/di/extension/config.php +++ b/phpBB/phpbb/di/extension/config.php @@ -39,16 +39,24 @@ class config extends Extension */ public function load(array $config, ContainerBuilder $container) { - $container->setParameter('core.adm_relative_path', ($this->config_php->get('phpbb_adm_relative_path') ? $this->config_php->get('phpbb_adm_relative_path') : 'adm/')); - $container->setParameter('core.table_prefix', $this->config_php->get('table_prefix')); - $container->setParameter('cache.driver.class', $this->convert_30_acm_type($this->config_php->get('acm_type'))); - $container->setParameter('dbal.driver.class', $this->config_php->convert_30_dbms_to_31($this->config_php->get('dbms'))); - $container->setParameter('dbal.dbhost', $this->config_php->get('dbhost')); - $container->setParameter('dbal.dbuser', $this->config_php->get('dbuser')); - $container->setParameter('dbal.dbpasswd', $this->config_php->get('dbpasswd')); - $container->setParameter('dbal.dbname', $this->config_php->get('dbname')); - $container->setParameter('dbal.dbport', $this->config_php->get('dbport')); - $container->setParameter('dbal.new_link', defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK); + $parameters = array( + 'core.adm_relative_path' => $this->config_php->get('phpbb_adm_relative_path') ? $this->config_php->get('phpbb_adm_relative_path') : 'adm/', + 'core.table_prefix' => $this->config_php->get('table_prefix'), + 'cache.driver.class' => $this->convert_30_acm_type($this->config_php->get('acm_type')), + 'dbal.driver.class' => $this->config_php->convert_30_dbms_to_31($this->config_php->get('dbms')), + 'dbal.dbhost' => $this->config_php->get('dbhost'), + 'dbal.dbuser' => $this->config_php->get('dbuser'), + 'dbal.dbpasswd' => $this->config_php->get('dbpasswd'), + 'dbal.dbname' => $this->config_php->get('dbname'), + 'dbal.dbport' => $this->config_php->get('dbport'), + 'dbal.new_link' => defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK, + ); + $parameter_bag = $container->getParameterBag(); + + foreach ($parameters as $parameter => $value) + { + $container->setParameter($parameter, $parameter_bag->escapeValue($value)); + } } /** diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php index edca8ee1af..a64d88fe39 100644 --- a/phpBB/phpbb/extension/metadata_manager.php +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -177,6 +177,7 @@ class metadata_manager throw new \phpbb\extension\exception($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file)); } + array_walk_recursive($metadata, array($this, 'sanitize_json')); $this->metadata = $metadata; return true; @@ -184,6 +185,17 @@ class metadata_manager } /** + * Sanitize input from JSON array using htmlspecialchars() + * + * @param mixed $value Value of array row + * @param string $key Key of array row + */ + public function sanitize_json(&$value, $key) + { + $value = htmlspecialchars($value); + } + + /** * This array handles the cleaning of the array * * @return array Contains the cleaned metadata array @@ -337,30 +349,30 @@ class metadata_manager public function output_template_data() { $this->template->assign_vars(array( - 'META_NAME' => htmlspecialchars($this->metadata['name']), - 'META_TYPE' => htmlspecialchars($this->metadata['type']), - 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? htmlspecialchars($this->metadata['description']) : '', + 'META_NAME' => $this->metadata['name'], + 'META_TYPE' => $this->metadata['type'], + 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? $this->metadata['description'] : '', 'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '', - 'META_VERSION' => (isset($this->metadata['version'])) ? htmlspecialchars($this->metadata['version']) : '', - 'META_TIME' => (isset($this->metadata['time'])) ? htmlspecialchars($this->metadata['time']) : '', - 'META_LICENSE' => htmlspecialchars($this->metadata['license']), + 'META_VERSION' => (isset($this->metadata['version'])) ? $this->metadata['version'] : '', + 'META_TIME' => (isset($this->metadata['time'])) ? $this->metadata['time'] : '', + 'META_LICENSE' => $this->metadata['license'], - 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? htmlspecialchars($this->metadata['require']['php']) : '', + 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '', 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(), - 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? htmlspecialchars($this->metadata['extra']['soft-require']['phpbb/phpbb']) : '', + 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? $this->metadata['extra']['soft-require']['phpbb/phpbb'] : '', 'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(), - 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? htmlspecialchars($this->metadata['extra']['display-name']) : '', + 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '', )); foreach ($this->metadata['authors'] as $author) { $this->template->assign_block_vars('meta_authors', array( - 'AUTHOR_NAME' => htmlspecialchars($author['name']), + 'AUTHOR_NAME' => $author['name'], 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '', 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '', - 'AUTHOR_ROLE' => (isset($author['role'])) ? htmlspecialchars($author['role']) : '', + 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '', )); } } diff --git a/phpBB/phpbb/file_downloader.php b/phpBB/phpbb/file_downloader.php new file mode 100644 index 0000000000..d717b394d5 --- /dev/null +++ b/phpBB/phpbb/file_downloader.php @@ -0,0 +1,120 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb; + +class file_downloader +{ + /** @var string Error string */ + protected $error_string = ''; + + /** @var int Error number */ + protected $error_number = 0; + + /** + * Retrieve contents from remotely stored file + * + * @param string $host File host + * @param string $directory Directory file is in + * @param string $filename Filename of file to retrieve + * @param int $port Port to connect to; default: 80 + * @param int $timeout Connection timeout in seconds; default: 6 + * + * @return mixed File data as string if file can be read and there is no + * timeout, false if there were errors or the connection timed out + * + * @throws \RuntimeException If data can't be retrieved and no error + * message is returned + */ + public function get($host, $directory, $filename, $port = 80, $timeout = 6) + { + // Set default values for error variables + $this->error_number = 0; + $this->error_string = ''; + + if ($socket = @fsockopen($host, $port, $this->error_number, $this->error_string, $timeout)) + { + @fputs($socket, "GET $directory/$filename HTTP/1.0\r\n"); + @fputs($socket, "HOST: $host\r\n"); + @fputs($socket, "Connection: close\r\n\r\n"); + + $timer_stop = time() + $timeout; + stream_set_timeout($socket, $timeout); + + $file_info = ''; + $get_info = false; + + while (!@feof($socket)) + { + if ($get_info) + { + $file_info .= @fread($socket, 1024); + } + else + { + $line = @fgets($socket, 1024); + if ($line == "\r\n") + { + $get_info = true; + } + else if (stripos($line, '404 not found') !== false) + { + throw new \RuntimeException(array('FILE_NOT_FOUND', $filename)); + } + } + + $stream_meta_data = stream_get_meta_data($socket); + + if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop) + { + throw new \RuntimeException('FSOCK_TIMEOUT'); + } + } + @fclose($socket); + } + else + { + if ($this->error_string) + { + $this->error_string = utf8_convert_message($this->error_string); + return false; + } + else + { + throw new \RuntimeException('FSOCK_DISABLED'); + } + } + + return $file_info; + } + + /** + * Get error string + * + * @return string Error string + */ + public function get_error_string() + { + return $this->error_string; + } + + /** + * Get error number + * + * @return int Error number + */ + public function get_error_number() + { + return $this->error_number; + } +} diff --git a/phpBB/phpbb/message/admin_form.php b/phpBB/phpbb/message/admin_form.php index 93db59880c..96b8d3499e 100644 --- a/phpBB/phpbb/message/admin_form.php +++ b/phpBB/phpbb/message/admin_form.php @@ -178,6 +178,7 @@ class admin_form extends form 'S_CONTACT_ADMIN' => true, 'S_CONTACT_FORM' => $this->config['contact_admin_form_enable'], 'S_IS_REGISTERED' => $this->user->data['is_registered'], + 'S_POST_ACTION' => append_sid($this->phpbb_root_path . 'memberlist.' . $this->phpEx, 'mode=contactadmin'), 'CONTACT_INFO' => $l_admin_info, 'MESSAGE' => $this->body, diff --git a/phpBB/phpbb/message/form.php b/phpBB/phpbb/message/form.php index 076b41dc07..21d4de0b4d 100644 --- a/phpBB/phpbb/message/form.php +++ b/phpBB/phpbb/message/form.php @@ -146,7 +146,7 @@ abstract class form WHERE user_id = ' . $this->user->data['user_id']; $this->db->sql_query($sql); - if ($this->cc_sender) + if ($this->cc_sender && $this->user->data['is_registered']) { $this->message->cc_sender(); } diff --git a/phpBB/phpbb/message/topic_form.php b/phpBB/phpbb/message/topic_form.php index 1e0f2a1945..174643bb81 100644 --- a/phpBB/phpbb/message/topic_form.php +++ b/phpBB/phpbb/message/topic_form.php @@ -117,7 +117,7 @@ class topic_form extends form 'TOPIC_NAME' => htmlspecialchars_decode($this->topic_row['topic_title']), 'U_TOPIC' => generate_board_url() . '/viewtopic.' . $this->phpEx . '?f=' . $this->topic_row['forum_id'] . '&t=' . $this->topic_id, )); - + $this->message->set_body($this->body); $this->message->add_recipient( $this->recipient_name, $this->recipient_address, diff --git a/phpBB/phpbb/notification/manager.php b/phpBB/phpbb/notification/manager.php index 971a53a16a..dd611e1dd1 100644 --- a/phpBB/phpbb/notification/manager.php +++ b/phpBB/phpbb/notification/manager.php @@ -292,7 +292,7 @@ class manager WHERE notification_time <= " . (int) $time . (($notification_type_name !== false) ? ' AND ' . (is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') . - (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') . + (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : 'item_parent_id = ' . (int) $item_parent_id) : '') . (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : ''); $this->db->sql_query($sql); } diff --git a/phpBB/phpbb/path_helper.php b/phpBB/phpbb/path_helper.php index 936564d8b6..b49d8d13c2 100644 --- a/phpBB/phpbb/path_helper.php +++ b/phpBB/phpbb/path_helper.php @@ -154,6 +154,7 @@ class path_helper return $this->web_root_path; } + // We do not need to escape $path_info, $request_uri and $script_name because we can not find their content in the result. // Path info (e.g. /foo/bar) $path_info = $this->filesystem->clean_path($this->symfony_request->getPathInfo()); @@ -203,9 +204,12 @@ class path_helper */ if ($this->request->is_ajax() && $this->symfony_request->get('_referer')) { + // We need to escape $absolute_board_url because it can be partially concatenated to the result. + $absolute_board_url = $this->request->escape($this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath(), true); + $referer_web_root_path = $this->get_web_root_path_from_ajax_referer( $this->symfony_request->get('_referer'), - $this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath() + $absolute_board_url ); return $this->web_root_path = $this->phpbb_root_path . $referer_web_root_path; } @@ -278,10 +282,16 @@ class path_helper $referer_dir = dirname($referer_dir); } - while (strpos($absolute_board_url, $referer_dir) !== 0) + while (($dir_position = strpos($absolute_board_url, $referer_dir)) !== 0) { $fixed_root_path .= '../'; $referer_dir = dirname($referer_dir); + + // Just return phpbb_root_path if we reach the top directory + if ($referer_dir === '.') + { + return $this->phpbb_root_path; + } } $fixed_root_path .= substr($absolute_board_url, strlen($referer_dir) + 1); diff --git a/phpBB/phpbb/profilefields/type/type_base.php b/phpBB/phpbb/profilefields/type/type_base.php index 52f5d15511..9b4bada26d 100644 --- a/phpBB/phpbb/profilefields/type/type_base.php +++ b/phpBB/phpbb/profilefields/type/type_base.php @@ -158,7 +158,19 @@ abstract class type_base implements type_interface } else { - return $this->request->variable($key, '', true); + $default_value = ''; + $lang_fields = array( + 'l_lang_name', + 'l_lang_explain', + 'l_lang_default_value', + 'l_lang_options', + ); + + if (in_array($key, $lang_fields)) + { + $default_value = array(0 => ''); + } + return $this->request->variable($key, $default_value, true); } } diff --git a/phpBB/phpbb/profilefields/type/type_bool.php b/phpBB/phpbb/profilefields/type/type_bool.php index 0582722833..75934e3be7 100644 --- a/phpBB/phpbb/profilefields/type/type_bool.php +++ b/phpBB/phpbb/profilefields/type/type_bool.php @@ -352,7 +352,7 @@ class type_bool extends type_base } } - if ($step == 3 && ($field_data[$key] || $action != 'edit') && $key == 'l_lang_options') + if ($key == 'l_lang_options' && $this->request->is_set($key)) { $field_data[$key] = $this->request->variable($key, array(0 => array('')), true); diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index ea9854894c..56ce3999ed 100644 --- a/phpBB/phpbb/request/request.php +++ b/phpBB/phpbb/request/request.php @@ -275,7 +275,7 @@ class request implements \phpbb\request\request_interface */ public function file($form_name) { - return $this->variable($form_name, array('name' => 'none'), false, \phpbb\request\request_interface::FILES); + return $this->variable($form_name, array('name' => 'none'), true, \phpbb\request\request_interface::FILES); } /** @@ -416,4 +416,27 @@ class request implements \phpbb\request\request_interface { return $this->input[$super_global]; } + + /** + * {@inheritdoc} + */ + public function escape($var, $multibyte) + { + if (is_array($var)) + { + $result = array(); + foreach ($var as $key => $value) + { + $this->type_cast_helper->set_var($key, $key, gettype($key), $multibyte); + $result[$key] = $this->escape($value, $multibyte); + } + $var = $result; + } + else + { + $this->type_cast_helper->set_var($var, $var, 'string', $multibyte); + } + + return $var; + } } diff --git a/phpBB/phpbb/request/request_interface.php b/phpBB/phpbb/request/request_interface.php index 3236f73990..47b3b3a4ed 100644 --- a/phpBB/phpbb/request/request_interface.php +++ b/phpBB/phpbb/request/request_interface.php @@ -142,4 +142,14 @@ interface request_interface * @return array The original array of the requested super global. */ public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST); + + /** + * Escape a string variable. + * + * @param mixed $value The contents to fill with + * @param bool $multibyte Indicates whether string values may contain UTF-8 characters. + * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks. + * @return string|array + */ + public function escape($value, $multibyte); } diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index 477e91efd6..691d0d5bef 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -31,10 +31,11 @@ class session var $update_session_page = true; /** - * Extract current session page - * - * @param string $root_path current root path (phpbb_root_path) - */ + * Extract current session page + * + * @param string $root_path current root path (phpbb_root_path) + * @return array + */ static function extract_current_page($root_path) { global $request, $symfony_request, $phpbb_filesystem; @@ -42,8 +43,8 @@ class session $page_array = array(); // First of all, get the request uri... - $script_name = $symfony_request->getScriptName(); - $args = explode('&', $symfony_request->getQueryString()); + $script_name = $request->escape($symfony_request->getScriptName(), true); + $args = $request->escape(explode('&', $symfony_request->getQueryString()), true); // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support... if (!$script_name) @@ -61,8 +62,8 @@ class session // Since some browser do not encode correctly we need to do this with some "special" characters... // " -> %22, ' => %27, < -> %3C, > -> %3E - $find = array('"', "'", '<', '>'); - $replace = array('%22', '%27', '%3C', '%3E'); + $find = array('"', "'", '<', '>', '"', '<', '>'); + $replace = array('%22', '%27', '%3C', '%3E', '%22', '%3C', '%3E'); foreach ($args as $key => $argument) { @@ -87,7 +88,7 @@ class session $symfony_request_path = $phpbb_filesystem->clean_path($symfony_request->getPathInfo()); if ($symfony_request_path !== '/') { - $page_name .= $symfony_request_path; + $page_name .= str_replace('%2F', '/', urlencode($symfony_request_path)); } // current directory within the phpBB root (for example: adm) @@ -1062,7 +1063,7 @@ class session $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); - $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']; + $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain']; header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false); } diff --git a/phpBB/phpbb/symfony_request.php b/phpBB/phpbb/symfony_request.php index bf9ddec493..2931cae3cc 100644 --- a/phpBB/phpbb/symfony_request.php +++ b/phpBB/phpbb/symfony_request.php @@ -15,6 +15,10 @@ namespace phpbb; use Symfony\Component\HttpFoundation\Request; +/** + * WARNING: The Symfony request does not escape the input and should be used very carefully + * prefer the phpbb request as possible + */ class symfony_request extends Request { /** @@ -24,21 +28,12 @@ class symfony_request extends Request */ public function __construct(\phpbb\request\request_interface $phpbb_request) { - // This function is meant to sanitize the global input arrays - $sanitizer = function(&$value, $key) { - $type_cast_helper = new \phpbb\request\type_cast_helper(); - $type_cast_helper->set_var($value, $value, gettype($value), true); - }; - $get_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::GET); $post_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::POST); $server_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::SERVER); $files_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::FILES); $cookie_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::COOKIE); - array_walk_recursive($get_parameters, $sanitizer); - array_walk_recursive($post_parameters, $sanitizer); - parent::__construct($get_parameters, $post_parameters, array(), $cookie_parameters, $files_parameters, $server_parameters); } } diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php index a3b002f350..db3a8e3571 100644 --- a/phpBB/phpbb/template/twig/twig.php +++ b/phpBB/phpbb/template/twig/twig.php @@ -115,6 +115,11 @@ class twig extends \phpbb\template\base ) ); + if (defined('DEBUG')) + { + $this->twig->addExtension(new \Twig_Extension_Debug()); + } + $lexer = new \phpbb\template\twig\lexer($this->twig); $this->twig->setLexer($lexer); @@ -189,13 +194,24 @@ class twig extends \phpbb\template\base { $path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/"; $template_path = $path . 'template/'; + $theme_path = $path . 'theme/'; + $is_valid_dir = false; if (is_dir($template_path)) { + $is_valid_dir = true; + $paths[] = $template_path; + } + if (is_dir($theme_path)) + { + $is_valid_dir = true; + $paths[] = $theme_path; + } + + if ($is_valid_dir) + { // Add the base style directory as a safe directory $this->twig->getLoader()->addSafeDirectory($path); - - $paths[] = $template_path; } } } @@ -253,25 +269,38 @@ class twig extends \phpbb\template\base { $ext_style_template_path = $ext_path . $template_dir['ext_path']; $ext_style_path = dirname($ext_style_template_path); + $ext_style_theme_path = $ext_style_path . 'theme/'; } else { $ext_style_path = $ext_path . 'styles/' . $template_dir['name'] . '/'; $ext_style_template_path = $ext_style_path . 'template/'; + $ext_style_theme_path = $ext_style_path . 'theme/'; } } else { $ext_style_path = $ext_path . 'styles/' . $template_dir . '/'; $ext_style_template_path = $ext_style_path . 'template/'; + $ext_style_theme_path = $ext_style_path . 'theme/'; } + $ok = false; if (is_dir($ext_style_template_path)) { + $ok = true; + $paths[] = $ext_style_template_path; + } + if (is_dir($ext_style_theme_path)) + { + $ok = true; + $paths[] = $ext_style_theme_path; + } + + if ($ok) + { // Add the base style directory as a safe directory $this->twig->getLoader()->addSafeDirectory($ext_style_path); - - $paths[] = $ext_style_template_path; } } diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index 96386f6d04..dc62f06fb2 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -50,6 +50,9 @@ class version_helper /** @var \phpbb\config\config */ protected $config; + /** @var \phpbb\file_downloader */ + protected $file_downloader; + /** @var \phpbb\user */ protected $user; @@ -58,12 +61,14 @@ class version_helper * * @param \phpbb\cache\service $cache * @param \phpbb\config\config $config + * @param \phpbb\file_downloader $file_downloader * @param \phpbb\user $user */ - public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\user $user) + public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\user $user) { $this->cache = $cache; $this->config = $config; + $this->file_downloader = $file_downloader; $this->user = $user; if (defined('PHPBB_QA')) @@ -249,16 +254,32 @@ class version_helper } else if ($info === false || $force_update) { - $errstr = $errno = ''; - $info = get_remote_file($this->host, $this->path, $this->file, $errstr, $errno); + try { + $info = $this->file_downloader->get($this->host, $this->path, $this->file); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($this->user->lang($exception->getMessage())); + } + $error_string = $this->file_downloader->get_error_string(); - if (!empty($errstr)) + if (!empty($error_string)) { - throw new \RuntimeException($errstr); + throw new \RuntimeException($error_string); } $info = json_decode($info, true); + // Sanitize any data we retrieve from a server + if (!empty($info)) + { + $json_sanitizer = function (&$value, $key) { + $type_cast_helper = new \phpbb\request\type_cast_helper(); + $type_cast_helper->set_var($value, $value, gettype($value), true); + }; + array_walk_recursive($info, $json_sanitizer); + } + if (empty($info['stable']) && empty($info['unstable'])) { $this->user->add_lang('acp/common'); @@ -266,15 +287,6 @@ class version_helper throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL')); } - // Replace & with & on announcement links - foreach ($info as $stability => $branches) - { - foreach ($branches as $branch => $branch_data) - { - $info[$stability][$branch]['announcement'] = str_replace('&', '&', $branch_data['announcement']); - } - } - $info['stable'] = (empty($info['stable'])) ? array() : $info['stable']; $info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable']; |