diff options
Diffstat (limited to 'phpBB/phpbb')
43 files changed, 2203 insertions, 172 deletions
diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index 3be1d3873f..142a47247f 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -78,7 +78,7 @@ class db extends \phpbb\auth\provider\base $username_clean = utf8_clean_string($username); - $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts + $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts FROM ' . USERS_TABLE . " WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; $result = $this->db->sql_query($sql); @@ -170,72 +170,8 @@ class db extends \phpbb\auth\provider\base } - // If the password convert flag is set we need to convert it - if ($row['user_pass_convert']) - { - // enable super globals to get literal value - // this is needed to prevent unicode normalization - $super_globals_disabled = $this->request->super_globals_disabled(); - if ($super_globals_disabled) - { - $this->request->enable_super_globals(); - } - - // in phpBB2 passwords were used exactly as they were sent, with addslashes applied - $password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : ''; - $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format; - $password_new_format = $this->request->variable('password', '', true); - - if ($super_globals_disabled) - { - $this->request->disable_super_globals(); - } - - if ($password == $password_new_format) - { - if (!function_exists('utf8_to_cp1252')) - { - include($this->phpbb_root_path . 'includes/utf/data/recode_basic.' . $this->php_ext); - } - - // cp1252 is phpBB2's default encoding, characters outside ASCII range might work when converted into that encoding - // plain md5 support left in for conversions from other systems. - if ((strlen($row['user_password']) == 34 && ($this->passwords_manager->check(md5($password_old_format), $row['user_password']) || $this->passwords_manager->check(md5(utf8_to_cp1252($password_old_format)), $row['user_password']))) - || (strlen($row['user_password']) == 32 && (md5($password_old_format) == $row['user_password'] || md5(utf8_to_cp1252($password_old_format)) == $row['user_password']))) - { - $hash = $this->passwords_manager->hash($password_new_format); - - // Update the password in the users table to the new format and remove user_pass_convert flag - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_password = \'' . $this->db->sql_escape($hash) . '\', - user_pass_convert = 0 - WHERE user_id = ' . $row['user_id']; - $this->db->sql_query($sql); - - $row['user_pass_convert'] = 0; - $row['user_password'] = $hash; - } - else - { - // Although we weren't able to convert this password we have to - // increase login attempt count to make sure this cannot be exploited - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = user_login_attempts + 1 - WHERE user_id = ' . (int) $row['user_id'] . ' - AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; - $this->db->sql_query($sql); - - return array( - 'status' => LOGIN_ERROR_PASSWORD_CONVERT, - 'error_msg' => 'LOGIN_ERROR_PASSWORD_CONVERT', - 'user_row' => $row, - ); - } - } - } - // Check password ... - if (!$row['user_pass_convert'] && $this->passwords_manager->check($password, $row['user_password'])) + if ($this->passwords_manager->check($password, $row['user_password'])) { // Check for old password hash... if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32) @@ -244,8 +180,7 @@ class db extends \phpbb\auth\provider\base // Update the password in the users table to the new format $sql = 'UPDATE ' . USERS_TABLE . " - SET user_password = '" . $this->db->sql_escape($hash) . "', - user_pass_convert = 0 + SET user_password = '" . $this->db->sql_escape($hash) . "' WHERE user_id = {$row['user_id']}"; $this->db->sql_query($sql); diff --git a/phpBB/phpbb/auth/provider/oauth/oauth.php b/phpBB/phpbb/auth/provider/oauth/oauth.php index 2230ce15d1..07430bb42a 100644 --- a/phpBB/phpbb/auth/provider/oauth/oauth.php +++ b/phpBB/phpbb/auth/provider/oauth/oauth.php @@ -215,7 +215,7 @@ class oauth extends \phpbb\auth\provider\base } // Retrieve the user's account - $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts + $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts FROM ' . $this->users_table . ' WHERE user_id = ' . (int) $row['user_id']; $result = $this->db->sql_query($sql); diff --git a/phpBB/phpbb/auth/provider_collection.php b/phpBB/phpbb/auth/provider_collection.php new file mode 100644 index 0000000000..27a3f24564 --- /dev/null +++ b/phpBB/phpbb/auth/provider_collection.php @@ -0,0 +1,65 @@ +<?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\auth; + +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** +* Collection of auth providers to be configured at container compile time. +*/ +class provider_collection extends \phpbb\di\service_collection +{ + /** @var \phpbb\config\config phpBB Config */ + protected $config; + + /** + * Constructor + * + * @param ContainerInterface $container Container object + * @param \phpbb\config\config $config phpBB config + */ + public function __construct($container, \phpbb\config\config $config) + { + $this->container = $container; + $this->config = $config; + } + + /** + * Get an auth provider. + * + * @return object Default auth provider selected in config if it + * does exist. Otherwise the standard db auth + * provider. + * @throws \RuntimeException If neither the auth provider that + * is specified by the phpBB config nor the db + * auth provider exist. The db auth provider + * should always exist in a phpBB installation. + */ + public function get_provider() + { + if ($this->offsetExists('auth.provider.' . basename(trim($this->config['auth_method'])))) + { + return $this->offsetGet('auth.provider.' . basename(trim($this->config['auth_method']))); + } + // Revert to db auth provider if selected method does not exist + elseif ($this->offsetExists('auth.provider.db')) + { + return $this->offsetGet('auth.provider.db'); + } + else + { + throw new \RuntimeException(sprintf('The authentication provider for the authentication method "%1$s" does not exist. It was not possible to recover from this by reverting to the database authentication provider.', $this->config['auth_method'])); + } + } +} diff --git a/phpBB/phpbb/avatar/driver/gravatar.php b/phpBB/phpbb/avatar/driver/gravatar.php index 34b894c2a7..c4344ee6e8 100644 --- a/phpBB/phpbb/avatar/driver/gravatar.php +++ b/phpBB/phpbb/avatar/driver/gravatar.php @@ -81,7 +81,8 @@ class gravatar extends \phpbb\avatar\driver\driver array( 'email' => array( array('string', false, 6, 60), - array('email')) + array('email'), + ), ) ); diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php index 00e519e3f2..f3acf7cb2c 100644 --- a/phpBB/phpbb/avatar/driver/local.php +++ b/phpBB/phpbb/avatar/driver/local.php @@ -36,7 +36,7 @@ class local extends \phpbb\avatar\driver\driver public function prepare_form($request, $template, $user, $row, &$error) { $avatar_list = $this->get_avatar_list($user); - $category = $request->variable('avatar_local_cat', ''); + $category = $request->variable('avatar_local_cat', key($avatar_list)); foreach ($avatar_list as $cat => $null) { @@ -131,7 +131,7 @@ class local extends \phpbb\avatar\driver\driver } return array( - 'avatar' => ($category != $user->lang['MAIN']) ? $category . '/' . $file : $file, + 'avatar' => ($category != $user->lang['NO_AVATAR_CATEGORY']) ? $category . '/' . $file : $file, 'avatar_width' => $avatar_list[$category][urldecode($file)]['width'], 'avatar_height' => $avatar_list[$category][urldecode($file)]['height'], ); @@ -179,9 +179,9 @@ class local extends \phpbb\avatar\driver\driver { $dims = array(0, 0); } - $cat = ($path == $file_path) ? $user->lang['MAIN'] : str_replace("$path/", '', $file_path); + $cat = ($path == $file_path) ? $user->lang['NO_AVATAR_CATEGORY'] : str_replace("$path/", '', $file_path); $avatar_list[$cat][$image] = array( - 'file' => ($cat != $user->lang['MAIN']) ? rawurlencode($cat) . '/' . rawurlencode($image) : rawurlencode($image), + 'file' => ($cat != $user->lang['NO_AVATAR_CATEGORY']) ? rawurlencode($cat) . '/' . rawurlencode($image) : rawurlencode($image), 'filename' => rawurlencode($image), 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $image))), 'width' => $dims[0], diff --git a/phpBB/phpbb/config/config.php b/phpBB/phpbb/config/config.php index 8cbe1e1e2d..aaad333006 100644 --- a/phpBB/phpbb/config/config.php +++ b/phpBB/phpbb/config/config.php @@ -37,7 +37,7 @@ class config implements \ArrayAccess, \IteratorAggregate, \Countable /** * Retrieves an ArrayIterator over the configuration values. * - * @return ArrayIterator An iterator over all config data + * @return \ArrayIterator An iterator over all config data */ public function getIterator() { diff --git a/phpBB/phpbb/console/application.php b/phpBB/phpbb/console/application.php index da2bfbb49a..b1f0635913 100644 --- a/phpBB/phpbb/console/application.php +++ b/phpBB/phpbb/console/application.php @@ -13,15 +13,93 @@ namespace phpbb\console; +use Symfony\Component\Console\Shell; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\DependencyInjection\TaggedContainerInterface; class application extends \Symfony\Component\Console\Application { - function register_container_commands(TaggedContainerInterface $container, $tag = 'console.command') + /** + * @var bool Indicates whether or not we are in a shell + */ + protected $in_shell = false; + + /** + * @var \phpbb\user User object + */ + protected $user; + + /** + * @param string $name The name of the application + * @param string $version The version of the application + * @param \phpbb\user $user The user which runs the application (used for translation) + */ + public function __construct($name, $version, \phpbb\user $user) + { + parent::__construct($name, $version); + + $this->user = $user; + } + + /** + * Gets the help message. + * + * It's a hack of the default help message to display the --shell + * option only for the application and not for all the commands. + * + * @return string A help message. + */ + public function getHelp() + { + // If we are already in a shell + // we do not want to have the --shell option available + if ($this->in_shell) + { + return parent::getHelp(); + } + + $this->getDefinition()->addOption(new InputOption( + '--shell', + '-s', + InputOption::VALUE_NONE, + $this->user->lang('CLI_DESCRIPTION_OPTION_SHELL') + )); + + return parent::getHelp(); + } + + /** + * Register a set of commands from the container + * + * @param TaggedContainerInterface $container The container + * @param string $tag The tag used to register the commands + */ + public function register_container_commands(TaggedContainerInterface $container, $tag = 'console.command') { foreach($container->findTaggedServiceIds($tag) as $id => $void) { $this->add($container->get($id)); } } + + /** + * {@inheritdoc} + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + // Run a shell if the --shell (or -s) option is set and if no command name is specified + // Also, we do not want to have the --shell option available if we are already in a shell + if (!$this->in_shell && $this->getCommandName($input) === null && $input->hasParameterOption(array('--shell', '-s'))) + { + $shell = new Shell($this); + $this->in_shell = true; + $shell->run(); + + return 0; + } + + return parent::doRun($input, $output); + } } diff --git a/phpBB/phpbb/console/command/cache/purge.php b/phpBB/phpbb/console/command/cache/purge.php index 1e2adaeb4d..50953185a4 100644 --- a/phpBB/phpbb/console/command/cache/purge.php +++ b/phpBB/phpbb/console/command/cache/purge.php @@ -43,7 +43,6 @@ class purge extends \phpbb\console\command\command $this->log = $log; $this->user = $user; $this->config = $config; - $this->user->add_lang(array('acp/common')); parent::__construct(); } diff --git a/phpBB/phpbb/console/command/cron/cron_list.php b/phpBB/phpbb/console/command/cron/cron_list.php new file mode 100644 index 0000000000..9db6a23947 --- /dev/null +++ b/phpBB/phpbb/console/command/cron/cron_list.php @@ -0,0 +1,90 @@ +<?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\console\command\cron; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class cron_list extends \phpbb\console\command\command +{ + /** @var \phpbb\cron\manager */ + protected $cron_manager; + + /** @var \phpbb\user */ + protected $user; + + public function __construct(\phpbb\cron\manager $cron_manager, \phpbb\user $user) + { + $this->cron_manager = $cron_manager; + $this->user = $user; + parent::__construct(); + } + + protected function configure() + { + $this + ->setName('cron:list') + ->setDescription($this->user->lang('CLI_DESCRIPTION_CRON_LIST')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $tasks = $this->cron_manager->get_tasks(); + + if (empty($tasks)) + { + $output->writeln($this->user->lang('CRON_NO_TASKS')); + return; + } + + $ready_tasks = array(); + $not_ready_tasks = array(); + foreach ($tasks as $task) + { + if ($task->is_ready()) + { + $ready_tasks[] = $task; + } + else + { + $not_ready_tasks[] = $task; + } + } + + if (!empty($ready_tasks)) + { + $output->writeln('<info>' . $this->user->lang('TASKS_READY') . '</info>'); + $this->print_tasks_names($ready_tasks, $output); + } + + if (!empty($ready_tasks) && !empty($not_ready_tasks)) + { + $output->writeln(''); + } + + if (!empty($not_ready_tasks)) + { + $output->writeln('<info>' . $this->user->lang('TASKS_NOT_READY') . '</info>'); + $this->print_tasks_names($not_ready_tasks, $output); + } + } + + protected function print_tasks_names(array $tasks, OutputInterface $output) + { + foreach ($tasks as $task) + { + $output->writeln($task->get_name()); + } + } +} diff --git a/phpBB/phpbb/console/command/db/migrate.php b/phpBB/phpbb/console/command/db/migrate.php index 0f74664095..2abeaf5268 100644 --- a/phpBB/phpbb/console/command/db/migrate.php +++ b/phpBB/phpbb/console/command/db/migrate.php @@ -43,7 +43,7 @@ class migrate extends \phpbb\console\command\command $this->cache = $cache; $this->log = $log; $this->user = $user; - $this->user->add_lang(array('common', 'acp/common', 'install', 'migrator')); + $this->user->add_lang(array('common', 'install', 'migrator')); parent::__construct(); } diff --git a/phpBB/phpbb/console/command/dev/migration_tips.php b/phpBB/phpbb/console/command/dev/migration_tips.php new file mode 100644 index 0000000000..c2f61568ea --- /dev/null +++ b/phpBB/phpbb/console/command/dev/migration_tips.php @@ -0,0 +1,64 @@ +<?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\console\command\dev; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class migration_tips extends \phpbb\console\command\command +{ + /** @var \phpbb\extension\manager */ + protected $extension_manager; + + function __construct(\phpbb\extension\manager $extension_manager) + { + $this->extension_manager = $extension_manager; + parent::__construct(); + } + + protected function configure() + { + $this + ->setName('dev:migration-tips') + ->setDescription('Finds migrations that are not depended on.') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $migrations = $this->extension_manager->get_finder() + ->set_extensions(array()) + ->core_path('phpbb/db/migration/data/') + ->get_classes(); + $tips = $migrations; + + foreach ($migrations as $migration_class) + { + foreach ($migration_class::depends_on() as $dependency) + { + $tips_key = array_search($dependency, $tips); + if ($tips_key !== false) + { + unset($tips[$tips_key]); + } + } + } + + $output->writeln("\t\tarray("); + foreach ($tips as $migration) + { + $output->writeln("\t\t\t'{$migration}',"); + } + $output->writeln("\t\t);"); + } +} diff --git a/phpBB/phpbb/controller/provider.php b/phpBB/phpbb/controller/provider.php index 91f3a07fb1..bd85385a41 100644 --- a/phpBB/phpbb/controller/provider.php +++ b/phpBB/phpbb/controller/provider.php @@ -46,10 +46,10 @@ class provider } /** - * @param \phpbb\extension\finder $finder + * @param \phpbb\finder $finder * @return null */ - public function find_routing_files(\phpbb\extension\finder $finder) + public function find_routing_files(\phpbb\finder $finder) { // We hardcode the path to the core config directory // because the finder cannot find it diff --git a/phpBB/phpbb/cron/manager.php b/phpBB/phpbb/cron/manager.php index 1eb8edf033..f04f063228 100644 --- a/phpBB/phpbb/cron/manager.php +++ b/phpBB/phpbb/cron/manager.php @@ -122,6 +122,16 @@ class manager } /** + * Find all tasks and return them. + * + * @return array List of all tasks. + */ + public function get_tasks() + { + return $this->tasks; + } + + /** * Wraps a task inside an instance of \phpbb\cron\task\wrapper. * * @param \phpbb\cron\task\task $task The task. diff --git a/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php b/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php new file mode 100644 index 0000000000..bd682e2f7c --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php @@ -0,0 +1,27 @@ +<?php +/** +* +* @package migration +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\db\migration\data\v310; + +class contact_admin_acp_module extends \phpbb\db\migration\migration +{ + public function update_data() + { + return array( + array('module.add', array( + 'acp', + 'ACP_BOARD_CONFIGURATION', + array( + 'module_basename' => 'acp_contact', + 'modes' => array('contact'), + ), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php b/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php new file mode 100644 index 0000000000..e255efb99d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php @@ -0,0 +1,37 @@ +<?php +/** +* +* @package migration +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\db\migration\data\v310; + +class contact_admin_form extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return isset($this->config['contact_admin_form_enable']); + } + + public function update_data() + { + return array( + array('config.add', array('contact_admin_form_enable', 1)), + array('custom', array(array($this, 'contact_admin_info'))), + ); + } + + public function contact_admin_info() + { + $text_config = new \phpbb\config\db_text($this->db, $this->table_prefix . 'config_text'); + $text_config->set_array(array( + 'contact_admin_info' => '', + 'contact_admin_info_uid' => '', + 'contact_admin_info_bitfield' => '', + 'contact_admin_info_flags' => OPTION_FLAG_BBCODE + OPTION_FLAG_SMILIES + OPTION_FLAG_LINKS, + )); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/passwords_convert_p1.php b/phpBB/phpbb/db/migration/data/v310/passwords_convert_p1.php new file mode 100644 index 0000000000..004d94d8bd --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/passwords_convert_p1.php @@ -0,0 +1,85 @@ +<?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\v310; + +class passwords_convert_p1 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\passwords_p2'); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'update_passwords'))), + ); + } + + public function update_passwords($start) + { + // Nothing to do if user_pass_convert column doesn't exist + if (!$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_pass_convert')) + { + return; + } + + $start = (int) $start; + $limit = 1000; + $converted_users = 0; + + $sql = 'SELECT user_password, user_id + FROM ' . $this->table_prefix . 'users + WHERE user_pass_convert = 1 + GROUP BY user_id + ORDER BY user_id'; + $result = $this->db->sql_query_limit($sql, $limit, $start); + + $update_users = array(); + while ($row = $this->db->sql_fetchrow($result)) + { + $converted_users++; + + $user_id = (int) $row['user_id']; + // Only prefix passwords without proper prefix + if (!isset($update_users[$user_id]) && !preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $row['user_password'])) + { + // Use $CP$ prefix for passwords that need to + // be converted and set pass convert to false. + $update_users[$user_id] = array( + 'user_password' => '$CP$' . $row['user_password'], + 'user_pass_convert' => 0, + ); + } + } + $this->db->sql_freeresult($result); + + foreach ($update_users as $user_id => $user_data) + { + $sql = 'UPDATE ' . $this->table_prefix . 'users + SET ' . $this->db->sql_build_array('UPDATE', $user_data) . ' + WHERE user_id = ' . $user_id; + $this->sql_query($sql); + } + + if ($converted_users < $limit) + { + // There are no more users to be converted + return; + } + + // There are still more users to query, return the next start value + return $start + $limit; + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/passwords_convert_p2.php b/phpBB/phpbb/db/migration/data/v310/passwords_convert_p2.php new file mode 100644 index 0000000000..26a99184a6 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/passwords_convert_p2.php @@ -0,0 +1,49 @@ +<?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\v310; + +class passwords_convert_p2 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_pass_convert'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\passwords_convert_p1'); + } + + public function update_schema() + { + return array( + 'drop_columns' => array( + $this->table_prefix . 'users' => array( + 'user_pass_convert', + ), + ), + ); + } + + public function revert_schema() + { + return array( + 'add_columns' => array( + $this->table_prefix . 'users' => array( + 'user_pass_convert' => array('BOOL', 0, 'after' => 'user_passchg'), + ), + ), + ); + } +} diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index 9b9532a7ad..5255c73c1c 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -714,7 +714,7 @@ class migrator /** * Load migration data files from a directory * - * @param \phpbb\extension\finder $finder + * @param \phpbb\finder $finder * @param string $path Path to migration data files * @param bool $check_fulfillable If TRUE (default), we will check * if all of the migrations are fulfillable after loading them. @@ -723,7 +723,7 @@ class migrator * with the last call to prevent throwing errors unnecessarily). * @return array Array of migration names */ - public function load_migrations(\phpbb\extension\finder $finder, $path, $check_fulfillable = true) + public function load_migrations(\phpbb\finder $finder, $path, $check_fulfillable = true) { if (!is_dir($path)) { diff --git a/phpBB/phpbb/extension/base.php b/phpBB/phpbb/extension/base.php index eb306aeb72..cbbd7bc622 100644 --- a/phpBB/phpbb/extension/base.php +++ b/phpBB/phpbb/extension/base.php @@ -23,7 +23,7 @@ class base implements \phpbb\extension\extension_interface /** @var ContainerInterface */ protected $container; - /** @var \phpbb\extension\finder */ + /** @var \phpbb\finder */ protected $finder; /** @var \phpbb\db\migrator */ @@ -39,11 +39,11 @@ class base implements \phpbb\extension\extension_interface * Constructor * * @param ContainerInterface $container Container object - * @param \phpbb\extension\finder $extension_finder + * @param \phpbb\finder $extension_finder * @param string $extension_name Name of this extension (from ext.manager) * @param string $extension_path Relative path to this extension */ - public function __construct(ContainerInterface $container, \phpbb\extension\finder $extension_finder, \phpbb\db\migrator $migrator, $extension_name, $extension_path) + public function __construct(ContainerInterface $container, \phpbb\finder $extension_finder, \phpbb\db\migrator $migrator, $extension_name, $extension_path) { $this->container = $container; $this->extension_finder = $extension_finder; diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php index cd7289e085..b83bb1b189 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -532,12 +532,22 @@ class manager } /** - * Instantiates a \phpbb\extension\finder. + * Instantiates a \phpbb\finder. * - * @return \phpbb\extension\finder An extension finder instance + * @param bool $use_all_available Should we load all extensions, or just enabled ones + * @return \phpbb\finder An extension finder instance */ - public function get_finder() + public function get_finder($use_all_available = false) { - return new \phpbb\extension\finder($this, $this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder'); + $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder'); + if ($use_all_available) + { + $finder->set_extensions(array_keys($this->all_available())); + } + else + { + $finder->set_extensions(array_keys($this->all_enabled())); + } + return $finder; } } diff --git a/phpBB/phpbb/extension/finder.php b/phpBB/phpbb/finder.php index 6f2408094e..28f28825ba 100644 --- a/phpBB/phpbb/extension/finder.php +++ b/phpBB/phpbb/finder.php @@ -11,14 +11,14 @@ * */ -namespace phpbb\extension; +namespace phpbb; /** -* The extension finder provides a simple way to locate files in active extensions +* The finder provides a simple way to locate files in the core and a set of extensions */ class finder { - protected $extension_manager; + protected $extensions; protected $filesystem; protected $phpbb_root_path; protected $cache; @@ -48,9 +48,6 @@ class finder /** * Creates a new finder instance with its dependencies * - * @param \phpbb\extension\manager $extension_manager An extension manager - * instance that provides the finder with a list of active - * extensions and their locations * @param \phpbb\filesystem $filesystem Filesystem instance * @param string $phpbb_root_path Path to the phpbb root directory * @param \phpbb\cache\driver\driver_interface $cache A cache instance or null @@ -58,9 +55,8 @@ class finder * @param string $cache_name The name of the cache variable, defaults to * _ext_finder */ - public function __construct(\phpbb\extension\manager $extension_manager, \phpbb\filesystem $filesystem, $phpbb_root_path = '', \phpbb\cache\driver\driver_interface $cache = null, $php_ext = 'php', $cache_name = '_ext_finder') + public function __construct(\phpbb\filesystem $filesystem, $phpbb_root_path = '', \phpbb\cache\driver\driver_interface $cache = null, $php_ext = 'php', $cache_name = '_ext_finder') { - $this->extension_manager = $extension_manager; $this->filesystem = $filesystem; $this->phpbb_root_path = $phpbb_root_path; $this->cache = $cache; @@ -76,15 +72,37 @@ class finder 'extension_prefix' => false, 'extension_directory' => false, ); + $this->extensions = array(); $this->cached_queries = ($this->cache) ? $this->cache->get($this->cache_name) : false; } /** + * Set the array of extensions + * + * @param array $extensions A list of extensions that should be searched aswell + * @param bool $replace_list Should the list be emptied before adding the extensions + * @return \phpbb\finder This object for chaining calls + */ + public function set_extensions(array $extensions, $replace_list = true) + { + if ($replace_list) + { + $this->extensions = array(); + } + + foreach ($extensions as $ext_name) + { + $this->extensions[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; + } + return $this; + } + + /** * Sets a core path to be searched in addition to extensions * * @param string $core_path The path relative to phpbb_root_path - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function core_path($core_path) { @@ -100,7 +118,7 @@ class finder * file extension is automatically added to suffixes. * * @param string $suffix A filename suffix - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function suffix($suffix) { @@ -117,7 +135,7 @@ class finder * file extension is automatically added to suffixes. * * @param string $extension_suffix A filename suffix - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function extension_suffix($extension_suffix) { @@ -133,7 +151,7 @@ class finder * file extension is automatically added to suffixes. * * @param string $core_suffix A filename suffix - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function core_suffix($core_suffix) { @@ -145,7 +163,7 @@ class finder * Sets the prefix all files found in extensions and core must match * * @param string $prefix A filename prefix - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function prefix($prefix) { @@ -158,7 +176,7 @@ class finder * Sets a prefix all files found in extensions must match * * @param string $extension_prefix A filename prefix - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function extension_prefix($extension_prefix) { @@ -170,7 +188,7 @@ class finder * Sets a prefix all files found in the core path must match * * @param string $core_prefix A filename prefix - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function core_prefix($core_prefix) { @@ -185,7 +203,7 @@ class finder * the current directory. * * @param string $directory - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function directory($directory) { @@ -198,7 +216,7 @@ class finder * Sets a directory all files found in extensions must be contained in * * @param string $extension_directory - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function extension_directory($extension_directory) { @@ -210,7 +228,7 @@ class finder * Sets a directory all files found in the core path must be contained in * * @param string $core_directory - * @return \phpbb\extension\finder This object for chaining calls + * @return \phpbb\finder This object for chaining calls */ public function core_directory($core_directory) { @@ -246,16 +264,14 @@ class finder * phpBB naming rules an incorrect class name will be returned. * * @param bool $cache Whether the result should be cached - * @param bool $use_all_available Use all available instead of just all - * enabled extensions * @return array An array of found class names */ - public function get_classes($cache = true, $use_all_available = false) + public function get_classes($cache = true) { $this->query['extension_suffix'] .= '.' . $this->php_ext; $this->query['core_suffix'] .= '.' . $this->php_ext; - $files = $this->find($cache, false, $use_all_available); + $files = $this->find($cache, false); return $this->get_classes_from_files($files); } @@ -290,27 +306,23 @@ class finder * Finds all directories matching the configured options * * @param bool $cache Whether the result should be cached - * @param bool $use_all_available Use all available instead of just all - * enabled extensions * @param bool $extension_keys Whether the result should have extension name as array key * @return array An array of paths to found directories */ - public function get_directories($cache = true, $use_all_available = false, $extension_keys = false) + public function get_directories($cache = true, $extension_keys = false) { - return $this->find_with_root_path($cache, true, $use_all_available, $extension_keys); + return $this->find_with_root_path($cache, true, $extension_keys); } /** * Finds all files matching the configured options. * * @param bool $cache Whether the result should be cached - * @param bool $use_all_available Use all available instead of just all - * enabled extensions * @return array An array of paths to found files */ - public function get_files($cache = true, $use_all_available = false) + public function get_files($cache = true) { - return $this->find_with_root_path($cache, false, $use_all_available); + return $this->find_with_root_path($cache, false); } /** @@ -318,16 +330,14 @@ class finder * * @param bool $cache Whether the result should be cached * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @param bool $use_all_available Use all available instead of just all - * enabled extensions + * otherwise * @param bool $extension_keys If true, result will be associative array * with extension name as key * @return array An array of paths to found items */ - protected function find_with_root_path($cache = true, $is_dir = false, $use_all_available = false, $extension_keys = false) + protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false) { - $items = $this->find($cache, $is_dir, $use_all_available); + $items = $this->find($cache, $is_dir); $result = array(); foreach ($items as $item => $ext_name) @@ -351,21 +361,11 @@ class finder * @param bool $cache Whether the result should be cached * @param bool $is_dir Directories will be returned when true, only files * otherwise - * @param bool $use_all_available Use all available instead of just all - * enabled extensions * @return array An array of paths to found items */ - public function find($cache = true, $is_dir = false, $use_all_available = false) + public function find($cache = true, $is_dir = false) { - if ($use_all_available) - { - $extensions = $this->extension_manager->all_available(); - } - else - { - $extensions = $this->extension_manager->all_enabled(); - } - + $extensions = $this->extensions; if ($this->query['core_path']) { $extensions['/'] = $this->phpbb_root_path . $this->query['core_path']; diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php index 453cb740bb..10efe5fd1c 100644 --- a/phpBB/phpbb/log/log.php +++ b/phpBB/phpbb/log/log.php @@ -391,28 +391,29 @@ class log implements \phpbb\log\log_interface } $sql_where = 'WHERE log_type = ' . $log_type; + + if (isset($conditions['keywords'])) + { + $sql_where .= $this->generate_sql_keyword($conditions['keywords'], ''); + + unset($conditions['keywords']); + } + foreach ($conditions as $field => $field_value) { $sql_where .= ' AND '; - if ($field == 'keywords') + if (is_array($field_value) && sizeof($field_value) == 2 && !is_array($field_value[1])) + { + $sql_where .= $field . ' ' . $field_value[0] . ' ' . $field_value[1]; + } + else if (is_array($field_value) && isset($field_value['IN']) && is_array($field_value['IN'])) { - $sql_where .= $this->generate_sql_keyword($field_value, '', ''); + $sql_where .= $this->db->sql_in_set($field, $field_value['IN']); } else { - if (is_array($field_value) && sizeof($field_value) == 2 && !is_array($field_value[1])) - { - $sql_where .= $field . ' ' . $field_value[0] . ' ' . $field_value[1]; - } - else if (is_array($field_value) && isset($field_value['IN']) && is_array($field_value['IN'])) - { - $sql_where .= $this->db->sql_in_set($field, $field_value['IN']); - } - else - { - $sql_where .= $field . ' = ' . $field_value; - } + $sql_where .= $field . ' = ' . $field_value; } } @@ -781,7 +782,7 @@ class log implements \phpbb\log\log_interface } } - $sql_keywords = $statement_operator . ' ('; + $sql_keywords = ' ' . $statement_operator . ' ('; if (!empty($operations)) { $sql_keywords .= $this->db->sql_in_set($table_alias . 'log_operation', $operations) . ' OR '; diff --git a/phpBB/phpbb/message/admin_form.php b/phpBB/phpbb/message/admin_form.php new file mode 100644 index 0000000000..b71b3fc535 --- /dev/null +++ b/phpBB/phpbb/message/admin_form.php @@ -0,0 +1,189 @@ +<?php +/** +* +* @package message +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\message; + +/** +* Class admin_form +* Displays a message to the user and allows him to send an email +* +* @package phpbb\message +*/ +class admin_form extends form +{ + /** @var \phpbb\config\db_text */ + protected $config_text; + + /** @var string */ + protected $subject; + /** @var string */ + protected $sender_name; + /** @var string */ + protected $sender_address; + + /** + * Construct + * + * @param \phpbb\auth\auth $auth + * @param \phpbb\config\config $config + * @param \phpbb\config\db_text $config_text + * @param \phpbb\db\driver\driver_interface $db + * @param \phpbb\user $user + * @param string $phpbb_root_path + * @param string $phpEx + */ + public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\config\db_text $config_text, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $phpEx) + { + parent::__construct($auth, $config, $db, $user, $phpbb_root_path, $phpEx); + $this->config_text = $config_text; + } + + /** + * {inheritDoc} + */ + public function check_allow() + { + $error = parent::check_allow(); + if ($error) + { + return $error; + } + + if (!$this->config['contact_admin_form_enable']) + { + return 'NO_CONTACT_PAGE'; + } + + return false; + } + + /** + * {inheritDoc} + */ + public function bind(\phpbb\request\request_interface $request) + { + parent::bind($request); + + $this->subject = $request->variable('subject', '', true); + $this->sender_address = $request->variable('email', ''); + $this->sender_name = $request->variable('name', '', true); + } + + /** + * {inheritDoc} + */ + public function submit(\messenger $messenger) + { + if (!$this->subject) + { + $this->errors[] = $this->user->lang['EMPTY_SUBJECT_EMAIL']; + } + if (!$this->body) + { + $this->errors[] = $this->user->lang['EMPTY_MESSAGE_EMAIL']; + } + + if ($this->user->data['is_registered']) + { + $this->message->set_sender_from_user($this->user); + $this->sender_name = $this->user->data['username']; + $this->sender_address = $this->user->data['user_email']; + } + else + { + if (!$this->sender_name) + { + $this->errors[] = $this->user->lang['EMPTY_SENDER_NAME']; + } + + if (!function_exists('validate_data')) + { + require($this->phpbb_root_path . 'includes/functions_user.' . $this->phpEx); + } + + $validate_array = validate_data( + array( + 'email' => $this->sender_address, + ), + array( + 'email' => array( + array('string', false, 6, 60), + array('email'), + ), + ) + ); + + foreach ($validate_array as $error) + { + $this->errors[] = $this->user->lang[$error]; + } + + $this->message->set_sender($this->user->ip, $this->sender_name, $this->sender_address, $this->user->lang_name); + $this->message->set_sender_notify_type(NOTIFY_EMAIL); + } + + $this->message->set_template('contact_admin'); + $this->message->set_subject($this->subject); + $this->message->set_body($this->body); + $this->message->add_recipient( + $this->user->lang['ADMINISTRATOR'], + $this->config['board_contact'], + $this->config['default_lang'], + NOTIFY_EMAIL + ); + + $this->message->set_template_vars(array( + 'FROM_EMAIL_ADDRESS' => $this->sender_address, + 'FROM_IP_ADDRESS' => $this->user->ip, + 'S_IS_REGISTERED' => $this->user->data['is_registered'], + + 'U_FROM_PROFILE' => generate_board_url() . '/memberlist.' . $this->phpEx . '?mode=viewprofile&u=' . $this->user->data['user_id'], + )); + + parent::submit($messenger); + } + + /** + * {inheritDoc} + */ + public function render(\phpbb\template\template $template) + { + $l_admin_info = $this->config_text->get('contact_admin_info'); + if ($l_admin_info) + { + $contact_admin_data = $this->config_text->get_array(array( + 'contact_admin_info', + 'contact_admin_info_uid', + 'contact_admin_info_bitfield', + 'contact_admin_info_flags', + )); + + $l_admin_info = generate_text_for_display( + $contact_admin_data['contact_admin_info'], + $contact_admin_data['contact_admin_info_uid'], + $contact_admin_data['contact_admin_info_bitfield'], + $contact_admin_data['contact_admin_info_flags'] + ); + } + + $template->assign_vars(array( + 'S_CONTACT_ADMIN' => true, + 'S_CONTACT_FORM' => $this->config['contact_admin_form_enable'], + 'S_IS_REGISTERED' => $this->user->data['is_registered'], + + 'CONTACT_INFO' => $l_admin_info, + 'MESSAGE' => $this->body, + 'SUBJECT' => $this->subject, + 'NAME' => $this->sender_name, + 'EMAIL' => $this->sender_address, + )); + + parent::render($template); + } +} diff --git a/phpBB/phpbb/message/form.php b/phpBB/phpbb/message/form.php new file mode 100644 index 0000000000..d7a42c4080 --- /dev/null +++ b/phpBB/phpbb/message/form.php @@ -0,0 +1,173 @@ +<?php +/** +* +* @package message +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\message; + +/** +* Abstract class form +* +* @package phpbb\message +*/ +abstract class form +{ + /** @var \phpbb\auth\auth */ + protected $auth; + /** @var \phpbb\config\config */ + protected $config; + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + /** @var \phpbb\message\message */ + protected $message; + /** @var \phpbb\user */ + protected $user; + + /** @var string */ + protected $phpbb_root_path; + /** @var string */ + protected $phpEx; + + /** @var array */ + protected $errors = array(); + /** @var bool */ + protected $cc_sender; + /** @var string */ + protected $body; + + /** + * Construct + * + * @param \phpbb\auth\auth $auth + * @param \phpbb\config\config $config + * @param \phpbb\db\driver\driver_interface $db + * @param \phpbb\user $user + * @param string $phpbb_root_path + * @param string $phpEx + */ + public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $phpEx) + { + $this->phpbb_root_path = $phpbb_root_path; + $this->phpEx = $phpEx; + $this->user = $user; + $this->auth = $auth; + $this->config = $config; + $this->db = $db; + + $this->message = new message($config['server_name']); + $this->message->set_sender_from_user($this->user); + } + + /** + * Returns the title for the email form page + * + * @return string + */ + public function get_page_title() + { + return $this->user->lang['SEND_EMAIL']; + } + + /** + * Returns the file name of the form template + * + * @return string + */ + public function get_template_file() + { + return 'memberlist_email.html'; + } + + /** + * Checks whether the user is allowed to use the form + * + * @return false|string Error string if not allowed, false otherwise + */ + public function check_allow() + { + if (!$this->config['email_enable']) + { + return 'EMAIL_DISABLED'; + } + + if (time() - $this->user->data['user_emailtime'] < $this->config['flood_interval']) + { + return 'FLOOD_EMAIL_LIMIT'; + } + + return false; + } + + /** + * Get the return link after the message has been sent + * + * @return string + */ + public function get_return_message() + { + return sprintf($this->user->lang['RETURN_INDEX'], '<a href="' . append_sid($this->phpbb_root_path . 'index.' . $this->phpEx) . '">', '</a>'); + } + + /** + * Bind the values of the request to the form + * + * @param \phpbb\request\request_interface $request + * @return null + */ + public function bind(\phpbb\request\request_interface $request) + { + $this->cc_sender = $request->is_set_post('cc_sender'); + $this->body = $request->variable('message', '', true); + } + + /** + * Submit form, generate the email and send it + * + * @param \messenger $messenger + * @return null + */ + public function submit(\messenger $messenger) + { + if (!check_form_key('memberlist_email')) + { + $this->errors[] = 'FORM_INVALID'; + } + + if (!sizeof($this->errors)) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_emailtime = ' . time() . ' + WHERE user_id = ' . $this->user->data['user_id']; + $this->db->sql_query($sql); + + if ($this->cc_sender) + { + $this->message->cc_sender(); + } + + $this->message->send($messenger, phpbb_get_board_contact($this->config, $this->phpEx)); + + meta_refresh(3, append_sid($this->phpbb_root_path . 'index.' . $this->phpEx)); + trigger_error($this->user->lang['EMAIL_SENT'] . '<br /><br />' . $this->get_return_message()); + } + } + + /** + * Render the template of the form + * + * @param \phpbb\template\template $template + * @return null + */ + public function render(\phpbb\template\template $template) + { + add_form_key('memberlist_email'); + + $template->assign_vars(array( + 'ERROR_MESSAGE' => (sizeof($this->errors)) ? implode('<br />', $this->errors) : '', + )); + } +} diff --git a/phpBB/phpbb/message/message.php b/phpBB/phpbb/message/message.php new file mode 100644 index 0000000000..182995ba21 --- /dev/null +++ b/phpBB/phpbb/message/message.php @@ -0,0 +1,280 @@ +<?php +/** +* +* @package message +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\message; + +/** +* Class message +* Holds all information for an email and sends it in the end +* +* @package phpbb\message +*/ +class message +{ + /** @var string */ + protected $server_name; + + /** @var string */ + protected $subject = ''; + /** @var string */ + protected $body = ''; + /** @var string */ + protected $template = ''; + /** @var array */ + protected $template_vars = array(); + + /** @var string */ + protected $sender_ip = ''; + /** @var string */ + protected $sender_name = ''; + /** @var string */ + protected $sender_address = ''; + /** @var string */ + protected $sender_lang = ''; + /** @var string */ + protected $sender_id = ''; + /** @var string */ + protected $sender_username = ''; + /** @var string */ + protected $sender_jabber = ''; + /** @var int */ + protected $sender_notify_type = NOTIFY_EMAIL; + + /** @var array */ + protected $recipients; + + /** + * Construct + * + * @param string $server_name Used for AntiAbuse header + */ + public function __construct($server_name) + { + $this->server_name = $server_name; + } + + /** + * Set the subject of the email + * + * @param string $subject + * @return null + */ + public function set_subject($subject) + { + $this->subject = $subject; + } + + /** + * Set the body of the email text + * + * @param string $body + * @return null + */ + public function set_body($body) + { + $this->body = $body; + } + + /** + * Set the name of the email template to use + * + * @param string $template + * @return null + */ + public function set_template($template) + { + $this->template = $template; + } + + /** + * Set the array with the "template" data for the email + * + * @param array $template_vars + * @return null + */ + public function set_template_vars($template_vars) + { + $this->template_vars = $template_vars; + } + + /** + * Add a recipient from \phpbb\user + * + * @param \phpbb\user $user + * @return null + */ + public function add_recipient_from_user_row(array $user) + { + $this->add_recipient( + $user['username'], + $user['user_email'], + $user['user_lang'], + $user['user_notify_type'], + $user['username'], + $user['user_jabber'] + ); + } + + /** + * Add a recipient + * + * @param string $recipient_name Displayed sender name + * @param string $recipient_address Email address + * @param string $recipient_lang + * @param int $recipient_notify_type Used notification methods (Jabber, Email, ...) + * @param string $recipient_username User Name (used for AntiAbuse header) + * @param string $recipient_jabber + * @return null + */ + public function add_recipient($recipient_name, $recipient_address, $recipient_lang, $recipient_notify_type = NOTIFY_EMAIL, $recipient_username = '', $recipient_jabber = '') + { + $this->recipients[] = array( + 'name' => $recipient_name, + 'address' => $recipient_address, + 'lang' => $recipient_lang, + 'username' => $recipient_username, + 'jabber' => $recipient_jabber, + 'notify_type' => $recipient_notify_type, + 'to_name' => $recipient_name, + ); + } + + /** + * Set the senders data from \phpbb\user object + * + * @param \phpbb\user $user + * @return null + */ + public function set_sender_from_user($user) + { + $this->set_sender( + $user->ip, + $user->data['username'], + $user->data['user_email'], + $user->lang_name, + $user->data['user_id'], + $user->data['username'], + $user->data['user_jabber'] + ); + + $this->set_sender_notify_type($user->data['user_notify_type']); + } + + /** + * Set the senders data + * + * @param string $sender_ip + * @param string $sender_name Displayed sender name + * @param string $sender_address Email address + * @param string $sender_lang + * @param int $sender_id User ID + * @param string $sender_username User Name (used for AntiAbuse header) + * @param string $sender_jabber + * @return null + */ + public function set_sender($sender_ip, $sender_name, $sender_address, $sender_lang = '', $sender_id = 0, $sender_username = '', $sender_jabber = '') + { + $this->sender_ip = $sender_ip; + $this->sender_name = $sender_name; + $this->sender_address = $sender_address; + $this->sender_lang = $sender_lang; + $this->sender_id = $sender_id; + $this->sender_username = $sender_username; + $this->sender_jabber = $sender_jabber; + } + + /** + * Which notification type should be used? Jabber, Email, ...? + * + * @param int $sender_notify_type + * @return null + */ + public function set_sender_notify_type($sender_notify_type) + { + $this->sender_notify_type = $sender_notify_type; + } + + /** + * Ok, now the same email if CC specified, but without exposing the user's email address + * + * @return null + */ + public function cc_sender() + { + if (!sizeof($this->recipients)) + { + trigger_error('No email recipients specified'); + } + if (!$this->sender_address) + { + trigger_error('No email sender specified'); + } + + $this->recipients[] = array( + 'lang' => $this->sender_lang, + 'address' => $this->sender_address, + 'name' => $this->sender_name, + 'username' => $this->sender_username, + 'jabber' => $this->sender_jabber, + 'notify_type' => $this->sender_notify_type, + 'to_name' => $this->recipients[0]['to_name'], + ); + } + + /** + * Send the email + * + * @param \messenger $messenger + * @param string $phpEx + * @return null + */ + public function send(\messenger $messenger, $contact) + { + if (!sizeof($this->recipients)) + { + return; + } + + foreach ($this->recipients as $recipient) + { + $messenger->template($this->template, $recipient['lang']); + $messenger->replyto($this->sender_address); + $messenger->to($recipient['address'], $recipient['name']); + $messenger->im($recipient['jabber'], $recipient['username']); + + $messenger->headers('X-AntiAbuse: Board servername - ' . $this->server_name); + $messenger->headers('X-AntiAbuse: User IP - ' . $this->sender_ip); + + if ($this->sender_id) + { + $messenger->headers('X-AntiAbuse: User_id - ' . $this->sender_id); + } + if ($this->sender_username) + { + $messenger->headers('X-AntiAbuse: Username - ' . $this->sender_username); + } + + $messenger->subject(htmlspecialchars_decode($this->subject)); + + $messenger->assign_vars(array( + 'BOARD_CONTACT' => $contact, + 'TO_USERNAME' => htmlspecialchars_decode($recipient['to_name']), + 'FROM_USERNAME' => htmlspecialchars_decode($this->sender_name), + 'MESSAGE' => htmlspecialchars_decode($this->body)) + ); + + if (sizeof($this->template_vars)) + { + $messenger->assign_vars($this->template_vars); + } + + $messenger->send($recipient['notify_type']); + } + } +} diff --git a/phpBB/phpbb/message/topic_form.php b/phpBB/phpbb/message/topic_form.php new file mode 100644 index 0000000000..3a35c35d21 --- /dev/null +++ b/phpBB/phpbb/message/topic_form.php @@ -0,0 +1,156 @@ +<?php +/** +* +* @package message +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\message; + +/** +* Class topic_form +* Form used to send topics as notification emails +* +* @package phpbb\message +*/ +class topic_form extends form +{ + /** @var int */ + protected $topic_id; + /** @var array */ + protected $topic_row; + /** @var string */ + protected $recipient_address; + /** @var string */ + protected $recipient_name; + /** @var string */ + protected $recipient_lang; + + /** + * Get the data of the topic + * + * @param int $topic_id + * @return false|array false if the topic does not exist, array otherwise + */ + protected function get_topic_row($topic_id) + { + $sql = 'SELECT forum_id, topic_title + FROM ' . TOPICS_TABLE . ' + WHERE topic_id = ' . (int) $topic_id; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + return $row; + } + + /** + * {inheritDoc} + */ + public function check_allow() + { + $error = parent::check_allow(); + if ($error) + { + return $error; + } + + if (!$this->auth->acl_get('u_sendemail')) + { + return 'NO_EMAIL'; + } + + if (!$this->topic_row) + { + return 'NO_TOPIC'; + } + + if (!$this->auth->acl_get('f_read', $this->topic_row['forum_id'])) + { + return 'SORRY_AUTH_READ'; + } + + if (!$this->auth->acl_get('f_email', $this->topic_row['forum_id'])) + { + return 'NO_EMAIL'; + } + + return false; + } + + /** + * {inheritDoc} + */ + public function bind(\phpbb\request\request_interface $request) + { + parent::bind($request); + + $this->topic_id = $request->variable('t', 0); + $this->recipient_address = $request->variable('email', ''); + $this->recipient_name = $request->variable('name', '', true); + $this->recipient_lang = $request->variable('lang', $this->config['default_lang']); + + $this->topic_row = $this->get_topic_row($this->topic_id); + } + + /** + * {inheritDoc} + */ + public function submit(\messenger $messenger) + { + if (!$this->recipient_address || !preg_match('/^' . get_preg_expression('email') . '$/i', $this->recipient_address)) + { + $this->errors[] = $this->user->lang['EMPTY_ADDRESS_EMAIL']; + } + + if (!$this->recipient_name) + { + $this->errors[] = $this->user->lang['EMPTY_NAME_EMAIL']; + } + + $this->message->set_template('email_notify'); + $this->message->set_template_vars(array( + '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->add_recipient( + $this->recipient_name, + $this->recipient_address, + $this->recipient_lang, + NOTIFY_EMAIL + ); + $this->message->set_sender_notify_type(NOTIFY_EMAIL); + + parent::submit($messenger); + } + + /** + * {inheritDoc} + */ + public function get_return_message() + { + return sprintf($this->user->lang['RETURN_TOPIC'], '<a href="' . append_sid($this->phpbb_root_path . 'viewtopic.' . $this->phpEx, 'f=' . $this->topic_row['forum_id'] . '&t=' . $this->topic_id) . '">', '</a>'); + } + + /** + * {inheritDoc} + */ + public function render(\phpbb\template\template $template) + { + parent::render($template); + + $this->user->add_lang('viewtopic'); + $template->assign_vars(array( + 'EMAIL' => $this->recipient_address, + 'NAME' => $this->recipient_name, + 'S_LANG_OPTIONS' => language_select($this->recipient_lang), + 'MESSAGE' => $this->body, + + 'L_EMAIL_BODY_EXPLAIN' => $this->user->lang['EMAIL_TOPIC_EXPLAIN'], + 'S_POST_ACTION' => append_sid($this->phpbb_root_path . 'memberlist.' . $this->phpEx, 'mode=email&t=' . $this->topic_id)) + ); + } +} diff --git a/phpBB/phpbb/message/user_form.php b/phpBB/phpbb/message/user_form.php new file mode 100644 index 0000000000..7aa4b94def --- /dev/null +++ b/phpBB/phpbb/message/user_form.php @@ -0,0 +1,134 @@ +<?php +/** +* +* @package message +* @copyright (c) 2014 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +namespace phpbb\message; + +/** +* Class user_form +* Allows users to send emails to other users +* +* @package phpbb\message +*/ +class user_form extends form +{ + /** @var int */ + protected $recipient_id; + /** @var array */ + protected $recipient_row; + /** @var string */ + protected $subject; + + /** + * Get the data of the recipient + * + * @param int $user_id + * @return false|array false if the user does not exist, array otherwise + */ + protected function get_user_row($user_id) + { + $sql = 'SELECT user_id, username, user_colour, user_email, user_allow_viewemail, user_lang, user_jabber, user_notify_type + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . (int) $user_id . ' + AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + return $row; + } + + /** + * {inheritDoc} + */ + public function check_allow() + { + $error = parent::check_allow(); + if ($error) + { + return $error; + } + + if (!$this->auth->acl_get('u_sendemail')) + { + return 'NO_EMAIL'; + } + + if ($this->recipient_id == ANONYMOUS || !$this->config['board_email_form']) + { + return 'NO_EMAIL'; + } + + if (!$this->recipient_row) + { + return 'NO_USER'; + } + + // Can we send email to this user? + if (!$this->recipient_row['user_allow_viewemail'] && !$this->auth->acl_get('a_user')) + { + return 'NO_EMAIL'; + } + + return false; + } + + /** + * {inheritDoc} + */ + public function bind(\phpbb\request\request_interface $request) + { + parent::bind($request); + + $this->recipient_id = $request->variable('u', 0); + $this->subject = $request->variable('subject', '', true); + + $this->recipient_row = $this->get_user_row($this->recipient_id); + } + + /** + * {inheritDoc} + */ + public function submit(\messenger $messenger) + { + if (!$this->subject) + { + $this->errors[] = $this->user->lang['EMPTY_SUBJECT_EMAIL']; + } + + if (!$this->body) + { + $this->errors[] = $this->user->lang['EMPTY_MESSAGE_EMAIL']; + } + + $this->message->set_template('profile_send_email'); + $this->message->set_subject($this->subject); + $this->message->set_body($this->body); + $this->message->add_recipient_from_user_row($this->recipient_row); + + parent::submit($messenger); + } + + /** + * {inheritDoc} + */ + public function render(\phpbb\template\template $template) + { + parent::render($template); + + $template->assign_vars(array( + 'S_SEND_USER' => true, + 'S_POST_ACTION' => append_sid($this->phpbb_root_path . 'memberlist.' . $this->phpEx, 'mode=email&u=' . $this->recipient_id), + + 'L_SEND_EMAIL_USER' => $this->user->lang('SEND_EMAIL_USER', $this->recipient_row['username']), + 'USERNAME_FULL' => get_username_string('full', $this->recipient_row['user_id'], $this->recipient_row['username'], $this->recipient_row['user_colour']), + 'SUBJECT' => $this->subject, + 'MESSAGE' => $this->body, + )); + } +} diff --git a/phpBB/phpbb/passwords/driver/base.php b/phpBB/phpbb/passwords/driver/base.php index fffc9d1461..1d47180e55 100644 --- a/phpBB/phpbb/passwords/driver/base.php +++ b/phpBB/phpbb/passwords/driver/base.php @@ -43,4 +43,20 @@ abstract class base implements driver_interface { return true; } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return false; + } + + /** + * @inheritdoc + */ + public function get_settings_only($hash, $full = false) + { + return false; + } } diff --git a/phpBB/phpbb/passwords/driver/bcrypt.php b/phpBB/phpbb/passwords/driver/bcrypt.php index 3edf7255c0..de5840c7cf 100644 --- a/phpBB/phpbb/passwords/driver/bcrypt.php +++ b/phpBB/phpbb/passwords/driver/bcrypt.php @@ -60,7 +60,7 @@ class bcrypt extends base /** * @inheritdoc */ - public function check($password, $hash) + public function check($password, $hash, $user_row = array()) { $salt = substr($hash, 0, 29); if (strlen($salt) != 29) diff --git a/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php b/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php new file mode 100644 index 0000000000..f706c7af69 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php @@ -0,0 +1,84 @@ +<?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\passwords\driver; + +class bcrypt_wcf2 extends base +{ + const PREFIX = '$wcf2$'; + + /** @var \phpbb\passwords\driver\bcrypt */ + protected $bcrypt; + + /** @var phpbb\passwords\driver\helper */ + protected $helper; + + /** + * Constructor of passwords driver object + * + * @param \phpbb\passwords\driver\bcrypt $bcrypt Salted md5 driver + * @param \phpbb\passwords\driver\helper $helper Password driver helper + */ + public function __construct(\phpbb\passwords\driver\bcrypt $bcrypt, helper $helper) + { + $this->bcrypt = $bcrypt; + $this->helper = $helper; + } + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + if (empty($hash) || strlen($hash) != 60) + { + return false; + } + else + { + $salt = substr($hash, 0, 29); + + if (strlen($salt) != 29) + { + return false; + } + // Works for standard WCF 2.x, i.e. WBB4 and similar + return $hash === $this->bcrypt->hash($this->bcrypt->hash($password, $salt), $salt); + } + } +} diff --git a/phpBB/phpbb/passwords/driver/convert_password.php b/phpBB/phpbb/passwords/driver/convert_password.php new file mode 100644 index 0000000000..45d84f45c0 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/convert_password.php @@ -0,0 +1,43 @@ +<?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\passwords\driver; + +class convert_password extends base +{ + const PREFIX = '$CP$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + return false; + } +} diff --git a/phpBB/phpbb/passwords/driver/driver_interface.php b/phpBB/phpbb/passwords/driver/driver_interface.php index 54c9d6500e..a257e71f23 100644 --- a/phpBB/phpbb/passwords/driver/driver_interface.php +++ b/phpBB/phpbb/passwords/driver/driver_interface.php @@ -23,6 +23,13 @@ interface driver_interface public function is_supported(); /** + * Check if hash type is a legacy hash type + * + * @return bool True if it's a legacy hash type, false if not + */ + public function is_legacy(); + + /** * Returns the hash prefix * * @return string Hash prefix @@ -44,10 +51,11 @@ interface driver_interface * * @param string $password The password to check * @param string $hash The password hash to check against + * @param string $user_row User's row in users table * * @return bool True if password is correct, else false */ - public function check($password, $hash); + public function check($password, $hash, $user_row = array()); /** * Get only the settings of the specified hash diff --git a/phpBB/phpbb/passwords/driver/md5_mybb.php b/phpBB/phpbb/passwords/driver/md5_mybb.php new file mode 100644 index 0000000000..0745bceb5e --- /dev/null +++ b/phpBB/phpbb/passwords/driver/md5_mybb.php @@ -0,0 +1,60 @@ +<?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\passwords\driver; + +class md5_mybb extends base +{ + const PREFIX = '$md5_mybb$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + if (empty($hash) || strlen($hash) != 32 || !isset($user_row['user_passwd_salt'])) + { + return false; + } + else + { + // Works for myBB 1.1.x, 1.2.x, 1.4.x, 1.6.x + return $hash === md5(md5($user_row['user_passwd_salt']) . md5($password)); + } + } +} diff --git a/phpBB/phpbb/passwords/driver/md5_phpbb2.php b/phpBB/phpbb/passwords/driver/md5_phpbb2.php new file mode 100644 index 0000000000..de1993e8a1 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/md5_phpbb2.php @@ -0,0 +1,118 @@ +<?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\passwords\driver; + +class md5_phpbb2 extends base +{ + const PREFIX = '$md5_phpbb2$'; + + /** @var \phpbb\request\request phpBB request object */ + protected $request; + + /** @var \phpbb\passwords\driver\salted_md5 */ + protected $salted_md5; + + /** @var phpBB root path */ + protected $phpbb_root_path; + + /** @var php file extension */ + protected $php_ext; + + /** + * Constructor of passwords driver object + * + * @param \phpbb\request\request $request phpBB request object + * @param \phpbb\passwords\driver\salted_md5 $salted_md5 Salted md5 driver + * @param string $phpbb_root_path phpBB root path + * @param string $php_ext PHP file extension + */ + public function __construct($request, \phpbb\passwords\driver\salted_md5 $salted_md5, $phpbb_root_path, $php_ext) + { + $this->request = $request; + $this->salted_md5 = $salted_md5; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + if (strlen($hash) != 32 && strlen($hash) != 34) + { + return false; + } + + // enable super globals to get literal value + // this is needed to prevent unicode normalization + $super_globals_disabled = $this->request->super_globals_disabled(); + if ($super_globals_disabled) + { + $this->request->enable_super_globals(); + } + + // in phpBB2 passwords were used exactly as they were sent, with addslashes applied + $password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : ''; + $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format; + $password_new_format = $this->request->variable('password', '', true); + + if ($super_globals_disabled) + { + $this->request->disable_super_globals(); + } + + if ($password == $password_new_format) + { + if (!function_exists('utf8_to_cp1252')) + { + include($this->phpbb_root_path . 'includes/utf/data/recode_basic.' . $this->php_ext); + } + + if (md5($password_old_format) === $hash || md5(\utf8_to_cp1252($password_old_format)) === $hash + || $this->salted_md5->check(md5($password_old_format), $hash) === true + || $this->salted_md5->check(md5(\utf8_to_cp1252($password_old_format)), $hash) === true) + { + return true; + } + } + + return false; + } +} diff --git a/phpBB/phpbb/passwords/driver/md5_vb.php b/phpBB/phpbb/passwords/driver/md5_vb.php new file mode 100644 index 0000000000..440b9e39e9 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/md5_vb.php @@ -0,0 +1,60 @@ +<?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\passwords\driver; + +class md5_vb extends base +{ + const PREFIX = '$md5_vb$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + if (empty($hash) || strlen($hash) != 32 || !isset($user_row['user_passwd_salt'])) + { + return false; + } + else + { + // Works for vB 3.8.x, 4.x.x, 5.0.x + return $hash === md5(md5($password) . $user_row['user_passwd_salt']); + } + } +} diff --git a/phpBB/phpbb/passwords/driver/salted_md5.php b/phpBB/phpbb/passwords/driver/salted_md5.php index a9f6712751..b5f59754e1 100644 --- a/phpBB/phpbb/passwords/driver/salted_md5.php +++ b/phpBB/phpbb/passwords/driver/salted_md5.php @@ -56,6 +56,14 @@ class salted_md5 extends base /** * @inheritdoc */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ public function hash($password, $setting = '') { if ($setting) @@ -92,7 +100,7 @@ class salted_md5 extends base /** * @inheritdoc */ - public function check($password, $hash) + public function check($password, $hash, $user_row = array()) { if (strlen($hash) !== 34) { diff --git a/phpBB/phpbb/passwords/driver/sha1.php b/phpBB/phpbb/passwords/driver/sha1.php new file mode 100644 index 0000000000..5d6c93f6a8 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/sha1.php @@ -0,0 +1,52 @@ +<?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\passwords\driver; + +class sha1 extends base +{ + const PREFIX = '$sha1$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + return (strlen($hash) == 40) ? $hash === sha1($password) : false; + } +} diff --git a/phpBB/phpbb/passwords/driver/sha1_smf.php b/phpBB/phpbb/passwords/driver/sha1_smf.php new file mode 100644 index 0000000000..3e3322d77f --- /dev/null +++ b/phpBB/phpbb/passwords/driver/sha1_smf.php @@ -0,0 +1,51 @@ +<?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\passwords\driver; + +class sha1_smf extends base +{ + const PREFIX = '$smf$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + return (isset($user_row['login_name'])) ? sha1(strtolower($user_row['login_name']) . $password) : false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + return (strlen($hash) == 40) ? $hash === $this->hash($password, $user_row) : false; + } +} diff --git a/phpBB/phpbb/passwords/driver/sha1_wcf1.php b/phpBB/phpbb/passwords/driver/sha1_wcf1.php new file mode 100644 index 0000000000..04a69705e9 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/sha1_wcf1.php @@ -0,0 +1,60 @@ +<?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\passwords\driver; + +class sha1_wcf1 extends base +{ + const PREFIX = '$wcf1$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + if (empty($hash) || strlen($hash) != 40 || !isset($user_row['user_passwd_salt'])) + { + return false; + } + else + { + // Works for standard WCF 1.x, i.e. WBB3 and similar + return $hash === sha1($user_row['user_passwd_salt'] . sha1($user_row['user_passwd_salt'] . sha1($password))); + } + } +} diff --git a/phpBB/phpbb/passwords/driver/sha_xf1.php b/phpBB/phpbb/passwords/driver/sha_xf1.php new file mode 100644 index 0000000000..7ae0b90f51 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/sha_xf1.php @@ -0,0 +1,68 @@ +<?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\passwords\driver; + +class sha_xf1 extends base +{ + const PREFIX = '$xf1$'; + + /** + * @inheritdoc + */ + public function get_prefix() + { + return self::PREFIX; + } + + /** + * @inheritdoc + */ + public function is_legacy() + { + return true; + } + + /** + * @inheritdoc + */ + public function hash($password, $user_row = '') + { + // Do not support hashing + return false; + } + + /** + * @inheritdoc + */ + public function check($password, $hash, $user_row = array()) + { + if (empty($hash) || (strlen($hash) != 40 && strlen($hash) != 64) || !isset($user_row['user_passwd_salt'])) + { + return false; + } + else + { + // Works for xenforo 1.0, 1.1 + if ($hash === sha1(sha1($password) . $user_row['user_passwd_salt']) + || $hash === hash('sha256', hash('sha256', $password) . $user_row['user_passwd_salt'])) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/phpBB/phpbb/passwords/manager.php b/phpBB/phpbb/passwords/manager.php index 8b16cf55dd..0a349c4a14 100644 --- a/phpBB/phpbb/passwords/manager.php +++ b/phpBB/phpbb/passwords/manager.php @@ -141,7 +141,7 @@ class manager */ if (!preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $hash, $match)) { - return $this->get_algorithm('$H$'); + return false; } // Be on the lookout for multiple hashing algorithms @@ -224,9 +224,10 @@ class manager * * @param string $password Password that should be checked * @param string $hash Stored hash + * @param array $user_row User's row in users table * @return string|bool True if password is correct, false if not */ - public function check($password, $hash) + public function check($password, $hash, $user_row = array()) { if (strlen($password) > 4096) { @@ -235,11 +236,19 @@ class manager return false; } + // Empty hashes can't be checked + if (empty($hash)) + { + return false; + } + // First find out what kind of hash we're dealing with $stored_hash_type = $this->detect_algorithm($hash); if ($stored_hash_type == false) { - return false; + // Still check MD5 hashes as that is what the installer + // will default to for the admin user + return $this->get_algorithm('$H$')->check($password, $hash); } // Multiple hash passes needed @@ -259,6 +268,21 @@ class manager $this->convert_flag = false; } + // Check all legacy hash types if prefix is $CP$ + if ($stored_hash_type->get_prefix() === '$CP$') + { + // Remove $CP$ prefix for proper checking + $hash = substr($hash, 4); + + foreach ($this->type_map as $algorithm) + { + if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true) + { + return true; + } + } + } + return $stored_hash_type->check($password, $hash); } diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index d286dc9cfc..59b7ec2029 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -408,9 +408,8 @@ class session $session_expired = false; // Check whether the session is still valid if we have one - $method = basename(trim($config['auth_method'])); - - $provider = $phpbb_container->get('auth.provider.' . $method); + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $provider = $provider_collection->get_provider(); if (!($provider instanceof \phpbb\auth\provider\provider_interface)) { @@ -577,9 +576,8 @@ class session } } - $method = basename(trim($config['auth_method'])); - - $provider = $phpbb_container->get('auth.provider.' . $method); + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $provider = $provider_collection->get_provider(); $this->data = $provider->autologin(); if (sizeof($this->data)) @@ -898,9 +896,8 @@ class session $db->sql_query($sql); // Allow connecting logout with external auth method logout - $method = basename(trim($config['auth_method'])); - - $provider = $phpbb_container->get('auth.provider.' . $method); + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $provider = $provider_collection->get_provider(); $provider->logout($this->data, $new_session); if ($this->data['user_id'] != ANONYMOUS) @@ -1075,7 +1072,7 @@ class session { global $config, $db; - if (defined('IN_CHECK_BAN')) + if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN')) { return; } @@ -1189,7 +1186,7 @@ class session if ($banned && !$return) { - global $template; + global $template, $phpbb_root_path, $phpEx; // If the session is empty we need to create a valid one... if (empty($this->session_id)) @@ -1210,8 +1207,6 @@ class session // We show a login box here to allow founders accessing the board if banned by IP if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS) { - global $phpEx; - $this->setup('ucp'); $this->data['is_registered'] = $this->data['is_bot'] = false; @@ -1235,7 +1230,8 @@ class session $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : ''; $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; - $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>'); + $contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx); + $message = sprintf($this->lang[$message], $till_date, '<a href="' . $contact_link . '">', '</a>'); $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>'; diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php index f4cc26cc9a..4e90044395 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -317,7 +317,7 @@ class user extends \phpbb\session } // Is board disabled and user not an admin or moderator? - if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) + if ($config['board_disable'] && !defined('IN_LOGIN') && !defined('SKIP_CHECK_DISABLED') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) { if ($this->data['is_bot']) { |