Improve processing of uploaded images

As mentioned in dev chat on May 15 there are quite a few “stalled” tickets on Trac dealing with image processing/resizing after uploading:

All of these, and more, can be “unblocked” by: Save progress of intermediate image creation after upload #40439.

Fixing this will also enable “refreshing” of the way we do responsive images, and will enable improvements in how we generally work with images in the block editor. Then we will be able to enhance the Image block and make it “just work” regardless of the context, see Enhancement: images handling and more importantly https://github.com/WordPress/gutenberg/issues/6177#issuecomment-442953527.

In short: fixing the above tickets will greatly improve user experience especially when uploading large images or the server is slow/busy. It will also open the way for enhancing how we work with images in the editor, and let us show better fitting images on the front-end.

#media, #upload

Dev Chat Agenda: May 22

Below is the agenda for the weekly devchat meeting on Wednesday, May 22, 2019, 2000 UTC.

  • Announcements
  • 5.2.1 Debrief
  • 5.2.2 Planning
    • Call for release leads
  • 5.3
  • Calls from component maintainers
  • Open Floor

If you have anything to propose for the agenda or specific items related to those listed above, please leave a comment below.

This meeting is held in the #core channel in the Making WordPress Slack.

#agenda, #devchat

#5-3, #5-2, #5-2-1, #core

Dev Chat Summary: 22 May

@chanthaboune served as the facilitator for discussion and many contributors were in attendance.

Announcements

Nothing major to announce this week. Tune in next!

5.2.1 Debrief

WordPress 5.2.1 released yesterday! For information on the release you may refer to the 5.2.1 blog post. Thanks to @desrosj and @earnjam for leading such a smooth release. As of now, there are no notable issues. If you are seeing any issues, please discuss in the comments below or create a new ticket at: https://core.trac.wordpress.org/.

5.2.2

There are a handful of tickets in the 5.2.2 milestone. A team is needed to help wrangle those tickets into a new release. Now is the time to volunteer for leading 5.2.2. This release would aim to be for a 2 week release cycle to clear up remaining tickets in the milestone. There were two volunteers to lead in chat today: @audrasjb and @justinahinon. Please volunteer in the comments below if you are also interested in leading or co-leading!

@aduth said there was mention of a few issues in #core-editor chat earlier today of Gutenberg bugs which would be nice to aim to include for the release: https://wordpress.slack.com/archives/C02QB2JS7/p1558530408162500

Major release (5.3)

Comments were closed today in the call for 5.3 tickets post. @chanthaboune will be pulling those together the submissions and do some outreach to maintainers that have not included items to the post as we prepare for the next major release. These tickets will inform what focuses this release will have.

Calls from component maintainers

@azaozz, is continuing to plan for some recommended changes and focuses for the Uploads and Media components.

@desrosj reminded us that the following components: General Component, Comments, Pings/Trackbacks, External Libraries, Filesystem API, Rewrite Rules, and Script Loader are all currently without any maintainers. If those parts of core interest you, feel free to reach out to @chanthaboune to get involved!

@karmatosed mentioned that there is an editor component triage on Friday at 17:00 UTC, @desrosj and @karmatosed will be running it in #core-editor and the triage will focus on trac tickets.

@johnbillion asked if there were any component maintainers looking for new maintainers of their components and @chanthaboune made the important reminder, “open source is designed to let people move in and out of volunteer positions as needed” If you are not comfortable saying in dev chat that you would like to make changes, please feel free to reach out privately to @chanthaboune or other co-maintainers.

Open Floor

There was an ask by @afragen to have a committer review https://core.trac.wordpress.org/ticket/46938 He also reminded us committers are not the only ones with valuable feedback. Please direct any thoughts about the issue to the ticket, even if you are not one. 🙂

#5-3, #5-2, #5-2-1, #devchat, #summary

Fatal Error Recovery Mode in 5.2

