Problem/Motivation

Currently if we have the same field machine names across different webforms, the webform encrypt setttings would be shared acrross webforms.

Old description:
In the process of writing tests for a project, while trying to save the form to add a new webform field to a webform, the test was failing because of missing webform.encrypt schema.

Proposed resolution

Mofify current schema so that the settings are saved per webform and per field.

Remaining tasks

Do it.

User interface changes

None.

API changes

None.

Data model changes

Database schema changes for the webform settings.

CommentFileSizeAuthor
#45 2921824-45.patch13.36 KBManuel Garcia
#45 interdiff-44-45.txt909 bytesManuel Garcia
#44 2921824-44.patch13.38 KBManuel Garcia
#44 interdiff-39-44.txt9.42 KBManuel Garcia
#43 Screenshot from 2017-11-20 09-04-55.png40.97 KBManuel Garcia
#39 2921824-39.patch12.61 KBManuel Garcia
#39 interdiff-37-39.patch654 bytesManuel Garcia
#37 2921824-37.patch12.62 KBManuel Garcia
#37 interdiff-35-37.txt1.75 KBManuel Garcia
#35 2921824-35.patch12.28 KBManuel Garcia
#35 interdiff-34-35.txt11.16 KBManuel Garcia
#34 2921824-34.patch10.85 KBManuel Garcia
#34 interdiff-31-34.txt3.83 KBManuel Garcia
#31 interdiff-26-31.patch1.94 KBManuel Garcia
#31 2921824-31.patch9.53 KBManuel Garcia
#26 interdiff.txt735 bytesManuel Garcia
#26 2921824-26.patch7.88 KBManuel Garcia
#25 interdiff-2921824-11-25.txt1.15 KBfenstrat
#25 2921824-25.patch7.6 KBfenstrat
#13 interdiff-2921824-11-13.txt267 bytesfenstrat
#13 2921824-13.patch7.88 KBfenstrat
#11 interdiff-2921824-8-10.txt8.43 KBfenstrat
#11 2921824-11.patch7.62 KBfenstrat
#8 2921824-8.patch5.67 KBManuel Garcia
#8 interdiff.txt5.9 KBManuel Garcia
#2 2921824-2.patch743 bytesManuel Garcia
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Manuel Garcia created an issue. See original summary.

Manuel Garcia’s picture

Status: Active » Needs review
FileSize
743 bytes

Here it is, works with the current data structure.

vijaycs85’s picture

Status: Needs review » Reviewed & tested by the community

Looks good.

+++ b/config/schema/webform_encrypt.schema.yml
@@ -0,0 +1,21 @@
+webform.encrypt:

Out of scope of this issue, but we should be using proper namespace here i.e. webform_encrypt.settings.

Manuel Garcia’s picture

@vijaycs85 yeah, but that would require an upgrade path, so I went with the path of least resistance...

fenstrat’s picture

Status: Reviewed & tested by the community » Needs work

I noticed a nasty issue with the current config schema. While it's not related to properly defining the schema as the patch is doing here, it's probably worth fixing here.

The current schema is like so:

element:
  settings:
    field_name_1:
      encrypt: '1'
      encrypt_profile: profile_name

Further fields are added under settings. At no point is the form name accounted for. So, if a second form shares the component machine name field_name_1 that means they also share encryption settings. Not cool :)

Given the module still has no D8 release and is only reporting 14 installs I think it's time to introduce a breaking schema change now (including the namespace issue @vijaycs85 mentioned above). I don't think an upgrade path is worth it.

This will also effect #2855702: Allow encryption for more elements. I've run out of time on this till next week, but can pick it up then.

Manuel Garcia’s picture

Yeah @fenstrat you are correct in your assessment of the way the module currently saves the data.

Ideally this configuration should be saved with the webform itself, so inside webform.webform.WEBFORMID.elements.FIELDNAME

I believe this may be is a sign of a bigger problem, perhaps this module should be making use of the hooks provided by webform module, instead of using hook_form_FORM_ID_alter etc.

Manuel Garcia’s picture

#2855702: Allow encryption for more elements was committed a few days ago.

I've spent a bit of time on this today, here are my findindings:

  1. None of the hooks provided by webform module allow us to hook into webform_ui_element_form. So it looks like we're stuck with our current approach.
  2. On webform_ui_element_form, which is where WebformElementEncrypt::processWebformElementEncrypt() currently adds our settings form fields, has no information regarding to which webform this field is attached to. So unless someone figures this out, I'm not sure how we're going to do #5.
Manuel Garcia’s picture

Title: Add missing schema configuration file » Encryption settings are only saved per field
Category: Task » Bug report
Issue summary: View changes
Status: Needs work » Needs review
FileSize
5.9 KB
5.67 KB

