From 3d5c5ad2f62e58b3eff76e70dcac09a9fd561107 Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Tue, 24 Apr 2018 23:33:29 +0200 Subject: [PATCH] security update core 7.58 --- CHANGELOG.txt | 28 ++ INSTALL.mysql.txt | 45 ++ INSTALL.pgsql.txt | 44 ++ INSTALL.sqlite.txt | 31 ++ INSTALL.txt | 400 ++++++++++++++++++ includes/bootstrap.inc | 13 +- includes/common.inc | 7 +- includes/database/pgsql/database.inc | 12 +- includes/database/pgsql/install.inc | 2 +- includes/database/pgsql/select.inc | 4 +- includes/database/query.inc | 6 +- includes/database/schema.inc | 5 +- includes/database/sqlite/query.inc | 13 +- includes/database/sqlite/schema.inc | 2 +- includes/errors.inc | 6 +- includes/file.inc | 29 +- includes/request-sanitizer.inc | 82 ++++ install.php | 26 ++ misc/drupal.js | 123 +++++- modules/aggregator/aggregator.info | 6 +- modules/aggregator/aggregator.module | 8 + modules/aggregator/aggregator.test | 38 +- modules/aggregator/tests/aggregator_test.info | 6 +- modules/block/block.info | 6 +- modules/block/block.module | 19 +- modules/block/tests/block_test.info | 6 +- .../block_test_theme/block_test_theme.info | 6 +- modules/blog/blog.info | 6 +- modules/book/book.info | 6 +- modules/color/color.info | 6 +- modules/comment/comment.info | 6 +- modules/contact/contact.info | 6 +- modules/contact/contact.module | 9 +- modules/contact/contact.test | 22 + modules/contextual/contextual.info | 6 +- modules/dashboard/dashboard.info | 6 +- modules/dblog/dblog.info | 6 +- modules/field/field.info | 6 +- .../field_sql_storage/field_sql_storage.info | 6 +- modules/field/modules/list/list.info | 6 +- .../field/modules/list/tests/list_test.info | 6 +- modules/field/modules/number/number.info | 6 +- modules/field/modules/options/options.info | 6 +- modules/field/modules/text/text.info | 6 +- modules/field/tests/field_test.info | 6 +- modules/field/theme/field.tpl.php | 8 +- modules/field_ui/field_ui.info | 6 +- modules/file/file.info | 6 +- modules/file/file.module | 23 +- modules/file/tests/file.test | 147 +++++++ modules/file/tests/file_module_test.info | 6 +- modules/file/tests/file_module_test.module | 15 + modules/filter/filter.info | 6 +- modules/forum/forum.info | 6 +- modules/help/help.info | 6 +- modules/image/image.info | 6 +- modules/image/tests/image_module_test.info | 6 +- modules/locale/locale.info | 6 +- modules/locale/locale.test | 6 +- modules/locale/tests/locale_test.info | 6 +- modules/menu/menu.info | 6 +- modules/node/node.info | 6 +- modules/node/tests/node_access_test.info | 6 +- modules/node/tests/node_test.info | 6 +- modules/node/tests/node_test_exception.info | 6 +- modules/openid/openid.info | 6 +- modules/openid/tests/openid_test.info | 6 +- modules/overlay/overlay.info | 6 +- modules/path/path.info | 6 +- modules/php/php.info | 6 +- modules/poll/poll.info | 6 +- modules/profile/profile.info | 6 +- modules/rdf/rdf.info | 6 +- modules/rdf/tests/rdf_test.info | 6 +- modules/search/search.info | 6 +- .../search/tests/search_embedded_form.info | 6 +- modules/search/tests/search_extra_type.info | 6 +- modules/search/tests/search_node_tags.info | 6 +- modules/shortcut/shortcut.info | 6 +- modules/simpletest/drupal_web_test_case.php | 32 +- modules/simpletest/simpletest.info | 6 +- .../simpletest/tests/actions_loop_test.info | 6 +- modules/simpletest/tests/ajax_forms_test.info | 6 +- modules/simpletest/tests/ajax_test.info | 6 +- modules/simpletest/tests/batch_test.info | 6 +- modules/simpletest/tests/boot_test_1.info | 6 +- modules/simpletest/tests/boot_test_2.info | 6 +- modules/simpletest/tests/common.test | 36 +- modules/simpletest/tests/common_test.info | 6 +- modules/simpletest/tests/common_test.module | 3 + .../tests/common_test_cron_helper.info | 6 +- modules/simpletest/tests/database_test.info | 6 +- .../drupal_autoload_test.info | 6 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- .../simpletest/tests/entity_cache_test.info | 6 +- .../tests/entity_cache_test_dependency.info | 6 +- .../tests/entity_crud_hook_test.info | 6 +- .../tests/entity_query_access_test.info | 6 +- modules/simpletest/tests/error_test.info | 6 +- modules/simpletest/tests/file_test.info | 6 +- modules/simpletest/tests/filter_test.info | 6 +- modules/simpletest/tests/form_test.info | 6 +- modules/simpletest/tests/image_test.info | 6 +- modules/simpletest/tests/menu_test.info | 6 +- modules/simpletest/tests/module_test.info | 6 +- modules/simpletest/tests/path_test.info | 6 +- .../tests/psr_0_test/psr_0_test.info | 6 +- .../tests/psr_4_test/psr_4_test.info | 6 +- .../simpletest/tests/requirements1_test.info | 6 +- .../simpletest/tests/requirements2_test.info | 6 +- modules/simpletest/tests/session_test.info | 6 +- .../tests/system_dependencies_test.info | 6 +- ...atible_core_version_dependencies_test.info | 6 +- ...system_incompatible_core_version_test.info | 6 +- ...ible_module_version_dependencies_test.info | 6 +- ...stem_incompatible_module_version_test.info | 6 +- .../tests/system_project_namespace_test.info | 6 +- modules/simpletest/tests/system_test.info | 6 +- modules/simpletest/tests/taxonomy_test.info | 6 +- modules/simpletest/tests/theme_test.info | 6 +- .../themes/test_basetheme/test_basetheme.info | 6 +- .../themes/test_subtheme/test_subtheme.info | 6 +- .../tests/themes/test_theme/test_theme.info | 6 +- .../test_theme_nyan_cat.info | 6 +- .../simpletest/tests/update_script_test.info | 6 +- modules/simpletest/tests/update_test_1.info | 6 +- modules/simpletest/tests/update_test_2.info | 6 +- modules/simpletest/tests/update_test_3.info | 6 +- modules/simpletest/tests/url_alter_test.info | 6 +- modules/simpletest/tests/xmlrpc_test.info | 6 +- modules/statistics/statistics.info | 6 +- modules/statistics/statistics.module | 2 +- modules/syslog/syslog.info | 6 +- modules/system/system.info | 6 +- modules/system/system.install | 2 +- modules/system/tests/cron_queue_test.info | 6 +- modules/system/tests/system_cron_test.info | 6 +- modules/taxonomy/taxonomy.info | 6 +- modules/toolbar/toolbar.info | 6 +- modules/tracker/tracker.info | 6 +- .../translation/tests/translation_test.info | 6 +- modules/translation/translation.info | 6 +- modules/trigger/tests/trigger_test.info | 6 +- modules/trigger/trigger.info | 6 +- modules/update/tests/aaa_update_test.info | 6 +- modules/update/tests/bbb_update_test.info | 6 +- modules/update/tests/ccc_update_test.info | 6 +- .../update_test_admintheme.info | 6 +- .../update_test_basetheme.info | 6 +- .../update_test_subtheme.info | 6 +- modules/update/tests/update_test.info | 6 +- modules/update/update.info | 6 +- modules/user/tests/user_form_test.info | 6 +- modules/user/user.info | 6 +- modules/user/user.module | 9 +- modules/user/user.test | 76 +++- profiles/minimal/minimal.info | 6 +- profiles/standard/standard.info | 6 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- profiles/testing/testing.info | 6 +- themes/bartik/bartik.info | 6 +- themes/garland/garland.info | 6 +- themes/seven/seven.info | 6 +- themes/stark/stark.info | 6 +- 166 files changed, 1633 insertions(+), 480 deletions(-) create mode 100644 INSTALL.mysql.txt create mode 100644 INSTALL.pgsql.txt create mode 100644 INSTALL.sqlite.txt create mode 100644 INSTALL.txt create mode 100644 includes/request-sanitizer.inc create mode 100644 install.php diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c015fb4f..799b8003 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,32 @@ +Drupal 7.58, 2018-03-28 +----------------------- +- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-002. + +Drupal 7.57, 2018-02-21 +----------------------- +- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-001. + +Drupal 7.56, 2017-06-21 +----------------------- +- Fixed security issues (access bypass). See SA-CORE-2017-003. + +Drupal 7.55, 2017-06-07 +----------------------- +- Fixed incompatibility with PHP versions 7.0.19 and 7.1.5 due to duplicate + DATE_RFC7231 definition. +- Made Drupal core pass all automated tests on PHP 7.1. +- Allowed services such as Let's Encrypt to work with Drupal on Apache, by + making Drupal's .htaccess file allow access to the .well-known directory + defined by RFC 5785. +- Made new Drupal sites work correctly on Apache 2.4 when the mod_access_compat + Apache module is disabled. +- Fixed Drupal's URL-generating functions to always encode '[' and ']' so that + the URLs will pass HTML5 validation. +- Various additional bug fixes. +- Various API documentation improvements. +- Additional automated test coverage. + Drupal 7.54, 2017-02-01 ----------------------- - Modules are now able to define theme engines (API addition: diff --git a/INSTALL.mysql.txt b/INSTALL.mysql.txt new file mode 100644 index 00000000..95a87343 --- /dev/null +++ b/INSTALL.mysql.txt @@ -0,0 +1,45 @@ + +CREATE THE MySQL DATABASE +-------------------------- + +This step is only necessary if you don't already have a database set up (e.g., +by your host). In the following examples, 'username' is an example MySQL user +which has the CREATE and GRANT privileges. Use the appropriate user name for +your system. + +First, you must create a new database for your Drupal site (here, 'databasename' +is the name of the new database): + + mysqladmin -u username -p create databasename + +MySQL will prompt for the 'username' database password and then create the +initial database files. Next you must log in and set the access database rights: + + mysql -u username -p + +Again, you will be asked for the 'username' database password. At the MySQL +prompt, enter the following command: + + GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, + CREATE TEMPORARY TABLES ON databasename.* + TO 'username'@'localhost' IDENTIFIED BY 'password'; + +where: + + 'databasename' is the name of your database + 'username' is the username of your MySQL account + 'localhost' is the web server host where Drupal is installed + 'password' is the password required for that username + +Note: Unless the database user/host combination for your Drupal installation +has all of the privileges listed above (except possibly CREATE TEMPORARY TABLES, +which is currently only used by Drupal core automated tests and some +contributed modules), you will not be able to install or run Drupal. + +If successful, MySQL will reply with: + + Query OK, 0 rows affected + +If the InnoDB storage engine is available, it will be used for all database +tables. InnoDB provides features over MyISAM such as transaction support, +row-level locks, and consistent non-locking reads. diff --git a/INSTALL.pgsql.txt b/INSTALL.pgsql.txt new file mode 100644 index 00000000..8fe80433 --- /dev/null +++ b/INSTALL.pgsql.txt @@ -0,0 +1,44 @@ + +CREATE THE PostgreSQL DATABASE +------------------------------ + +Note that the database must be created with UTF-8 (Unicode) encoding. + +1. CREATE DATABASE USER + + This step is only necessary if you don't already have a user set up (e.g., by + your host), or want to create a new user for use with Drupal only. The + following command creates a new user named 'username' and asks for a password + for that user: + + createuser --pwprompt --encrypted --no-createrole --no-createdb username + + If there are no errors, then the command was successful. + +2. CREATE DRUPAL DATABASE + + This step is only necessary if you don't already have a database set up + (e.g., by your host) or want to create a new database for use with Drupal + only. The following command creates a new database named 'databasename', + which is owned by the previously created 'username': + + createdb --encoding=UTF8 --owner=username databasename + + If there are no errors, then the command was successful. + +3. CREATE SCHEMA OR SCHEMAS (Optional advanced step) + + Drupal will run across different schemas within your database if you so wish. + By default, Drupal runs inside the 'public' schema but you can use $db_prefix + inside settings.php to define a schema for Drupal to run inside of, or + specify tables that are shared inside of a separate schema. Drupal will not + create schemas for you. In fact, the user that Drupal runs as should not be + allowed to do this. You'll need to execute the SQL below as a superuser, + replace 'username' with the username that Drupal uses to connect to + PostgreSQL, and replace 'schema_name' with a schema name you wish to use, + such as 'shared': + + CREATE SCHEMA schema_name AUTHORIZATION username; + + Do this for as many schemas as you need. See default.settings.php for + instructions on how to set which tables use which schemas. diff --git a/INSTALL.sqlite.txt b/INSTALL.sqlite.txt new file mode 100644 index 00000000..8e57d60c --- /dev/null +++ b/INSTALL.sqlite.txt @@ -0,0 +1,31 @@ + +SQLITE REQUIREMENTS +------------------- + +To use SQLite with your Drupal installation, the following requirements must be +met: Server has PHP 5.2 or later with PDO, and the PDO SQLite driver must be +enabled. + +SQLITE DATABASE CREATION +------------------------ + +The Drupal installer will create the SQLite database for you. The only +requirement is that the installer must have write permissions to the directory +where the database file resides. This directory (not just the database file) also +has to remain writeable by the web server going forward for SQLite to continue to +be able to operate. + +On the "Database configuration" form in the "Database file" field, you must +supply the exact path to where you wish your database file to reside. It is +strongly suggested that you choose a path that is outside of the webroot, yet +ensure that the directory is writeable by the web server. + +If you must place your database file in your webroot, you could try using the +following in your "Database file" field: + + sites/default/files/.ht.sqlite + +Note: The .ht in the name will tell Apache to prevent the database from being +downloaded. Please check that the file is, indeed, protected by your webserver. +If not, please consult the documentation of your webserver on how to protect a +file from downloading. diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 00000000..e00c8bad --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,400 @@ + +CONTENTS OF THIS FILE +--------------------- + + * Requirements and notes + * Optional server requirements + * Installation + * Building and customizing your site + * Multisite configuration + * More information + +REQUIREMENTS AND NOTES +---------------------- + +Drupal requires: + +- A web server. Apache (version 2.0 or greater) is recommended. +- PHP 5.2.4 (or greater) (http://www.php.net/). +- One of the following databases: + - MySQL 5.0.15 (or greater) (http://www.mysql.com/). + - MariaDB 5.1.44 (or greater) (http://mariadb.org/). MariaDB is a fully + compatible drop-in replacement for MySQL. + - Percona Server 5.1.70 (or greater) (http://www.percona.com/). Percona + Server is a backwards-compatible replacement for MySQL. + - PostgreSQL 8.3 (or greater) (http://www.postgresql.org/). + - SQLite 3.3.7 (or greater) (http://www.sqlite.org/). + +For more detailed information about Drupal requirements, including a list of +PHP extensions and configurations that are required, see "System requirements" +(http://drupal.org/requirements) in the Drupal.org online documentation. + +For detailed information on how to configure a test server environment using a +variety of operating systems and web servers, see "Local server setup" +(http://drupal.org/node/157602) in the Drupal.org online documentation. + +Note that all directories mentioned in this document are always relative to the +directory of your Drupal installation, and commands are meant to be run from +this directory (except for the initial commands that create that directory). + +OPTIONAL SERVER REQUIREMENTS +---------------------------- + +- If you want to use Drupal's "Clean URLs" feature on an Apache web server, you + will need the mod_rewrite module and the ability to use local .htaccess + files. For Clean URLs support on IIS, see "Clean URLs with IIS" + (http://drupal.org/node/3854) in the Drupal.org online documentation. + +- If you plan to use XML-based services such as RSS aggregation, you will need + PHP's XML extension. This extension is enabled by default on most PHP + installations. + +- To serve gzip compressed CSS and JS files on an Apache web server, you will + need the mod_headers module and the ability to use local .htaccess files. + +- Some Drupal functionality (e.g., checking whether Drupal and contributed + modules need updates, RSS aggregation, etc.) require that the web server be + able to go out to the web and download information. If you want to use this + functionality, you need to verify that your hosting provider or server + configuration allows the web server to initiate outbound connections. Most web + hosting setups allow this. + +INSTALLATION +------------ + +1. Download and extract Drupal. + + You can obtain the latest Drupal release from http://drupal.org -- the files + are available in .tar.gz and .zip formats and can be extracted using most + compression tools. + + To download and extract the files, on a typical Unix/Linux command line, use + the following commands (assuming you want version x.y of Drupal in .tar.gz + format): + + wget http://drupal.org/files/projects/drupal-x.y.tar.gz + tar -zxvf drupal-x.y.tar.gz + + This will create a new directory drupal-x.y/ containing all Drupal files and + directories. Then, to move the contents of that directory into a directory + within your web server's document root or your public HTML directory, + continue with this command: + + mv drupal-x.y/* drupal-x.y/.htaccess /path/to/your/installation + +2. Optionally, download a translation. + + By default, Drupal is installed in English, and further languages may be + installed later. If you prefer to install Drupal in another language + initially: + + - Download a translation file for the correct Drupal version and language + from the translation server: http://localize.drupal.org/translate/downloads + + - Place the file into your installation profile's translations directory. + For instance, if you are using the Standard installation profile, + move the .po file into the directory: + + profiles/standard/translations/ + + For detailed instructions, visit http://drupal.org/localize + +3. Create the Drupal database. + + Because Drupal stores all site information in a database, you must create + this database in order to install Drupal, and grant Drupal certain database + privileges (such as the ability to create tables). For details, consult + INSTALL.mysql.txt, INSTALL.pgsql.txt, or INSTALL.sqlite.txt. You may also + need to consult your web hosting provider for instructions specific to your + web host. + + Take note of the username, password, database name, and hostname as you + create the database. You will enter this information during the install. + +4. Run the install script. + + To run the install script, point your browser to the base URL of your + website (e.g., http://www.example.com). + + You will be guided through several screens to set up the database, add the + site maintenance account (the first user, also known as user/1), and provide + basic web site settings. + + During installation, several files and directories need to be created, which + the install script will try to do automatically. However, on some hosting + environments, manual steps are required, and the install script will tell + you that it cannot proceed until you fix certain issues. This is normal and + does not indicate a problem with your server. + + The most common steps you may need to perform are: + + a. Missing files directory. + + The install script will attempt to create a file storage directory in + the default location at sites/default/files (the location of the files + directory may be changed after Drupal is installed). + + If auto-creation fails, you can make it work by changing permissions on + the sites/default directory so that the web server can create the files + directory within it for you. (If you are creating a multisite + installation, substitute the correct sites directory for sites/default; + see the Multisite Configuration section of this file, below.) + + For example, on a Unix/Linux command line, you can grant everyone + (including the web server) permission to write to the sites/default + directory with this command: + + chmod a+w sites/default + + Be sure to set the permissions back after the installation is finished! + Sample command: + + chmod go-w sites/default + + Alternatively, instead of allowing the web server to create the files + directory for you as described above, you can create it yourself. Sample + commands from a Unix/Linux command line: + + mkdir sites/default/files + chmod a+w sites/default/files + + b. Missing settings file. + + Drupal will try to automatically create a settings.php configuration file, + which is normally in the directory sites/default (to avoid problems when + upgrading, Drupal is not packaged with this file). If auto-creation fails, + you will need to create this file yourself, using the file + sites/default/default.settings.php as a template. + + For example, on a Unix/Linux command line, you can make a copy of the + default.settings.php file with the command: + + cp sites/default/default.settings.php sites/default/settings.php + + Next, grant write privileges to the file to everyone (including the web + server) with the command: + + chmod a+w sites/default/settings.php + + Be sure to set the permissions back after the installation is finished! + Sample command: + + chmod go-w sites/default/settings.php + + c. Write permissions after install. + + The install script will attempt to write-protect the settings.php file and + the sites/default directory after saving your configuration. If this + fails, you will be notified, and you can do it manually. Sample commands + from a Unix/Linux command line: + + chmod go-w sites/default/settings.php + chmod go-w sites/default + +5. Verify that the site is working. + + When the install script finishes, you will be logged in with the site + maintenance account on a "Welcome" page. If the default Drupal theme is not + displaying properly and links on the page result in "Page Not Found" errors, + you may be experiencing problems with clean URLs. Visit + http://drupal.org/getting-started/clean-urls to troubleshoot. + +6. Change file system storage settings (optional). + + The files directory created in step 4 is the default file system path used to + store all uploaded files, as well as some temporary files created by + Drupal. After installation, you can modify the file system path to store + uploaded files in a different location. + + It is not necessary to modify this path, but you may wish to change it if: + + - Your site runs multiple Drupal installations from a single codebase (modify + the file system path of each installation to a different directory so that + uploads do not overlap between installations). + + - Your site runs on a number of web servers behind a load balancer or reverse + proxy (modify the file system path on each server to point to a shared file + repository). + + - You want to restrict access to uploaded files. + + To modify the file system path: + + a. Ensure that the new location for the path exists and is writable by the + web server. For example, to create a new directory named uploads and grant + write permissions, use the following commands on a Unix/Linux command + line: + + mkdir uploads + chmod a+w uploads + + b. Navigate to Administration > Configuration > Media > File system, and + enter the desired path. Note that if you want to use private file storage, + you need to first enter the path for private files and save the + configuration, and then change the "Default download method" setting and + save again. + + Changing the file system path after files have been uploaded may cause + unexpected problems on an existing site. If you modify the file system path + on an existing site, remember to copy all files from the original location + to the new location. + +7. Revoke documentation file permissions (optional). + + Some administrators suggest making the documentation files, especially + CHANGELOG.txt, non-readable so that the exact version of Drupal you are + running is slightly more difficult to determine. If you wish to implement + this optional security measure, from a Unix/Linux command line you can use + the following command: + + chmod a-r CHANGELOG.txt + + Note that the example only affects CHANGELOG.txt. To completely hide all + documentation files from public view, repeat this command for each of the + Drupal documentation files in the installation directory, substituting the + name of each file for CHANGELOG.txt in the example. + + For more information on setting file permissions, see "Modifying Linux, + Unix, and Mac file permissions" (http://drupal.org/node/202483) or + "Modifying Windows file permissions" (http://drupal.org/node/202491) in the + Drupal.org online documentation. + +8. Set up independent "cron" maintenance jobs. + + Many Drupal modules have tasks that must be run periodically, including the + Search module (building and updating the index used for keyword searching), + the Aggregator module (retrieving feeds from other sites), and the System + module (performing routine maintenance and pruning of database tables). These + tasks are known as "cron maintenance tasks", named after the Unix/Linux + "cron" utility. + + When you install Drupal, its built-in cron feature is enabled, which + automatically runs the cron tasks periodically, triggered by people visiting + pages of your site. You can configure the built-in cron feature by navigating + to Administration > Configuration > System > Cron. + + It is also possible to run the cron tasks independent of site visits; this is + recommended for most sites. To do this, you will need to set up an automated + process to visit the page cron.php on your site, which executes the cron + tasks. + + The URL of the cron.php page requires a "cron key" to protect against + unauthorized access. Your site's cron key is automatically generated during + installation and is specific to your site. The full URL of the page, with the + cron key, is available in the "Cron maintenance tasks" section of the Status + report page at Administration > Reports > Status report. + + As an example for how to set up this automated process, you can use the + crontab utility on Unix/Linux systems. The following crontab line uses the + wget command to visit the cron.php page, and runs each hour, on the hour: + + 0 * * * * wget -O - -q -t 1 http://example.com/cron.php?cron_key=YOURKEY + + Replace the text "http://example.com/cron.php?cron_key=YOURKEY" in the + example with the full URL displayed under "Cron maintenance tasks" on the + "Status report" page. + + More information about cron maintenance tasks is available at + http://drupal.org/cron, and sample cron shell scripts can be found in the + scripts/ directory. (Note that these scripts must be customized like the + above example, to add your site-specific cron key and domain name.) + +BUILDING AND CUSTOMIZING YOUR SITE +---------------------------------- + +A new installation of Drupal defaults to a very basic configuration. To extend +your site, you use "modules" and "themes". A module is a plugin that adds +functionality to Drupal, while a theme changes the look of your site. The core +of Drupal provides several optional modules and themes, and you can download +more at http://drupal.org/project/modules and http://drupal.org/project/themes + +Do not mix downloaded or custom modules and themes with Drupal's core modules +and themes. Drupal's modules and themes are located in the top-level modules and +themes directories, while the modules and themes you add to Drupal are normally +placed in the sites/all/modules and sites/all/themes directories. If you run a +multisite installation, you can also place modules and themes in the +site-specific directories -- see the Multisite Configuration section, below. + +Never edit Drupal's core modules and themes; instead, use the hooks available in +the Drupal API. To modify the behavior of Drupal, develop a module as described +at http://drupal.org/developing/modules. To modify the look of Drupal, create a +subtheme as described at http://drupal.org/node/225125, or a completely new +theme as described at http://drupal.org/documentation/theme + +MULTISITE CONFIGURATION +----------------------- + +A single Drupal installation can host several Drupal-powered sites, each with +its own individual configuration. + +Additional site configurations are created in subdirectories within the 'sites' +directory. Each subdirectory must have a 'settings.php' file, which specifies +the configuration settings. The easiest way to create additional sites is to +copy the 'default' directory and modify the 'settings.php' file as appropriate. +The new directory name is constructed from the site's URL. The configuration for +www.example.com could be in 'sites/example.com/settings.php' (note that 'www.' +should be omitted if users can access your site at http://example.com/). + +Sites do not have to have a different domain. You can also use subdomains and +subdirectories for Drupal sites. For example, example.com, sub.example.com, and +sub.example.com/site3 can all be defined as independent Drupal sites. The setup +for a configuration such as this would look like the following: + + sites/default/settings.php + sites/example.com/settings.php + sites/sub.example.com/settings.php + sites/sub.example.com.site3/settings.php + +When searching for a site configuration (for example www.sub.example.com/site3), +Drupal will search for configuration files in the following order, using the +first configuration it finds: + + sites/www.sub.example.com.site3/settings.php + sites/sub.example.com.site3/settings.php + sites/example.com.site3/settings.php + sites/www.sub.example.com/settings.php + sites/sub.example.com/settings.php + sites/example.com/settings.php + sites/default/settings.php + +If you are installing on a non-standard port, the port number is treated as the +deepest subdomain. For example: http://www.example.com:8080/ could be loaded +from sites/8080.www.example.com/. The port number will be removed according to +the pattern above if no port-specific configuration is found, just like a real +subdomain. + +Each site configuration can have its own site-specific modules and themes in +addition to those installed in the standard 'modules' and 'themes' directories. +To use site-specific modules or themes, simply create a 'modules' or 'themes' +directory within the site configuration directory. For example, if +sub.example.com has a custom theme and a custom module that should not be +accessible to other sites, the setup would look like this: + + sites/sub.example.com/ + settings.php + themes/custom_theme + modules/custom_module + +NOTE: for more information about multiple virtual hosts or the configuration +settings, consult http://drupal.org/getting-started/6/install/multi-site + +For more information on configuring Drupal's file system path in a multisite +configuration, see step 6 above. + +MORE INFORMATION +---------------- + +- See the Drupal.org online documentation: + http://drupal.org/documentation + +- For a list of security announcements, see the "Security advisories" page at + http://drupal.org/security (available as an RSS feed). This page also + describes how to subscribe to these announcements via e-mail. + +- For information about the Drupal security process, or to find out how to + report a potential security issue to the Drupal security team, see the + "Security team" page at http://drupal.org/security-team + +- For information about the wide range of available support options, visit + http://drupal.org and click on Community and Support in the top or bottom + navigation. diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 99a5ac84..06acf935 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.54'); +define('VERSION', '7.58'); /** * Core API compatibility. @@ -254,8 +254,13 @@ define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' * http://tools.ietf.org/html/rfc7231#section-7.1.1.1 * * Example: Sun, 06 Nov 1994 08:49:37 GMT + * + * This constant was introduced in PHP 7.0.19 and PHP 7.1.5 but needs to be + * defined by Drupal for earlier PHP versions. */ -define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T'); +if (!defined('DATE_RFC7231')) { + define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T'); +} /** * Provides a caching wrapper to be used in place of large array structures. @@ -2627,6 +2632,10 @@ function _drupal_bootstrap_configuration() { timer_start('page'); // Initialize the configuration, including variables from settings.php. drupal_settings_initialize(); + + // Sanitize unsafe keys from the request. + require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc'; + DrupalRequestSanitizer::sanitize(); } /** diff --git a/includes/common.inc b/includes/common.inc index da8996a1..d7dc47f2 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -487,7 +487,7 @@ function drupal_http_build_query(array $query, $parent = '') { $params = array(); foreach ($query as $key => $value) { - $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key)); + $key = $parent ? $parent . rawurlencode('[' . $key . ']') : rawurlencode($key); // Recurse into children. if (is_array($value)) { @@ -2236,8 +2236,11 @@ function url($path = NULL, array $options = array()) { 'prefix' => '' ); + // Determine whether this is an external link, but ensure that the current + // path is always treated as internal by default (to prevent external link + // injection vulnerabilities). if (!isset($options['external'])) { - $options['external'] = url_is_external($path); + $options['external'] = $path === $_GET['q'] ? FALSE : url_is_external($path); } // Preserve the original path before altering or aliasing. diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc index 41579659..fb3d0ab5 100644 --- a/includes/database/pgsql/database.inc +++ b/includes/database/pgsql/database.inc @@ -11,7 +11,7 @@ */ /** - * The name by which to obtain a lock for retrive the next insert id. + * The name by which to obtain a lock for retrieving the next insert id. */ define('POSTGRESQL_NEXTID_LOCK', 1000); @@ -55,7 +55,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection { $connection_options['pdo'] += array( // Prepared statements are most effective for performance when queries // are recycled (used several times). However, if they are not re-used, - // prepared statements become ineffecient. Since most of Drupal's + // prepared statements become inefficient. Since most of Drupal's // prepared queries are not re-used, it should be faster to emulate // the preparation than to actually ready statements for re-use. If in // doubt, reset to FALSE and measure performance. @@ -175,14 +175,14 @@ class DatabaseConnection_pgsql extends DatabaseConnection { } /** - * Retrive a the next id in a sequence. + * Retrieve the next id in a sequence. * * PostgreSQL has built in sequences. We'll use these instead of inserting * and updating a sequences table. */ public function nextId($existing = 0) { - // Retrive the name of the sequence. This information cannot be cached + // Retrieve the name of the sequence. This information cannot be cached // because the prefix may change, for example, like it does in simpletests. $sequence_name = $this->makeSequenceName('sequences', 'value'); @@ -194,7 +194,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection { } // PostgreSQL advisory locks are simply locks to be used by an - // application such as Drupal. This will prevent other Drupal proccesses + // application such as Drupal. This will prevent other Drupal processes // from altering the sequence while we are. $this->query("SELECT pg_advisory_lock(" . POSTGRESQL_NEXTID_LOCK . ")"); @@ -209,7 +209,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection { // Reset the sequence to a higher value than the existing id. $this->query("ALTER SEQUENCE " . $sequence_name . " RESTART WITH " . ($existing + 1)); - // Retrive the next id. We know this will be as high as we want it. + // Retrieve the next id. We know this will be as high as we want it. $id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField(); $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK . ")"); diff --git a/includes/database/pgsql/install.inc b/includes/database/pgsql/install.inc index c77f4ea7..122031ee 100644 --- a/includes/database/pgsql/install.inc +++ b/includes/database/pgsql/install.inc @@ -165,7 +165,7 @@ class DatabaseTasks_pgsql extends DatabaseTasks { LANGUAGE \'sql\'' ); - // Using || to concatenate in Drupal is not recommeneded because there are + // Using || to concatenate in Drupal is not recommended because there are // database drivers for Drupal that do not support the syntax, however // they do support CONCAT(item1, item2) which we can replicate in // PostgreSQL. PostgreSQL requires the function to be defined for each diff --git a/includes/database/pgsql/select.inc b/includes/database/pgsql/select.inc index f6a83db7..5b8736d6 100644 --- a/includes/database/pgsql/select.inc +++ b/includes/database/pgsql/select.inc @@ -80,7 +80,7 @@ class SelectQuery_pgsql extends SelectQuery { } // If a table loads all fields, it can not be added again. It would - // result in an ambigious alias error because that field would be loaded + // result in an ambiguous alias error because that field would be loaded // twice: Once through table_alias.* and once directly. If the field // actually belongs to a different table, it must be added manually. foreach ($this->tables as $table) { @@ -90,7 +90,7 @@ class SelectQuery_pgsql extends SelectQuery { } // If $field contains an characters which are not allowed in a field name - // it is considered an expression, these can't be handeld automatically + // it is considered an expression, these can't be handled automatically // either. if ($this->connection->escapeField($field) != $field) { return $return; diff --git a/includes/database/query.inc b/includes/database/query.inc index c9c5a832..048c8a26 100644 --- a/includes/database/query.inc +++ b/includes/database/query.inc @@ -845,8 +845,8 @@ class DeleteQuery extends Query implements QueryConditionInterface { /** * Executes the DELETE query. * - * @return - * The return value is dependent on the database connection. + * @return int + * The number of rows affected by the delete query. */ public function execute() { $values = array(); @@ -1242,7 +1242,7 @@ class UpdateQuery extends Query implements QueryConditionInterface { * MergeQuery::updateFields() and MergeQuery::insertFields() needs to be called * instead. MergeQuery::fields() can also be called which calls both of these * methods as the common case is to use the same column-value pairs for both - * INSERT and UPDATE. However, this is not mandatory. Another convinient + * INSERT and UPDATE. However, this is not mandatory. Another convenient * wrapper is MergeQuery::key() which adds the same column-value pairs to the * condition and the INSERT query part. * diff --git a/includes/database/schema.inc b/includes/database/schema.inc index d8344c62..31862db3 100644 --- a/includes/database/schema.inc +++ b/includes/database/schema.inc @@ -164,6 +164,9 @@ require_once dirname(__FILE__) . '/query.inc'; * @see drupal_install_schema() */ +/** + * Base class for database schema definitions. + */ abstract class DatabaseSchema implements QueryPlaceholderInterface { protected $connection; @@ -291,7 +294,7 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface { protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) { $info = $this->connection->getConnectionOptions(); - // Retrive the table name and schema + // Retrieve the table name and schema $table_info = $this->getPrefixInfo($table_name, $add_prefix); $condition = new DatabaseCondition('AND'); diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc index 1c6289bd..c9c028bb 100644 --- a/includes/database/sqlite/query.inc +++ b/includes/database/sqlite/query.inc @@ -99,16 +99,15 @@ class UpdateQuery_sqlite extends UpdateQuery { /** * SQLite specific implementation of DeleteQuery. - * - * When the WHERE is omitted from a DELETE statement and the table being deleted - * has no triggers, SQLite uses an optimization to erase the entire table content - * without having to visit each row of the table individually. - * - * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted - * by that optimized "truncate" optimization. */ class DeleteQuery_sqlite extends DeleteQuery { public function execute() { + // When the WHERE is omitted from a DELETE statement and the table being + // deleted has no triggers, SQLite uses an optimization to erase the entire + // table content without having to visit each row of the table individually. + // Prior to SQLite 3.6.5, SQLite does not return the actual number of rows + // deleted by that optimized "truncate" optimization. But we want to return + // the number of rows affected, so we calculate it directly. if (!count($this->condition)) { $total_rows = $this->connection->query('SELECT COUNT(*) FROM {' . $this->connection->escapeTable($this->table) . '}')->fetchField(); parent::execute(); diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc index df19d2fa..281d8fc6 100644 --- a/includes/database/sqlite/schema.inc +++ b/includes/database/sqlite/schema.inc @@ -244,7 +244,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema { // database. So the syntax '...RENAME TO database.table' would fail. // So we must determine the full table name here rather than surrounding // the table with curly braces incase the db_prefix contains a reference - // to a database outside of our existsing database. + // to a database outside of our existing database. $info = $this->getPrefixInfo($new_name); $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table']); diff --git a/includes/errors.inc b/includes/errors.inc index 7393148e..3548d1fd 100644 --- a/includes/errors.inc +++ b/includes/errors.inc @@ -66,7 +66,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line, $c _drupal_log_error(array( '%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error', // The standard PHP error handler considers that the error messages - // are HTML. We mimick this behavior here. + // are HTML. We mimic this behavior here. '!message' => filter_xss_admin($message), '%function' => $caller['function'], '%file' => $caller['file'], @@ -114,7 +114,7 @@ function _drupal_decode_exception($exception) { return array( '%type' => get_class($exception), // The standard PHP exception handler considers that the exception message - // is plain-text. We mimick this behavior here. + // is plain-text. We mimic this behavior here. '!message' => check_plain($message), '%function' => $caller['function'], '%file' => $caller['file'], @@ -233,7 +233,7 @@ function _drupal_log_error($error, $fatal = FALSE) { } else { // Display the message if the current error reporting level allows this type - // of message to be displayed, and unconditionnaly in update.php. + // of message to be displayed, and unconditionally in update.php. if (error_displayable($error)) { $class = 'error'; diff --git a/includes/file.inc b/includes/file.inc index de9d17d6..fa7f5eb5 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -535,7 +535,18 @@ SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 EOF; if ($private) { - $lines = "Deny from all\n\n" . $lines; + $lines = << + Require all denied + + +# Deny all requests from Apache 2.0-2.2. + + Deny from all + +EOF + . "\n\n" . $lines; } return $lines; @@ -889,7 +900,6 @@ function file_valid_uri($uri) { */ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { $original_source = $source; - $original_destination = $destination; // Assert that the source file actually exists. if (!file_exists($source)) { @@ -1604,6 +1614,20 @@ function file_save_upload($form_field_name, $validators = array(), $destination // If we made it this far it's safe to record this file in the database. if ($file = file_save($file)) { + // Track non-public files in the session if they were uploaded by an + // anonymous user. This allows modules such as the File module to only + // grant view access to the specific anonymous user who uploaded the file. + // See file_file_download(). + // The 'file_public_schema' variable is used to allow other publicly + // accessible file schemes to be treated the same as the public:// scheme + // provided by Drupal core and to avoid adding unnecessary data to the + // session (and the resulting bypass of the page cache) in those cases. For + // security reasons, only schemes that are completely publicly accessible, + // with no download restrictions, should be added to this variable. See + // file_managed_file_value(). + if (!$user->uid && !in_array($destination_scheme, variable_get('file_public_schema', array('public')))) { + $_SESSION['anonymous_allowed_file_ids'][$file->fid] = $file->fid; + } // Add file to the cache. $upload_cache[$form_field_name] = $file; return $file; @@ -2553,7 +2577,6 @@ function file_directory_temp() { * An associative array of headers, as expected by file_transfer(). */ function file_get_content_headers($file) { - $name = mime_header_encode($file->filename); $type = mime_header_encode($file->filemime); return array( diff --git a/includes/request-sanitizer.inc b/includes/request-sanitizer.inc new file mode 100644 index 00000000..1daa6b53 --- /dev/null +++ b/includes/request-sanitizer.inc @@ -0,0 +1,82 @@ + implode(', ', $get_sanitized_keys))), E_USER_NOTICE); + } + + // Process request body parameters. + $post_sanitized_keys = array(); + $_POST = self::stripDangerousValues($_POST, $whitelist, $post_sanitized_keys); + if ($log_sanitized_keys && $post_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from request body parameters (POST): @keys', array('@keys' => implode(', ', $post_sanitized_keys))), E_USER_NOTICE); + } + + // Process cookie parameters. + $cookie_sanitized_keys = array(); + $_COOKIE = self::stripDangerousValues($_COOKIE, $whitelist, $cookie_sanitized_keys); + if ($log_sanitized_keys && $cookie_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from cookie parameters (COOKIE): @keys', array('@keys' => implode(', ', $cookie_sanitized_keys))), E_USER_NOTICE); + } + + $request_sanitized_keys = array(); + $_REQUEST = self::stripDangerousValues($_REQUEST, $whitelist, $request_sanitized_keys); + + self::$sanitized = TRUE; + } + } + + /** + * Strips dangerous keys from the provided input. + * + * @param mixed $input + * The input to sanitize. + * @param string[] $whitelist + * An array of keys to whitelist as safe. + * @param string[] $sanitized_keys + * An array of keys that have been removed. + * + * @return mixed + * The sanitized input. + */ + protected static function stripDangerousValues($input, array $whitelist, array &$sanitized_keys) { + if (is_array($input)) { + foreach ($input as $key => $value) { + if ($key !== '' && $key[0] === '#' && !in_array($key, $whitelist, TRUE)) { + unset($input[$key]); + $sanitized_keys[] = $key; + } + else { + $input[$key] = self::stripDangerousValues($input[$key], $whitelist, $sanitized_keys); + } + } + } + return $input; + } + +} diff --git a/install.php b/install.php new file mode 100644 index 00000000..685d3b4e --- /dev/null +++ b/install.php @@ -0,0 +1,26 @@ +system requirements page for more information.'; + exit; +} + +// Start the installer. +require_once DRUPAL_ROOT . '/includes/install.core.inc'; +install_drupal(); diff --git a/misc/drupal.js b/misc/drupal.js index 03eef50e..19fbc712 100644 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -27,6 +27,42 @@ $.fn.init = function (selector, context, rootjQuery) { }; $.fn.init.prototype = jquery_init.prototype; +/** + * Pre-filter Ajax requests to guard against XSS attacks. + * + * See https://github.com/jquery/jquery/issues/2432 + */ +if ($.ajaxPrefilter) { + // For newer versions of jQuery, use an Ajax prefilter to prevent + // auto-executing script tags from untrusted domains. This is similar to the + // fix that is built in to jQuery 3.0 and higher. + $.ajaxPrefilter(function (s) { + if (s.crossDomain) { + s.contents.script = false; + } + }); +} +else if ($.httpData) { + // For the version of jQuery that ships with Drupal core, override + // jQuery.httpData to prevent auto-detecting "script" data types from + // untrusted domains. + var jquery_httpData = $.httpData; + $.httpData = function (xhr, type, s) { + // @todo Consider backporting code from newer jQuery versions to check for + // a cross-domain request here, rather than using Drupal.urlIsLocal() to + // block scripts from all URLs that are not on the same site. + if (!type && !Drupal.urlIsLocal(s.url)) { + var content_type = xhr.getResponseHeader('content-type') || ''; + if (content_type.indexOf('javascript') >= 0) { + // Default to a safe data type. + type = 'text'; + } + } + return jquery_httpData.call(this, xhr, type, s); + }; + $.httpData.prototype = jquery_httpData.prototype; +} + /** * Attach all registered behaviors to a page element. * @@ -137,7 +173,7 @@ Drupal.detachBehaviors = function (context, settings, trigger) { */ Drupal.checkPlain = function (str) { var character, regex, - replace = { '&': '&', '"': '"', '<': '<', '>': '>' }; + replace = { '&': '&', "'": ''', '"': '"', '<': '<', '>': '>' }; str = String(str); for (character in replace) { if (replace.hasOwnProperty(character)) { @@ -168,23 +204,76 @@ Drupal.checkPlain = function (str) { Drupal.formatString = function(str, args) { // Transform arguments before inserting them. for (var key in args) { - switch (key.charAt(0)) { - // Escaped only. - case '@': - args[key] = Drupal.checkPlain(args[key]); - break; - // Pass-through. - case '!': - break; - // Escaped and placeholder. - case '%': - default: - args[key] = Drupal.theme('placeholder', args[key]); - break; + if (args.hasOwnProperty(key)) { + switch (key.charAt(0)) { + // Escaped only. + case '@': + args[key] = Drupal.checkPlain(args[key]); + break; + // Pass-through. + case '!': + break; + // Escaped and placeholder. + default: + args[key] = Drupal.theme('placeholder', args[key]); + break; + } } - str = str.replace(key, args[key]); } - return str; + + return Drupal.stringReplace(str, args, null); +}; + +/** + * Replace substring. + * + * The longest keys will be tried first. Once a substring has been replaced, + * its new value will not be searched again. + * + * @param {String} str + * A string with placeholders. + * @param {Object} args + * Key-value pairs. + * @param {Array|null} keys + * Array of keys from the "args". Internal use only. + * + * @return {String} + * Returns the replaced string. + */ +Drupal.stringReplace = function (str, args, keys) { + if (str.length === 0) { + return str; + } + + // If the array of keys is not passed then collect the keys from the args. + if (!$.isArray(keys)) { + keys = []; + for (var k in args) { + if (args.hasOwnProperty(k)) { + keys.push(k); + } + } + + // Order the keys by the character length. The shortest one is the first. + keys.sort(function (a, b) { return a.length - b.length; }); + } + + if (keys.length === 0) { + return str; + } + + // Take next longest one from the end. + var key = keys.pop(); + var fragments = str.split(key); + + if (keys.length) { + for (var i = 0; i < fragments.length; i++) { + // Process each fragment with a copy of remaining keys. + fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0)); + } + } + + return fragments.join(args[key]); }; /** @@ -251,7 +340,7 @@ Drupal.t = function (str, args, options) { * A translated string. */ Drupal.formatPlural = function (count, singular, plural, args, options) { - var args = args || {}; + args = args || {}; args['@count'] = count; // Determine the index of the plural form. var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1); diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info index 67ebdc00..e8645d1f 100644 --- a/modules/aggregator/aggregator.info +++ b/modules/aggregator/aggregator.info @@ -7,8 +7,8 @@ files[] = aggregator.test configure = admin/config/services/aggregator/settings stylesheets[all][] = aggregator.css -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module index 70f8c5cd..02c9ec46 100644 --- a/modules/aggregator/aggregator.module +++ b/modules/aggregator/aggregator.module @@ -455,6 +455,14 @@ function aggregator_save_category($edit) { db_delete('aggregator_category') ->condition('cid', $edit['cid']) ->execute(); + // Remove category from feeds. + db_delete('aggregator_category_feed') + ->condition('cid', $edit['cid']) + ->execute(); + // Remove category from feed items. + db_delete('aggregator_category_item') + ->condition('cid', $edit['cid']) + ->execute(); // Make sure there is no active block for this category. if (module_exists('block')) { db_delete('block') diff --git a/modules/aggregator/aggregator.test b/modules/aggregator/aggregator.test index d84ee785..afa791d6 100644 --- a/modules/aggregator/aggregator.test +++ b/modules/aggregator/aggregator.test @@ -418,7 +418,7 @@ class CategorizeFeedTestCase extends AggregatorTestCase { } /** - * Creates a feed and makes sure you can add more than one category to it. + * Creates a feed and makes sure you can add/delete categories to it. */ function testCategorizeFeed() { @@ -448,7 +448,31 @@ class CategorizeFeedTestCase extends AggregatorTestCase { // Assert the feed has two categories. $this->getFeedCategories($db_feed); $this->assertEqual(count($db_feed->categories), 2, 'Feed has 2 categories'); + + // Use aggregator_save_feed() to delete a category. + $category = reset($categories); + aggregator_save_category(array('cid' => $category->cid)); + + // Assert that category is deleted. + $db_category = db_query("SELECT COUNT(*) FROM {aggregator_category} WHERE cid = :cid", array(':cid' => $category->cid))->fetchField(); + $this->assertFalse($db_category, format_string('The category %title has been deleted.', array('%title' => $category->title))); + + // Assert that category has been removed from feed. + $categorized_feeds = db_query("SELECT COUNT(*) FROM {aggregator_category_feed} WHERE cid = :cid", array(':cid' => $category->cid))->fetchField(); + $this->assertFalse($categorized_feeds, format_string('The category %title has been removed from feed %feed_title.', array('%title' => $category->title, '%feed_title' => $feed['title']))); + + // Assert that no broken links (associated with the deleted category) + // appear on one of the other category pages. + $this->createSampleNodes(); + $this->drupalGet('admin/config/services/aggregator'); + $this->clickLink('update items'); + $categories = $this->getCategories(); + $category = reset($categories); + $this->drupalGet('aggregator/categories/' . $category->cid); + global $base_path; + $this->assertNoRaw(','); } + } /** @@ -685,9 +709,21 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase { } } + // Delete category from feed items when category is deleted. + $cid = reset($feed->categories); + $categories = $this->getCategories(); + $category_title = $categories[$cid]->title; + + // Delete category. + aggregator_save_category(array('cid' => $cid)); + + // Assert category has been removed from feed items. + $categorized_count = db_query("SELECT COUNT(*) FROM {aggregator_category_item} WHERE cid = :cid", array(':cid' => $cid))->fetchField(); + $this->assertFalse($categorized_count, format_string('The category %title has been removed from feed items.', array('%title' => $category_title))); // Delete feed. $this->deleteFeed($feed); } + } /** diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info index 49838960..e6d5a0a7 100644 --- a/modules/aggregator/tests/aggregator_test.info +++ b/modules/aggregator/tests/aggregator_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/block/block.info b/modules/block/block.info index 9e47f1ff..934bfdea 100644 --- a/modules/block/block.info +++ b/modules/block/block.info @@ -6,8 +6,8 @@ core = 7.x files[] = block.test configure = admin/structure/block -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/block/block.module b/modules/block/block.module index 73e11621..d68ea9e7 100644 --- a/modules/block/block.module +++ b/modules/block/block.module @@ -432,23 +432,20 @@ function _block_rehash($theme = NULL) { drupal_alter('block_info', $current_blocks, $theme, $code_blocks); foreach ($current_blocks as $module => $module_blocks) { foreach ($module_blocks as $delta => $block) { - if (!isset($block['pages'])) { - // {block}.pages is type 'text', so it cannot have a - // default value, and not null, so we need to provide - // value if the module did not. - $block['pages'] = ''; - } - // Make sure weight is set. - if (!isset($block['weight'])) { - $block['weight'] = 0; - } + // Make sure certain attributes are set. + $block += array( + 'pages' => '', + 'weight' => 0, + 'status' => 0, + ); + // Check for active blocks in regions that are not available. if (!empty($block['region']) && $block['region'] != BLOCK_REGION_NONE && !isset($regions[$block['region']]) && $block['status'] == 1) { drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $block['info'], '%region' => $block['region'])), 'warning'); // Disabled modules are moved into the BLOCK_REGION_NONE later so no // need to move the block to another region. $block['status'] = 0; } - // Set region to none if not enabled and make sure status is set. + // Set region to none if not enabled. if (empty($block['status'])) { $block['status'] = 0; $block['region'] = BLOCK_REGION_NONE; diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info index ef1f7138..d7e22203 100644 --- a/modules/block/tests/block_test.info +++ b/modules/block/tests/block_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/block/tests/themes/block_test_theme/block_test_theme.info b/modules/block/tests/themes/block_test_theme/block_test_theme.info index be82747e..31b43824 100644 --- a/modules/block/tests/themes/block_test_theme/block_test_theme.info +++ b/modules/block/tests/themes/block_test_theme/block_test_theme.info @@ -13,8 +13,8 @@ regions[footer] = Footer regions[highlighted] = Highlighted regions[help] = Help -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/blog/blog.info b/modules/blog/blog.info index 0302f22f..84ad946d 100644 --- a/modules/blog/blog.info +++ b/modules/blog/blog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = blog.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/book/book.info b/modules/book/book.info index 396bd669..53e454bf 100644 --- a/modules/book/book.info +++ b/modules/book/book.info @@ -7,8 +7,8 @@ files[] = book.test configure = admin/content/book/settings stylesheets[all][] = book.css -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/color/color.info b/modules/color/color.info index 2b588106..0d17ce11 100644 --- a/modules/color/color.info +++ b/modules/color/color.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = color.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/comment/comment.info b/modules/comment/comment.info index 69885dbb..5d5abbf4 100644 --- a/modules/comment/comment.info +++ b/modules/comment/comment.info @@ -9,8 +9,8 @@ files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/contact/contact.info b/modules/contact/contact.info index 464c2246..b365daf9 100644 --- a/modules/contact/contact.info +++ b/modules/contact/contact.info @@ -6,8 +6,8 @@ core = 7.x files[] = contact.test configure = admin/structure/contact -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/contact/contact.module b/modules/contact/contact.module index 9a48f231..9c6671a9 100644 --- a/modules/contact/contact.module +++ b/modules/contact/contact.module @@ -234,7 +234,14 @@ function contact_form_user_profile_form_alter(&$form, &$form_state) { * Implements hook_user_presave(). */ function contact_user_presave(&$edit, $account, $category) { - $edit['data']['contact'] = isset($edit['contact']) ? $edit['contact'] : variable_get('contact_default_status', 1); + if (isset($edit['contact'])) { + // Set new value. + $edit['data']['contact'] = $edit['contact']; + } + elseif (!isset($account->data['contact'])) { + // Use default if none has been set. + $edit['data']['contact'] = variable_get('contact_default_status', 1); + } } /** diff --git a/modules/contact/contact.test b/modules/contact/contact.test index 6693b574..6a1674a0 100644 --- a/modules/contact/contact.test +++ b/modules/contact/contact.test @@ -346,6 +346,28 @@ class ContactPersonalTestCase extends DrupalWebTestCase { $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); $this->assertResponse(200); + // Test that users can disable their contact form. + $this->drupalLogin($this->contact_user); + $edit = array('contact' => FALSE); + $this->drupalPost('user/' . $this->contact_user->uid . '/edit', $edit, 'Save'); + $this->drupalLogout(); + $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); + $this->assertResponse(403); + + // Test that user's contact status stays disabled when saving. + $contact_user_temp = user_load($this->contact_user->uid, TRUE); + user_save($contact_user_temp); + $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); + $this->assertResponse(403); + + // Test that users can enable their contact form. + $this->drupalLogin($this->contact_user); + $edit = array('contact' => TRUE); + $this->drupalPost('user/' . $this->contact_user->uid . '/edit', $edit, 'Save'); + $this->drupalLogout(); + $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); + $this->assertResponse(200); + // Revoke the personal contact permission for the anonymous user. user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access user contact forms')); $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info index b57e9f67..ba47a4cb 100644 --- a/modules/contextual/contextual.info +++ b/modules/contextual/contextual.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = contextual.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info index d17a9740..d6e98660 100644 --- a/modules/dashboard/dashboard.info +++ b/modules/dashboard/dashboard.info @@ -7,8 +7,8 @@ files[] = dashboard.test dependencies[] = block configure = admin/dashboard/customize -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info index 89b66c11..cb85f811 100644 --- a/modules/dblog/dblog.info +++ b/modules/dblog/dblog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = dblog.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/field.info b/modules/field/field.info index d19c29d1..e05108ec 100644 --- a/modules/field/field.info +++ b/modules/field/field.info @@ -11,8 +11,8 @@ dependencies[] = field_sql_storage required = TRUE stylesheets[all][] = theme/field.css -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info b/modules/field/modules/field_sql_storage/field_sql_storage.info index a35372a8..05434613 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.info +++ b/modules/field/modules/field_sql_storage/field_sql_storage.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = field_sql_storage.test required = TRUE -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info index 0cd4939c..bef7e4a2 100644 --- a/modules/field/modules/list/list.info +++ b/modules/field/modules/list/list.info @@ -7,8 +7,8 @@ dependencies[] = field dependencies[] = options files[] = tests/list.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info index 4bd2dae2..2d4d6cce 100644 --- a/modules/field/modules/list/tests/list_test.info +++ b/modules/field/modules/list/tests/list_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info index d3c995e5..c65d94ae 100644 --- a/modules/field/modules/number/number.info +++ b/modules/field/modules/number/number.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = number.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info index d395377a..632ca24f 100644 --- a/modules/field/modules/options/options.info +++ b/modules/field/modules/options/options.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = options.test -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info index 678bdab3..fe93a35a 100644 --- a/modules/field/modules/text/text.info +++ b/modules/field/modules/text/text.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = text.test required = TRUE -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info index 07eed538..ce3c7251 100644 --- a/modules/field/tests/field_test.info +++ b/modules/field/tests/field_test.info @@ -6,8 +6,8 @@ files[] = field_test.entity.inc version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-02-01 -version = "7.54" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1485986921" +datestamp = "1522264019" diff --git a/modules/field/theme/field.tpl.php b/modules/field/theme/field.tpl.php index f0f9d583..460fd2e2 100644 --- a/modules/field/theme/field.tpl.php +++ b/modules/field/theme/field.tpl.php @@ -4,8 +4,10 @@ * @file field.tpl.php * Default template implementation to display the value of a field. * - * This file is not used and is here as a starting point for customization only. - * @see theme_field() + * This file is not used by Drupal core, which uses theme functions instead for + * performance reasons. The markup is the same, though, so if you want to use + * template files rather than functions to extend field theming, copy this to + * your custom theme. See theme_field() for a discussion of performance. * * Available variables: * - $items: An array of field values. Use render() to output them. @@ -45,7 +47,7 @@ */ ?>