WordPress 5.2 will allow administrators to fix or mitigate fatal errors on their site that would previously have been impossible to address without developer interference and modifying the codebase. Even in the case where a fatal error would commonly have made the backend completely inaccessible (for example through a so-called “white screen of death”), administrators will now still have the chance to log in and do something about the issue.

When a fatal error occurs, a user-facing error screen will display that informs the user/visitor that the site is experiencing technical difficulties. More importantly though, when such an error occurs, an email will be sent to the admin email address, informing about the issue and including a secret link to new feature called the “recovery mode”. Clicking this link will have the user enter this recovery mode, which works by placing a cookie on the current client.

When in recovery mode, plugins and themes (also referred to as “extensions”) which are causing a fatal error are paused for that client, ensuring they can work around these errors and access their admin backend as regularly. After entering recovery mode, the user needs to log in. It should be highlighted though that recovery mode itself is not tied to a specific user, but only to the cookie existing on the client.

After logging in, an admin notice will indicate that recovery mode is enabled. Furthermore, the user will be informed about which plugins/themes are currently paused due to fatal errors, and what exactly these errors are. They then have the possibility to address the issue in their preferred way:

  • They can completely deactivate the extension, e.g. when maintaining a working version of the site matters more than that extension’s functionality. This is typically a temporary solution, but provides an immediate resolution.
  • They can fix the problem if they have the technical capabilities, and afterwards resume the extension.
  • They can file a support ticket with the author of the respective extension or contact a developer, pointing out the exact error.

At any time, the user can decide to exit recovery mode, by clicking a button that permanently appears in the admin bar while in recovery mode. Exiting recovery mode will wipe the cookie from the client and thus cause all extensions to run as usual again. Keep in mind that if an extension is still broken, the fatal error will remain.

Admin backend while in recovery mode. Highlighted are the notice and the exit button in the admin bar, indicating recovery mode is active.
Admin backend while in recovery mode

The main benefit of recovery mode is to inform administrators about fatal errors on their site and allow them to still access their backend and decide what to do about the problem, rather than presenting them with the typical “white screen of death” which they cannot do anything about. It is impossible to automatically fix such errors, but recovery mode allows working around them by pausing the broken extensions. Pausing only happens for the client that is in recovery mode, and thus does not have any global implications. With a broken extension, only the user in recovery mode can access the broken areas; for the other users the site remains in a broken state until the issue has been fixed or mitigated.

Developers

There are a couple of ways that developers can integrate with the new recovery mode features:

  • Plugins that would like to enhance recovery mode can call a new function wp_is_recovery_mode() to check for whether it is active.
  • Environments can override the way that recovery mode is set up and validated if they prefer to use a different method or to purely enable it via code. A must-use plugin for example can set a constant WP_RECOVERY_MODE_SESSION_ID that needs to contain an arbitrary session ID, which will then be used to store recovery mode-specific data for that session. Having the constant available will force-enable recovery mode. However, this mechanism must be used with special care, as setting the constant unconditionally would result in recovery mode being globally enabled.
  • The template for the screen indicating that a fatal error occurred can be customized by using a php-error.php drop-in, similar to other previously existing drop-ins such as db-error.php.
  • The entire shutdown handler can be overridden by using a fatal-error-handler.php drop-in. This drop-in must return an instance of a class extending the default WP_Fatal_Error_Handler class. If that is the case, the instance will be used instead of the default one.
  • Environments that would like to disable the fatal error handler and recovery mode functionality altogether can do so by setting a WP_DISABLE_FATAL_ERROR_HANDLERconstant, typically in wp-config.php. The enabled status for the handler should be checked for by using a new function wp_is_fatal_error_handler_enabled().

Background

The fatal error recovery mode is a revised approach for what was originally the fatal error protection mechanism slated for WordPress 5.1, but then reverted due to some critical concerns. The client-specific recovery mode mitigates these concerns, so this time it is here to stay.

For further background information, please refer to the announcement post for the revised approach, the overarching Trac ticket, and generally the list of related 5.2 tickets.

#5-2, #dev-notes, #servehappy

#core-privacy April update