OK, nothing like stating that you're blocked to unblock yourself apparently...

Anyway, here is a patch addressing:

  1. The schema name as mentioned on #3.
  2. Saving the configuration per webform per field. In other words, addressing #5.
  3. Updated the hook_uninstall to reflect these changes.

We should write a test for our uninstall hook, as it is pretty important for us not to break it accidentally, we should open up a follow up for this.

Re-titling and modifying the issue description to reflect the new scope.

vijaycs85’s picture

Looks good @Manuel Garcia. Just few questions for my understanding:

  1. +++ b/src/WebformEncryptSubmissionStorage.php
    @@ -50,7 +50,8 @@ class WebformEncryptSubmissionStorage extends WebformSubmissionStorage {
    -    $config = \Drupal::service('config.factory')->get('webform.encrypt')->get('element.settings');
    ...
    +    $config = \Drupal::service('config.factory')->get('webform_encrypt.settings')->get("element.settings.$webform_id");
    

    So we are going to save settings per webform?

  2. +++ b/webform_encrypt.install
    @@ -15,11 +15,11 @@ function webform_encrypt_uninstall() {
    +  $config = \Drupal::service('config.factory')->get('webform_encrypt.settings')->get("element.settings");
    

    don't we need to change element.settings here?

Manuel Garcia’s picture

Re #9.1:
Yes, so that field configurations are not shared across webforms. Eg. so you can have fields with the same name on different webforms, but on one webform its encrypted and on another webform it is not. (see #5).

Re #9.2:
Not necessary there, we actually want the the whole configuration, so that inside the loop for the submissions:

+++ b/webform_encrypt.install
@@ -15,11 +15,11 @@ function webform_encrypt_uninstall() {
-    if (isset($config[$submission->name]['encrypt']) && $config[$submission->name]['encrypt']) {
-      $encryption_profile = \Drupal\encrypt\Entity\EncryptionProfile::load($config[$submission->name]['encrypt_profile']);
+    if (isset($config[$submission->webform_id][$submission->name]['encrypt']) && $config[$submission->webform_id][$submission->name]['encrypt']) {
+      $encryption_profile = \Drupal\encrypt\Entity\EncryptionProfile::load($config[$submission->webform_id][$submission->name]['encrypt_profile']);

we can check the configuration for each specific submission by using the webform_id as well as the field name (so we can figure out if we need to decrypt or not).

fenstrat’s picture

FileSize
7.62 KB
8.43 KB

@Manuel Garcia thanks!

The attached patch adapts what you had to use third_party_settings.

  1. third_party_settings benefits from automatically adding in dependencies to config on webform_encrypt
  2. This removes the need for a separate webform_encrypt.settings.yml, instead config is stored along side form config in webform.webform.form_name.yml
  3. Updates config in webform_encrypt_test module

p.s. I think testing on the 8.x branch needs to be be enabled, something is going wrong as pift is saying 'No tests found'. btw I'm happy to be a co-maintainer if needed.

vijaycs85’s picture

Nice one @fenstrat. me and @Manuel Garcia were talking about using third party settings.

Regarding testing: I have reopened #2921913: Add co-maintainers as how my access has been rollback to check the testing tab.

fenstrat’s picture

FileSize
7.88 KB
267 bytes

@vijaycs85 cheers. Will post in that co-maintainer issue.

Think I found why the tests aren't running, was missing the src folder.

vijaycs85’s picture

@fenstrat looks like the test is not in right directory - #2923249: Fix test dir

vijaycs85’s picture

@fenstrat :D snap!

fenstrat’s picture

@vijaycs85 hahaaa :) Happy to move that out if you want to get #2923249: Fix test dir in.

Status: Needs review » Needs work

The last submitted patch, 13: 2921824-13.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

vijaycs85’s picture

@fenstrat :) now the test is failing, let's move that out and push it and reroll this one.

vijaycs85’s picture

Looks like I don't have access to project anymore :( waiting for response on #2921913: Add co-maintainers

Manuel Garcia’s picture

Status: Needs work » Needs review

Brilliant thanks @fenstrat!
Just committed #2923249: Fix test dir, retesting #11.

Manuel Garcia’s picture

+++ b/src/Element/WebformElementEncrypt.php
@@ -79,16 +80,28 @@ class WebformElementEncrypt extends FormElement {
-    $config[$field_name] = array(
-      'encrypt' => $values['encrypt'],
-      'encrypt_profile' => $values['encrypt_profile'],
-    );
+    if (empty($values['encrypt'])) {
+      unset($config['settings'][$field_name]);
+    }
+    else {
+      $config['settings'][$field_name] = array(
+        'encrypt' => $values['encrypt'],
+        'encrypt_profile' => $values['encrypt_profile'],
+      );
+    }
 
-    \Drupal::service('config.factory')->getEditable('webform.encrypt')->set('element.settings', $config)->save();
+    if (empty($config['settings'])) {
+      $webform->unsetThirdPartySetting('webform_encrypt', 'element');
+    }
+    else {
...
+    }

This looks unnecessarily complex... is there a reason why we can't just $webform->setThirdPartySetting('webform_encrypt', 'element', $config); no matter what the values are?

The last submitted patch, 11: 2921824-11.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Manuel Garcia’s picture

Status: Needs review » Needs work

We should proceed from #11

fenstrat’s picture

@Manuel Garcia yeah agreed that logic is yucky, however passing an empty value to setThirdPartySetting() still writes a null value to config for element (i.e. that creates a dependency on webform_encrypt even if no components in the form have encryption enabled). I'll have another look tomorrow (and at the least document what's going on) when I continue from #11. Thanks!

fenstrat’s picture

Status: Needs work » Needs review
FileSize
7.6 KB
1.15 KB

This continues from #11.

  1. Fixes the failing test, I'd just incorrectly configured the test webform in #11.
  2. Adds a comment to explain the odd logic behind setThirdPartySetting()
Manuel Garcia’s picture

Again, thanks @fenstrat for working on this :)

Patch is looking good to me now, just adding a comment explaning why we need this logic in this patch.

fenstrat’s picture

@Manuel Garcia marvellous, much better explanation, cheers!

I'd mark this RTBC but I don't think that'd be right. @vijaycs85 care to do a review please? Thanks :)

vijaycs85’s picture

Status: Needs review » Reviewed & tested by the community

Thanks @fenstrat & @Manuel Garcia. Looks good to me.


Only note is what would happen for the sites with existing config. As mentioned in #5, we know it's going to break. Probably worth a follow up for those poor 14 sites? :)
fenstrat’s picture

@vijaycs85 Thanks.

TBH I don't think a config migration is worth it for 14 sites running a dev release?

Manuel Garcia’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs upgrade path

We should provide an upgrade path, we have to assume is a lot more than 14 sites, since those are just the ones that are pinging drupal.org.
More over, even if it was "just" 14 sites, their webforms will stop encrypting data, they may not even notice and get into trouble legally or otherwise.

Manuel Garcia’s picture

Status: Needs work » Needs review
FileSize
9.53 KB
1.94 KB

Here is the upgrade path, I've tested it a bit locally but we should test it further.

Status: Needs review » Needs work

The last submitted patch, 31: interdiff-26-31.patch, failed testing. View results

Manuel Garcia’s picture

oops wrong interdiff file extension...

Manuel Garcia’s picture

Status: Needs work » Needs review
FileSize
3.83 KB
10.85 KB

Some more work on this:

  1. Clearing the cache on hook_udpate so that the old config is cleared from cache.
  2. Turning our encrypt setting to be a boolean in the schema to match the expected value of the checkbox.

The last change I made for consistency, but also because with this patch I see that the checkbox is not shown as checked when you have saved it as enabled. As in if you enable encryption for a field, and save it, when you edit it again, the checkbox is not checked. Not sure what is going on there, but we need to fix that before we can commit this...

Manuel Garcia’s picture

Alright I managed to figure this all out I think...

  1. I have simplified the new schema, so its easier to get things, and more in line with how third party settings is meant to be used.
  2. I have changed our tests so they validate our schema since that should work now.
  3. Double checked our migration path, looks good to me but could use a second hand of testing (any takers?)
  4. The logic on WebformElementEncrypt::validateWebformElementEncrypt() is now a lot simpler due to the new schema.

Status: Needs review » Needs work

The last submitted patch, 35: 2921824-35.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Manuel Garcia’s picture

Status: Needs work » Needs review
FileSize
1.75 KB
12.62 KB

Let's see if this does the trick :)

vijaycs85’s picture

Over all, looks good. few findings/minor issues. Not sure if they qualify to 'Needs work' status :)

  1. +++ b/src/Element/WebformElementEncrypt.php
    @@ -79,16 +79,22 @@ class WebformElementEncrypt extends FormElement {
    +        'encrypt' => $values['encrypt'] == 1,
    

    Minor: Ideally type casting is done by config::save().

  2. +++ b/tests/src/Functional/WebformEncryptFunctionalTest.php
    @@ -29,13 +29,6 @@ class WebformEncryptFunctionalTest extends BrowserTestBase {
    -  protected $strictConfigSchema = FALSE;
    

    Nice!

  3. +++ b/webform_encrypt.install
    @@ -27,6 +31,57 @@ function webform_encrypt_uninstall() {
    + * Migrate webform encrypt enabed elements to using third party settings.
    ...
    +function webform_encrypt_update_8101() {
    

    @Manuel Garcia++

  4. +++ b/webform_encrypt.install
    @@ -27,6 +31,57 @@ function webform_encrypt_uninstall() {
    +  if (!empty($old_config)) {
    ...
    +  if (!empty($old_config)) {
    

    if (empty($old_config)) {
    return;
    }
    // Continue other logics.
    Minor: We could return at top if no old config. Saves us condition and intention

  5. +++ b/webform_encrypt.install
    @@ -27,6 +31,57 @@ function webform_encrypt_uninstall() {
    +  drupal_flush_all_caches();
    

    Not sure, if it's necessary. update_N eventually does this?

Manuel Garcia’s picture

Thanks @vijaycs85 for the review!

Re #38.1 - you're right, fixed and verified that the value is indeed typecasted on save.

Re #38.2 - Tests++

Re #38.4 - I know it looks weird, I struggled with it as well. The thing is that we need to delete the old config AND clear the cache at the end, so I did it like this in order not to have to do this on two places...

Re #38.5 - That's what I thought at first too, but even though we deleted it, the old config is stil accessible on the site (checked with config_inspector). That's not the case if we call drupal_flush_all_caches() here so perhaps not all the cache is cleared on hook_update?

Manuel Garcia’s picture

argh again wrong file extension for the interdiff... sorry bot!

The last submitted patch, 39: interdiff-37-39.patch, failed testing. View results

fenstrat’s picture

Status: Needs review » Needs work

@Manuel Garcia nice work!

+++ b/tests/modules/webform_encrypt_test/config/install/webform.webform.test_encryption.yml
@@ -1,6 +1,16 @@
+third_party_settings:
+  webform_encrypt:
+    test_text_field:

Simplifying the config schema is a good idea, but I think it's gone one level too far. We should reintroduce the elements level (this also matches webform itself). Because right now the fields are under the top level webform_encrypt level and that's one level too far.

The upgrade path looks good, I've not run it but will make time to test it later.

Manuel Garcia’s picture

Using config_inspector, this is how the Raw configuration data looks with this patch, for a webform with two fields,:

'third_party_settings' => 
  array (
    'webform_encrypt' => 
    array (
      'field2' => 
      array (
        'encrypt' => true,
        'encrypt_profile' => 'pfizer_encrypt',
      ),
      'field1' => 
      array (
        'encrypt' => true,
        'encrypt_profile' => 'pfizer_encrypt',
      ),
    ),
  ),

And the Tree of configuration data:

Are you sure we want to add another level? I ask because right now its realy clean to get the config for an element like this: $webform->getThirdPartySetting('webform_encrypt', $element_name);

Manuel Garcia’s picture

Status: Needs work » Needs review
FileSize
9.42 KB
13.38 KB

OK, I suppose it makes sense if we want to add some other webform-wide setting and if webform does it like this, we should follow their lead in any case, so here it is, hopefully I didn't forget anything.

Some highlights:

  • Had to restore a bit of the logic on WebformElementEncrypt::validateWebformElementEncrypt().
  • Was able to simplify a bit the update hook (only set the third party settings once per webform).
Manuel Garcia’s picture

Just realized we were breaking the uninstall process, fixing it now. We really need test coverage for this.

Manuel Garcia’s picture

fenstrat’s picture

Status: Needs review » Reviewed & tested by the community

@Manuel Garcia this is great, thank you :) It really does make sense to have under the elements level.

Tested the upgrade path and it works a treat.

Thanks for spinning off #2924905: Data gets destroyed due to hook_uninstall.

Manuel Garcia’s picture

Priority: Normal » Major

Thanks @fenstrat

Bumping priority here.

Also, we should have a look at #2924957: Unable to encrypt nested/multiple nested fields before cutting the first alpha release.

Manuel Garcia’s picture

Status: Reviewed & tested by the community » Needs review

#2924905: Data gets destroyed due to hook_uninstall is in now, let's see where we are with this patch now that we have a test for uninstalling.

Manuel Garcia’s picture

Status: Needs review » Reviewed & tested by the community

Test is still green, back to RTBC

fenstrat’s picture

Status: Reviewed & tested by the community » Fixed

Excellent! Thank you @Manuel Garcia and @vijaycs85, onwards :)

vijaycs85’s picture

yay! great work @Manuel Garcia & @fenstrat. I believe we are ready for first alpha release. I'd go for beta as a) we have done plenty of testing b) port from D7. But I will leave that with other maintainers to decide. Created an issue for release at #2925418: Create an alpha release on 8.x branch

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Manuel Garcia’s picture

Just a heads up that the update hook introduced here is faulty. If your webforms have fields inside containers, the configuration will not be migrated properly, see #2935893: webform_encrypt_update_8101 ignores fields in containers