Resave method not implemented

Created on 8 August 2019, almost 6 years ago
Updated 17 October 2023, over 1 year ago

Problem/Motivation

When a webform submission is saved, it is encrypted in the database. However if the resave method is called, the original, unencrypted data is saved to the database.

Proposed resolution

Implement WebformSubmissionInterface::resave() to encrypt the data as well.

Remaining tasks

  1. Review
  2. Commit

User interface changes

None

API changes

WebformEncryptSubmissionStorage will implement the resave() method.

Data model changes

None

Release notes snippet

TBD

Original issue description:

When calling the resave-method on the WebformSubmission entity inside a Webform handler, the un-encrypted data gets saved to the database because that method is not implemented by WebformEncryptSubmissionStorage.
In order to prevent multiple encryptions (multiple handlers can call the resave-method), I implemented a check inside the encrypt-function.

πŸ› Bug report
Status

RTBC

Version

1.0

Component

Code

Created by

πŸ‡§πŸ‡ͺBelgium lammensj

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 10.1.4 + Environment: PHP 8.1 & MySQL 8
    last update over 1 year ago
    8 pass
  • πŸ‡³πŸ‡±Netherlands seanB Netherlands

    Attached is a patch for the 2.x branch.

  • Status changed to Needs work over 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States alfattal Minnesota

    Patch in #14 failed to apply with the following error:

    Could not apply patch! Skipping. The error was: Cannot apply patch https://www.drupal.org/files/issues/2023-10-17/3073426-10-2.x.patch
    Unhandled promise rejection with ArgumentCountError: Too few arguments to function React\Promise\Promise::React\Promise\{closure}(), 0 passed in phar:///usr/local/bin/composer/src/Composer/Installer/InstallationManager.php on line 660 and exactly 1 expected in phar:///usr/local/bin/composer/vendor/react/promise/src/Promise.php:277
    Stack trace:
    #0 phar:///usr/local/bin/composer/src/Composer/Installer/InstallationManager.php(660): React\Promise\Promise::React\Promise\{closure}()
    #1 phar:///usr/local/bin/composer/vendor/react/promise/src/Internal/FulfilledPromise.php(47): Composer\Installer\InstallationManager::Composer\Installer\{closure}()
    #2 phar:///usr/local/bin/composer/src/Composer/Installer/InstallationManager.php(661): React\Promise\Internal\FulfilledPromise->then()
    #3 phar:///usr/local/bin/composer/vendor/react/promise/src/Promise.php(288): Composer\Installer\InstallationManager::Composer\Installer\{closure}()
    #4 phar:///usr/local/bin/composer/vendor/react/promise/src/Promise.php(37): React\Promise\Promise->call()
    #5 phar:///usr/local/bin/composer/src/Composer/Installer/InstallationManager.php(663): React\Promise\Promise->__construct()
    #6 phar:///usr/local/bin/composer/src/Composer/Installer/InstallationManager.php(221): Composer\Installer\InstallationManager->runCleanup()
    #7 phar:///usr/local/bin/composer/src/Composer/Installer.php(791): Composer\Installer\InstallationManager->execute()
    #8 phar:///usr/local/bin/composer/src/Composer/Installer.php(292): Composer\Installer->doInstall()
    #9 phar:///usr/local/bin/composer/src/Composer/Command/InstallCommand.php(147): Composer\Installer->run()
    #10 phar:///usr/local/bin/composer/vendor/symfony/console/Command/Command.php(298): Composer\Command\InstallCommand->execute()
    #11 phar:///usr/local/bin/composer/vendor/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run()
    #12 phar:///usr/local/bin/composer/vendor/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand()
    #13 phar:///usr/local/bin/composer/src/Composer/Console/Application.php(382): Symfony\Component\Console\Application->doRun()
    #14 phar:///usr/local/bin/composer/vendor/symfony/console/Application.php(171): Composer\Console\Application->doRun()
    #15 phar:///usr/local/bin/composer/src/Composer/Console/Application.php(145): Symfony\Component\Console\Application->run()
    #16 phar:///usr/local/bin/composer/bin/composer(88): Composer\Console\Application->run()
    #17 /usr/local/bin/composer(29): require('...')
    #18 {main}
    
    In Patches.php line 331:
                                                                                                                                           
      Cannot apply patch 3073426-14: Resave method not implemented (https://www.drupal.org/files/issues/2023-10-17/3073426-10-2.x.patch)!
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 10.2.x + Environment: PHP 8.1 & MySQL 8
    last update about 1 year ago
    8 pass
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 10.2.1 + Environment: PHP 8.1 & MySQL 8
    last update about 1 year ago
    8 pass
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 10.2.x + Environment: PHP 8.1 & MySQL 8
    last update about 1 year ago
    8 pass
  • πŸ‡¦πŸ‡ΊAustralia tinny

    The patch applies for me and it works fine except that handlers are called.

    I think the `::doPostSave()` method runs the handlers again.

  • πŸ‡¦πŸ‡ΊAustralia tinny

    Instead of doPostSave, all we need is to set the data back to the decrypted data.

    I've updated the patch.

  • Merge request !10Issue #3073426: Implement the resave method β†’ (Open) created by tinny
  • Pipeline finished with Failed
    3 months ago
    Total: 146s
    #436202
  • Pipeline finished with Failed
    3 months ago
    Total: 173s
    #436254
  • Pipeline finished with Failed
    3 months ago
    Total: 184s
    #436260
  • Pipeline finished with Failed
    3 months ago
    Total: 176s
    #436269
  • Status changed to Needs review 15 days ago
  • πŸ‡¬πŸ‡§United Kingdom altcom_neil

    Hello

    I have just run into this problem and wrote my own resave() method as was done here in pretty much the same way.

    However, there is an issue with this solution.

    If you are using cron to process webform submissions programmatically and then update the entity at the end. Because the cron does not have a current user with permission to see the encrypted values the values in the entity object are '[Value Encrypted]' and this is what then gets encrypted and written back into the database. Not the original unencrypted data.

    I guess this issue would be true of any method where a user or programmatic process is updating a submission not just through resave()?

    The only thing I found to go on so far is doing this at the start of the code being triggered by the cron:

        // Call the account switcher service.
        $accountSwitcher = \Drupal::service('account_switcher');
        // Switch to the admin user.
        $accountSwitcher->switchTo(new \Drupal\Core\Session\UserSession(['uid' => 1]));
    

    See https://drupal.stackexchange.com/a/316471

    Then when the code hits then \Drupal\webform_encrypt\WebformEncryptSubmissionStorage::decrypt method the currentUser is the default admin user (1).

    I will have a further investigation tomorrow. It may be that the resave() method needs extra protection against it accidentally overwriting the real data with the encrypted '[Value Encrypted]' string.

    Cheers, Neil

Production build 0.71.5 2024