This is a cumulative update for #core-privacy office hours and bug scrubs held in April 2019.

Office hours are held every Wednesday at 19:00 UTC in the #core-privacy channel on Making WordPress Slack. Bug scrubs are Mondays at 15:00 UTC.

5.2 release

5.2 has been a monumental team effort by core-privacy. The team has shipped all 24 of its tickets earmarked for the release. These included 15 bugfixes and 9 enhancements.

Special props go to @garrett-eclipse for being the driving force behind the team’s 5.2 ticket success.

The “biggest win” was #44005, introducing the new privacy policy page helpers.

General fixes include:

#46098 – The Privacy Policy guide help notice is now displayed on both the classic editor and the block editor.

#44707 – Users are now able to make additional requests when identical previous requests are in a complete or archived state.

#44644 – The ‘Download Personal Data’ admin action no longer triggers a completion of the request.

Also in 5.2 some privacy nags were removed; post-4.9.6, these notifications had served their purpose:

#45999 – Remove the Privacy Pointer

#46819 – Remove the Privacy Bubble

Some i18N-Privacy wins were:

#44721 – The Personal Data Erasure Fulfillment email is now in the User’s Locale

#46056 – The Personal Data Export email is now in the User’s Locale

Tickets shipped since the March team update included #44175, #44644, #44047, #46819, and #46098. Props @knutsp, @desrosj, @joshuawold, @birgire, @mechter, @subrataemfluence, @xkon, @saimonh, @audrasjb, @dejliglama, @ianbelanger, @iandunn, @pento, @sergeybiryukov.

@earnjam wrote a post in Make/Core on the developer-focused privacy updates in 5.2.

@williampatton wrote a dev note in Make/Themes on the new privacy policy page helpers coming in 5.2.

5.3: export and erasure

For 5.3, @xkon would like the team to focus on finalising all outstanding issues with export and erasure requests. @audrasjb has given @xkon access to his repo for the front-end forms for export and erasure, with a view to using this as our first team feature plugin. (#44013)

5.3: privacy notice updates

The team has discussed #44538, #44669, #46687 as an opportunity for collaboration with the #design team.

Plugin privacy audit

@idea15 has finished writing beta version 1 of the plugin privacy audit workflow, with the help of feedback from many team members and plugin developers. Please feel free to test the workflow on your plugin and provide the team with feedback in #core-privacy.

WordCamp Europe

@idea15 has signed up for a slot for the team at the WP Cafe at WCEU. This will be a friendly hangout and chat space with no set agenda.

As with last year, #core-privacy will have a team table at the WCEU contributor day. As with last year, @idea15 @xkon @pputzer @postphotos will take turns secretly disconnecting the wi-fi.

Cross-project privacy cooperation

Members of the #core-privacy team who participate in the cross-project privacy initiative will be participating in the Mozilla Global Sprint in May to standardise file formats for data portability exports and imports across our CMSes, and to identify the export and import functionality which may need to be created within each project. All are welcome to join in. Dates TBC.

Conference talks

New on WPTV:

@rhyswynne at WordCamp Edinburgh 2018: How to integrate the 4.9.6 privacy features into your plugin

@mainplus at WordCamp Belfast 2018: Follow the data

@riankinney at WordCamp Rome 2018: The differences between U.S. and EU privacy law

New talks:

@idea15 participated remotely in a privacy BOF at Drupalcon Seattle on behalf of the #core-privacy team.

@pputzer gave an outstanding talk at WordCamp Vienna on 27 April focusing on active #core-privacy tickets from a developer/site owner perspective. The slides are available here.

Other matters:

@javorszky started a review of the wp.org privacy policies which is currently active and available for discussion & review here.

Editor Chat Agenda: May 22nd

This is the agenda for the weekly editor chat meeting on Wednesday, 22nd May 2019, 13:00 UTC.

  • Tasks Coordination
  • Open Floor

This meeting is held in the #core-editor channel in the Making WordPress Slack.

If you have anything to propose for the agenda or specific items related to those listed above, please leave a comment below.

#agenda, #core-editor, #editor-chat

Site Health Check in 5.2

WordPress 5.2 will include two new pages in the admin interface to help end users to self-service their site through common configuration issues and other elements that go along with having a healthy online presence. It also provides a standardized location for developers to add debugging information.

The new pages can be found under the Tools menu, as Site Health, and presents the user with a fresh new admin interface. As we hope users will regularly ensure their site is up to standards, focus has been put on creating an interface you want to return to in the future.

Site Health Status

Screenshot of the WordPress Site Health Status page

The first page runs a series of tests on the user’s site, and will be categorized as critical, recommended, or good responses. These outcomes also affect the percentage of completion you have (where critical is weighted more heavily than recommended).

Each test result can be expanded to get an explanation of what you as a user should be paying attention to, and which problems are there if any, that need addressing.

Most of the bundled tests will also have actionable items, and provide links directly to the appropriate areas of your dashboard where you can improve upon the relevant settings.

Filtering the Tests

The tests are filterable via site_status_tests, meaning plugins or themes may add their own tests, or remove existing ones. We’ve also split these into two different types of tests: direct  and async. This was done as some tests may require more time to run, so to avoid potential timeouts within admin pages, any tests added to the async section will be run in succession via AJAX calls after the page is loaded.

Specifically of interest to server admins is the companion filter site_status_test_php_modules, which is based off the WordPress Hosting Team list of recommended and required PHP extensions.

Removing a Test

An example of a filter use would be a hosting provider that does automated updates. They may wish to remove the test for background updates being enabled or disabled as follows:

function myhost_remove_update_check( $tests ) {
	unset( $tests['async']['background_updates'] );
	return $tests;
}
add_filter( 'site_status_tests', 'myhost_remove_update_check' );

Adding a Test

This is an example of how a caching plugin might check to ensure that it’s cache setting is enabled.

<?php
function myplugin_add_caching_test( $tests ) {
	$tests['direct']['caching_plugin'] = array(
		'label' => __( 'My Caching Test' ),
		'test'  => 'myplugin_caching_test',
	);
	return $tests;
}
add_filter( 'site_status_tests', 'myplugin_add_caching_test' );

function myplugin_caching_test() {
	$result = array(
		'label'       => __( 'Caching is enabled' ),
		'status'      => 'good',
		'badge'       => array(
			'label' => __( 'Performance' ),
			'color' => 'orange',
		),
		'description' => sprintf(
			'<p>%s</p>',
			__( 'Caching can help load your site more quickly for visitors.' )
		),
		'actions'     => '',
		'test'        => 'caching_plugin',
	);

	if ( ! myplugin_caching_is_enabled() ) {
		$result['status'] = 'recommended';
		$result['label'] = __( 'Caching is not enabled' );
		$result['description'] = sprintf(
			'<p>%s</p>',
			__( 'Caching is not currently enabled on your site. Caching can help load your site more quickly for visitors.' )
		);
		$result['actions'] .= sprintf(
			'<p><a href="%s">%s</a></p>',
			esc_url( admin_url( 'admin.php?page=cachingplugin&action=enable-caching' ) ),
			__( 'Enable Caching' )
		);
	}

	return $result;
}

myplugin_add_caching_test() is hooked to the site_status_tests filter. It adds a new test called caching_plugin to the direct tests list. The value of test in this array is the function that will be called when the tests run on the Site Health Status page.

Note: If you add a test to the async test list, then you will also need to register the test function as an AJAX action using the wp_ajax_{$action} hook.

The test function should return an array with data about the result of the test. This array includes:

  • label: What the header of the section should say.
  • status: Section the result should be displayed in. Possible values are good, recommended, or critical.
  • badge: Array containing:
    • label: What the badge should say.
    • color: Applies a CSS class with this value to the badge. Core styles support blue, green, red, orange, purple and gray.
  • description: Additional details about the results of the test.
  • actions: A link or button to allow the end user to take action on the result.
  • test: The name of the test.

In the above example, the test function, myplugin_caching_test() sets an initial baseline value for the result, and then overrides portions as needed if the call to its internal function myplugin_caching_is_enabled() returns false.

Site Health Info

Screenshot of the WordPress Site Health Information page

The Information tab is meant for debug purposes. It provides a plethora of information about the website and server setup for sharing when looking for support in various locations, alongside a button to quickly copy any non-private information so you can easily paste this to others.

The page is split up into sections. Plugins and themes may introduce their own entries to this page using the debug_information filter, either by adding entries to existing sections, or by creating their own sections.

As mentioned, the copied information only includes non-private information, this can of course be subjective, and is therefore also included in the filter. Marking either a full section, or just individual entries as private can be done by setting the corresponding $private value to true.

For example, the database prefix is shown under the Database section, and is marked as private, so when I go to copy all the information, it’s not there:

Example of the database section of the Site Health Information page

The content that gets added to the clipboard for the entire Database section is shown below:

### Database ###

Extension: mysqli
Server version: 5.5.5-10.1.38-MariaDB-1~jessie
Client version: mysqlnd 5.0.12-dev - 20150407 - $Id: 7cc7cc96e675f6d72e5cf0f267f48e167c2abb23 $

A security plugin may for example think that any database information is always seen as private, and would filter this in the following way:

function secplugin_remove_database_info( $debug_info ) {
	$debug_info['wp-database']['private'] = true;
	return $debug_info;
}
add_filter( 'debug_information', 'secplugin_remove_database_info' );

Adding a new section may also be of interest. The example below adds your own plugin and its license key, but marks it as private, to the list:

function myplugin_add_debug_info( $debug_info ) {
	$debug_info['my-plugin-slug'] = array(
		'label'    => __( 'My Plugin', 'my-plugin-slug' ),
		'fields'   => array(
			'license' => array(
				'label'    => __( 'License', 'my-plugin-slug' ),
				'value'   => get_option( 'my-plugin-license', __( 'No license found', 'my-plugin-slug' ) ),
				'private' => true,
			),
		),
	);

	return $debug_info;
}
add_filter( 'debug_information', 'myplugin_add_debug_info' );

Each new section that’s added should use your plugin or theme slug to avoid name collisions. All core entries are prefixed with wp-.

All debug information is added in an unescaped manner, the Information page will run all data through wp_kses, and only allows a, strong, em and span tags (used for emphasis or linking to documentation).
Debug information is expected to be plain text, and is escaped before showing on the page. The displayed data is ran through esc_html(), and data that can be copied is ran through esc_attr().

#5-2, #dev-notes

WP5.3: Open Call for Tickets

As we were discussing plans for the next major release in last week’s devchat, it was made clear to me that a great first step would be to have an open call for tickets. Although iterating and stabilizing the new block editor is still top of the list, I’d like to open this call for additional high priority items.

Please leave a comment that links to a ticket you think needs some attention in this release cycle. Note: Adding your ticket here won’t necessarily guarantee inclusion. Still, no one can fix things they can’t see, so bravely and kindly share.

#5-3

Dashicons in WordPress 5.2

It’s been over 3 years since Dashicons has been updated (see #34221 from version 4.5). But, they have not been forgotten about! In 5.2, the Dashicons will see several changes, including 13 awesome new icons.

New Build Process

A new build process has been implemented in the Dashicons GitHub repository to make adding new icons easier. Now, when SVG files are added for new icons they are automatically included in the font and CSS files. This change will not be noticeable from the WordPress Core code base, but it’s worth noting.

New Font File Format: WOFF 2.0

This release will see the introduction of a new font file format, WOFF2 (Web Open Font Format 2). WOFF2 is a more modern replacement for the original WOFF 1.0 format that uses an improved compression, which results in lower network consumption.

WOFF2 is supported by all modern browsers, but is not supported in Internet Explorer.

WOFF 1.0 Format

The WOFF 1.0 file will remain in WordPress Core to ensure backwards compatibility for plugins and themes loading the wp-includes/fonts/dashicons.woff file directly. This file has not been updated to include the new icons below. The new build process currently only allows one WOFF format file to be built. Since WOFF2 is more modern, that is the file format being built moving forward.

However, WOFF 1.0 is compiled and included as an embedded font directly in the dashicons.css file. The embedded WOFF format has been updated to include the new icons. If you wish to use the new Dashicons and require the WOFF 1.0 format for IE support, it is recommended that you use the dashicons.css file included in core to define the Dashicons font face.

Alternatively, you can use the Embedded OpenType format file at wp-includes/fonts/dashicons.eot (supported by all versions of IE). This file does include the new icons.

New Icons

In 5.2, 13 completely new icons were added. However, 18 additional icons that were previously included in the font files but did not have a corresponding CSS declaration are now available. These icons are marked with an asterisk (*) below.

Buddicons

The Buddicons were all previously included in the icon font, but each is now accompanied by new a dashicons-buddicons-* class.

Icon CSS Class Code
dashicons-buddicons-activity * f452
dashicons-buddicons-bbpress-logo * f477
dashicons-buddicons-buddypress-logo * f448
dashicons-buddicons-community * f453
dashicons-buddicons-forums * f449
dashicons-buddicons-friends * f454
dashicons-buddicons-groups * f456
dashicons-buddicons-pm * f457
dashicons-buddicons-replies * f451
dashicons-buddicons-topics * f450
dashicons-buddicons-tracking * f455

Editor

Icon CSS Class Code
dashicons-editor-ol-rtl f12c
dashicons-editor-ltr f10c

Core Teams

Three new icons have been introduced for some newer teams: Tide, REST API, and Coding Standards.

Icon CSS Class Code
dashicons-tide f10d
dashicons-rest-api f124
dashicons-code-standards f13a

Sites

With the introduction of 3 new icons in 5.2, there are now 4 total site icons. No matter where you are located in the world, there is now an icon for you! (GH-95)

Icon CSS Class Code
dashicons-admin-site-alt f11d
dashicons-admin-site-alt2 f11e
dashicons-admin-site-alt3 f11f

Menus

Icon CSS Class Code
dashicons-menu-alt * f228
dashicons-menu-alt2 * f329
dashicons-menu-alt3 * f349

Social

Icon CSS Class Code
dashicons-instagram f12d

Miscellaneous

Icon CSS Class Code
dashicons-businesswoman f12f
dashicons-businessperson f12e
dashicons-email-alt2 f467
dashicons-yes-alt f12a
dashicons-camera-alt * f129
dashicons-plugins-checked * f485
dashicons-update-alt * f113
dashicons-text-page * f121

A very special thanks goes out to @joen, @empireoflight, @folletto, @netweb, @aduth, @dsifford, @SergioEstevao, @cathibosco1, @jaymanpandya, @oztaser, @ryelle, @joshuawold, @nateallen, @desrosj, @bahia0019, and @liljimmi for their contributions to Dashicons since the last update!

To get a complete overview of all icons please visit developer.wordpress.org/resource/dashicons/.

#5-2, #dashicons, #dev-notes, #ui

Security in 5.2

Post originally written by Scott Arciszewski.

Protection Against Supply-Chain Attacks

Starting with WordPress 5.2, your website will remain secure even if the wordpress.org servers get hacked.

We are now cryptographically signing WordPress updates with a key that is held offline, and your website will verify these signatures before applying updates.

Signature Verification in WordPress 5.2

When your WordPress site installs an automatic update, from version 5.2 onwards it will first check for the existence of an x-content-signature header. If one isn’t provided by our update server, your WordPress site will instead query for a filenamehere.sig file and parse it.

The signatures were calculated using Ed25519 of the SHA384 hash of the file’s contents. The signature is then base64-encoded for safe transport, no matter how it’s delivered.

The signing keys used to release updates are managed by the WordPress.org core development team. The verification key for the initial release of WordPress 5.2 is fRPyrxb/MvVLbdsYi+OOEv4xc+Eqpsj+kkAS6gNOkI0= (expires April 1, 2021).

(For the sake of specificity: Signing key here means Ed25519 secret key, while verification key means Ed25519 public key.)

To verify an update file, your WordPress site will calculate the SHA384 hash of the update file and then verify the Ed25519 signature of this hash. If you’re running PHP 7.1 or older and have not installed the Sodium extension, the signature verification code is provided by sodium compat.

Our signature verification is implemented in the new verify_file_signature() function, inside wp-admin/includes/file.php.

Modern Cryptography for WordPress Plugins

The inclusion of sodium_compat on WordPress 5.2 means that plugin developers can start to migrate their custom cryptography code away from mcrypt (which was deprecated in PHP 7.1, and removed in PHP 7.2) and towards libsodium.

Example Functions

<?php
/**
 * @param string $message
 * @param string $key
 * @return string
 */
function wp_custom_encrypt( $message, $key )
{
    $nonce = random_bytes(24);
    return base64_encode(
        $nonce . sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
            $message,
            $nonce,
            $nonce,
            $key
        )
    );
}

/**
 * @param string $message
 * @param string $key
 * @return string
 */
function wp_custom_decrypt( $message, $key )
{
    $decoded = base64_decode($message);
    $nonce = substr($decoded, 0, 24);
    $ciphertext = substr($decoded, 24);
    return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
        $ciphertext,
        $nonce,
        $nonce,
        $key
    );
}

How to Seamlessly and Securely Upgrade your Plugins to Use the New Cryptography APIs

If your plugin uses encryption provided by the abandoned mcrypt extension, there are two strategies for securely migrating your code to use libsodium.

Strategy 1: All Data Decryptable at Run-Time

If you can encrypt/decrypt arbitrary records, the most straightforward thing to do is to use mcrypt_decrypt() to obtain the plaintext, then re-encrypt your code using libsodium in one sitting.

Then remove the runtime code for handling mcrypt-encrypted messages.

<?php
// Do this in one sitting
$plaintext = mcrypt_decrypt( $mcryptCipher, $oldKey, $ciphertext, $mode, $iv );
$encrypted = wp_custom_encrypt( $plaintext, $newKey );

Strategy 2: Only Some Data Decryptable at Run-Time

If you can’t decrypt all records at once, the best thing to do is to immediately re-encrypt everything using sodium_crypto_secretbox() and then, at a later time, apply the mcrypt-flavored decryption routine (if it’s still encrypted).

<?php
/**
 * Migrate legacy ciphertext to libsodium
 * 
 * @param string $message
 * @param string $newKey
 * @return string
 */
function wp_migrate_encrypt( $message, $newKey )
{
    return wp_custom_encrypt(
        'legacy:' . base64_encode($message),
        $newKey
    );
}

/**
 * @param string $message
 * @param string $newKey
 * @param string $oldKey
 * @return string 
 */
function wp_migrate_decrypt( $message, $newKey, $oldKey )
{ 
    $plaintext = wp_custom_decrypt($message, $newKey);
    if ( substr($plaintext, 0, 7) === 'legacy:' ) {
        $decoded = base64_decode( substr($plaintext, 7) );
        if ( is_string($decoded) ) {
            // Now apply your mcrypt-based decryption code
            $plaintext = mcrypt_decrypt( $mcryptCipher, $oldKey, $decoded, $mode, $iv );

            // Call a re-encrypt routine here
        }
    }
    return $plaintext;
}

Avoid Opportunistic Upgrades

A common mistake some developers make is to try to do an “opportunistic” upgrade: Only perform the decrypt-then-re-encrypt routine on an as-needed basis. This is a disaster waiting to happen, and there is a lot of historical precedence to this.

Of particular note, Yahoo made this mistake, and as a result, had lots of MD5 password hashing lying around their database when they were breached, even though their active users had long since upgraded to bcrypt.

Detailed technical information about this new security feature, written by Paragon Initiative Enterprises (the cryptography team that developed it) are available here.

#5-2 #dev-notes