Commit 5d69ba12 authored by vijaycs85's avatar vijaycs85

Issue #2855702 by jribeiro, acbramley, l0ke: Allow encryption for more elements

parent bcdd07cc
<?php
/**
* @file
* Preprocessors and helper functions for theming.
*/
/**
* Prepares variables for webform submission HTML template.
*
* Default template: webform-submission-html.html.twig.
*
* @param array $variables
* An associative array containing the following key:
* - webform_submission: A webform submission.
*/
function webform_encrypt_preprocess_webform_submission_html(array &$variables) {
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
$webform_submission = $variables['webform_submission'];
/** @var \Drupal\webform\WebformSubmissionViewBuilderInterface $view_builder */
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('webform_submission');
$webform = $webform_submission->getWebform();
$data = $webform_submission->getData();
$elements = $webform->getElementsInitialized();
$data_original = $view_builder->buildElements($elements, $data);
$config = \Drupal::service('config.factory')->get('webform.encrypt')->get('element.settings');
foreach ($data_original as $key => &$element) {
if (isset($config[$key]['encrypt']) && $config[$key]['encrypt']) {
$user = \Drupal::currentUser();
if ($user->hasPermission('view encrypted values')) {
$encryption_profile = \Drupal\encrypt\Entity\EncryptionProfile::load($config[$key]['encrypt_profile']);
$element['#value']['#markup'] = Drupal::service('encryption')->decrypt($element['#value']['#markup'], $encryption_profile);
}
else {
$element['#value']['#markup'] = t('[Value Encrypted]');
}
}
}
$variables['data'] = $data_original;
}
/**
* Prepares variables for webform submission plain text template.
*
* Default template: webform-submission-text.html.twig.
*
* @param array $variables
* An associative array containing the following key:
* - webform_submission: A webform submission.
*/
function webform_encrypt_preprocess_webform_submission_text(array &$variables) {
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
$webform_submission = $variables['webform_submission'];
$variables['sid'] = $webform_submission->id();
$variables['uuid'] = $webform_submission->uuid();
$variables['is_draft'] = $webform_submission->isDraft() ? t('Yes') : t('No');
$variables['current_page'] = $webform_submission->getCurrentPage();
$variables['remote_addr'] = $webform_submission->getRemoteAddr();
$variables['submitted_by'] = $webform_submission->getOwner()->label();
$variables['webform'] = $webform_submission->getWebform()->label();
$variables['created'] = \Drupal\webform\Utility\WebformDateHelper::format($webform_submission->getCreatedTime());
$variables['completed'] = \Drupal\webform\Utility\WebformDateHelper::format($webform_submission->getCompletedTime());
$variables['changed'] = \Drupal\webform\Utility\WebformDateHelper::format($webform_submission->getChangedTime());
// @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\LanguageFormatter::viewValue()
$languages = \Drupal::languageManager()->getNativeLanguages();
$langcode = $webform_submission->get('langcode')->value;
$variables['language'] = isset($languages[$langcode]) ? $languages[$langcode]->getName() : $langcode;
if ($source_url = $webform_submission->getSourceUrl()) {
$variables['uri'] = $source_url->toString();
}
if ($source_entity = $webform_submission->getSourceEntity()) {
$variables['submitted_to'] = $source_entity->label();
}
/** @var \Drupal\webform\WebformSubmissionViewBuilderInterface $view_builder */
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('webform_submission');
$webform = $webform_submission->getWebform();
$data = $webform_submission->getData();
$elements = $webform->getElementsInitialized();
$data_original = $view_builder->buildElements($elements, $data, [], 'text');
$config = \Drupal::service('config.factory')->get('webform.encrypt')->get('element.settings');
foreach ($data_original as $key => &$element) {
if (isset($config[$key]['encrypt']) && $config[$key]['encrypt']) {
$user = \Drupal::currentUser();
if ($user->hasPermission('view encrypted values')) {
$encryption_profile = \Drupal\encrypt\Entity\EncryptionProfile::load($config[$key]['encrypt_profile']);
$element['#value']['#markup'] = Drupal::service('encryption')->decrypt($element['#value']['#markup'], $encryption_profile);
}
else {
$element['#value']['#markup'] = t('[Value Encrypted]');
}
}
}
$variables['data'] = $data_original;
}
/**
* Prepares variables for webform submission YAML template.
*
* Default template: webform-submission-yaml.html.twig.
*
* @param array $variables
* An associative array containing the following key:
* - webform_submission: A webform submission.
*/
function webform_encrypt_preprocess_webform_submission_yaml(array &$variables) {
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
$webform_submission = $variables['webform_submission'];
$data = $webform_submission->toArray(TRUE);
$webform = \Drupal\webform\Entity\Webform::load($data['webform_id']);
$elements = $webform->getElementsInitializedAndFlattened();
$config = \Drupal::service('config.factory')->get('webform.encrypt')->get('element.settings');
foreach ($elements as $key => $element) {
if (isset($config[$key]['encrypt']) && $config[$key]['encrypt']) {
$user = \Drupal::currentUser();
if ($user->hasPermission('view encrypted values')) {
$encryption_profile = \Drupal\encrypt\Entity\EncryptionProfile::load($config[$key]['encrypt_profile']);
$data['data'][$key] = Drupal::service('encryption')->decrypt($data['data'][$key], $encryption_profile);
}
else {
$data['data'][$key] = t('[Value Encrypted]');
}
}
}
$yaml = \Drupal\Component\Serialization\Yaml::encode($data);
$yaml = \Drupal\webform\Utility\WebformTidy::tidy($yaml);
$variables['yaml'] = [
'#markup' => $yaml,
'#allowed_tags' => \Drupal\Component\Utility\Xss::getAdminTagList(),
];;
}
/**
* Prepares variables for webform submission table template.
*
* Default template: webform-submission-table.html.twig.
*
* @param array $variables
* An associative array containing the following key:
* - webform_submission: A webform submission.
*/
function webform_encrypt_preprocess_webform_submission_table(array &$variables) {
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
$webform_submission = $variables['webform_submission'];
/** @var \Drupal\webform\WebformSubmissionViewBuilderInterface $view_builder */
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('webform_submission');
$webform = $webform_submission->getWebform();
$data = $webform_submission->getData();
$elements = $webform->getElementsFlattenedAndHasValue();
$config = \Drupal::service('config.factory')->get('webform.encrypt')->get('element.settings');
foreach ($elements as $key => $element) {
if (isset($config[$key]['encrypt']) && $config[$key]['encrypt']) {
$user = \Drupal::currentUser();
if ($user->hasPermission('view encrypted values')) {
$encryption_profile = \Drupal\encrypt\Entity\EncryptionProfile::load($config[$key]['encrypt_profile']);
$data[$key] = Drupal::service('encryption')->decrypt($data[$key], $encryption_profile);
}
else {
$data[$key] = t('[Value Encrypted]');
}
}
}
$variables['table'] = $view_builder->buildTable($elements, $data);
}
......@@ -49,7 +49,7 @@ class WebformElementEncrypt extends FormElement {
'#type' => 'checkbox',
'#title' => t('Encrypt this field\'s value'),
'#description' => t('<a href=":link">Click here</a> to edit encryption settings.', array(':link' => Url::fromRoute('entity.encryption_profile.collection')->toString())),
'#default_value' => $config[$field_name]['encrypt'] ? $config[$field_name]['encrypt'] : 0,
'#default_value' => isset($config[$field_name]['encrypt']) ? $config[$field_name]['encrypt'] : 0,
];
$element['element_encrypt']['encrypt_profile'] = [
......
<?php
namespace Drupal\webform_encrypt;
use Drupal\Core\Entity\EntityInterface;
use Drupal\webform\WebformSubmissionStorage;
use Drupal\encrypt\Entity\EncryptionProfile;
use Drupal\webform\Entity\WebformSubmission;
/**
* Alter webform submission storage definitions.
*/
class WebformEncryptSubmissionStorage extends WebformSubmissionStorage {
/**
* Decrypts a string.
*
* @param string $string
* The string to be decrypted.
* @param string $encryption_profile
* The encryption profile to be used to decrypt the string.
* @param bool $check_permissions
* Flag that controls permissions check.
*
* @return string
* The decrypted value.
*/
protected function decrypt($string, $encryption_profile, $check_permissions = TRUE) {
if ($check_permissions && !\Drupal::currentUser()->hasPermission('view encrypted values')) {
return '[Value Encrypted]';
}
$decrypted_value = \Drupal::service('encryption')->decrypt($string, $encryption_profile);
if ($decrypted_value === FALSE) {
return $string;
}
return $decrypted_value;
}
/**
* Returns the Webform Submission data decrypted.
*
* @param \Drupal\webform\Entity\WebformSubmission $webform_submission
* The Webform Submission entity object.
* @param bool $check_permissions
* Flag that controls permissions check.
*
* @return array
* An array containing the Webform Submission decrypted data.
*/
protected function getDecryptedData(WebformSubmission $webform_submission, $check_permissions = TRUE) {
$config = \Drupal::service('config.factory')->get('webform.encrypt')->get('element.settings');
$webform = $webform_submission->getWebform();
$elements = $webform->getElementsInitializedFlattenedAndHasValue();
$data = $webform_submission->getData();
foreach ($elements as $element_name => $element) {
// Skip elements that have no data.
if (!isset($data[$element_name])) {
continue;
}
// Skip elements that are not encrypted.
if (empty($config[$element_name]['encrypt'])) {
continue;
}
$encryption_profile = EncryptionProfile::load($config[$element_name]['encrypt_profile']);
// Checks whether is an element with multiple values.
if (is_array($data[$element_name])) {
foreach ($data[$element_name] as $element_value_key => $element_value) {
$data[$element_name][$element_value_key] = $this->decrypt($element_value, $encryption_profile, $check_permissions);
}
continue;
}
// Single element value.
$data[$element_name] = $this->decrypt($data[$element_name], $encryption_profile, $check_permissions);
}
return $data;
}
/**
* {@inheritdoc}
*/
protected function doPostSave(EntityInterface $entity, $update) {
$data = $this->getDecryptedData($entity, FALSE);
$entity->setData($data);
/** @var \Drupal\webform\WebformSubmissionInterface $entity */
parent::doPostSave($entity, $update);
}
/**
* {@inheritdoc}
*/
protected function loadData(array &$webform_submissions) {
parent::loadData($webform_submissions);
foreach ($webform_submissions as &$webform_submission) {
$data = $this->getDecryptedData($webform_submission);
$webform_submission->setData($data);
$webform_submission->setOriginalData($data);
}
}
}
<?php
namespace Drupal\Tests\webform_encrypt\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\Entity\Role;
/**
* Functional tests for the webform_encrypt module.
*
* @group webform_encrypt
*/
class WebformEncryptFunctionalTest extends BrowserTestBase {
/**
* The admin user.
*
* @var \Drupal\user\Entity\User
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected static $modules = [
'webform_encrypt',
'webform_encrypt_test',
'webform_ui',
];
/**
* Don't validate config schema https://www.drupal.org/node/2901950.
*
* @var bool
*/
protected $strictConfigSchema = FALSE;
/**
* Permissions to grant admin user.
*
* @var array
*/
protected $permissions = [
'access administration pages',
'view any webform submission',
'edit any webform',
];
/**
* Sets the test up.
*/
protected function setUp() {
parent::setUp();
// Test admin user.
$this->adminUser = $this->drupalCreateUser($this->permissions);
}
/**
* Test webform field encryption.
*/
public function testFieldEncryption() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$this->drupalLogin($this->adminUser);
$encrypted_value = '[Value Encrypted]';
// Test admin functionality.
$this->drupalGet('admin/structure/webform/manage/test_encryption');
// Add a new element and set encryption on it.
$page->clickLink('Add element');
$page->clickLink('Date');
$edit = [
'key' => 'test_date',
'title' => 'Test date',
'encrypt' => 1,
'encrypt_profile' => 'test_encryption_profile',
];
$this->submitForm($edit, 'Save');
$assert_session->responseContains('<em class="placeholder">Test date</em> has been created');
// Make a submission.
$edit = [
'test_text_field' => 'Test text field value',
'test_text_area' => 'Test text area value',
'test_not_encrypted' => 'Test not encrypted value',
'test_date' => '2017-08-14',
];
$this->drupalPostForm('/webform/test_encryption', $edit, 'Submit');
$assert_session->responseContains('New submission added to Test encryption.');
// Ensure encrypted fields do not show values.
$this->drupalGet('admin/structure/webform/manage/test_encryption/results/submissions');
$assert_session->responseNotContains($edit['test_text_field']);
$assert_session->responseNotContains($edit['test_text_field']);
$assert_session->responseContains($edit['test_not_encrypted']);
$assert_session->responseNotContains($edit['test_date']);
$submission_path = 'admin/structure/webform/manage/test_encryption/submission/1';
$this->drupalGet($submission_path);
$text_selector = '.form-item-test-text-field';
$area_selector = '.form-item-test-text-area';
$not_encrypted_selector = '.form-item-test-not-encrypted';
$date_selector = '.form-item-test-date';
$assert_session->elementTextContains('css', $text_selector, $encrypted_value);
$assert_session->elementTextNotContains('css', $text_selector, $edit['test_text_field']);
$assert_session->elementTextContains('css', $area_selector, $encrypted_value);
$assert_session->elementTextNotContains('css', $area_selector, $edit['test_text_area']);
$assert_session->elementTextContains('css', $not_encrypted_selector, $edit['test_not_encrypted']);
$assert_session->elementTextNotContains('css', $not_encrypted_selector, $encrypted_value);
$assert_session->elementTextContains('css', $date_selector, $encrypted_value);
$assert_session->elementTextNotContains('css', $date_selector, $edit['test_date']);
// Grant user access to view encrypted values and check again.
$this->grantPermissions(Role::load($this->adminUser->getRoles()[0]), ['view encrypted values']);
$this->drupalGet($submission_path);
$assert_session->responseNotContains($encrypted_value);
$assert_session->elementTextContains('css', $text_selector, $edit['test_text_field']);
$assert_session->elementTextContains('css', $area_selector, $edit['test_text_area']);
$assert_session->elementTextContains('css', $date_selector, '08/14/2017');
}
}
langcode: en
status: true
dependencies:
config:
- key.key.test
module:
- encrypt_test
id: test_encryption_profile
label: 'Test encryption profile'
encryption_method: test_encryption_method
encryption_key: test
encryption_method_configuration: { }
langcode: en
status: true
dependencies: { }
id: test
label: 'Test key'
description: ''
key_type: encryption
key_type_settings:
key_size: 128
key_provider: config
key_provider_settings:
base64_encoded: false
key_value: 1E265D6FA8C7B333
key_input: text_field
key_input_settings:
base64_encoded: false
element:
settings:
test_text_field:
encrypt: '1'
encrypt_profile: test_encryption_profile
test_text_area:
encrypt: '1'
encrypt_profile: test_encryption_profile
test_not_encrypted:
encrypt: ''
encrypt_profile: test_encryption_profile
langcode: en
status: open
dependencies: { }
open: null
close: null
uid: 1
template: false
id: test_encryption
title: 'Test encryption'
description: ''
category: ''
elements: "test_text_field:\n '#type': textfield\n '#title': 'Test text field'\ntest_text_area:\n '#type': textarea\n '#title': 'Test text area'\ntest_not_encrypted:\n '#type': textfield\n '#title': 'Test not encrypted'\n"
css: ''
javascript: ''
settings:
ajax: false
page: true
page_submit_path: ''
page_confirm_path: ''
form_submit_once: false
form_exception_message: ''
form_open_message: ''
form_close_message: ''
form_previous_submissions: true
form_confidential: false
form_confidential_message: ''
form_convert_anonymous: false
form_prepopulate: false
form_prepopulate_source_entity: false
form_prepopulate_source_entity_required: false
form_prepopulate_source_entity_type: ''
form_reset: false
form_disable_autocomplete: false
form_novalidate: false
form_unsaved: false
form_disable_back: false
form_autofocus: false
form_details_toggle: false
submission_label: ''
submission_log: false
submission_user_columns: { }
wizard_progress_bar: true
wizard_progress_pages: false
wizard_progress_percentage: false
wizard_start_label: ''
wizard_complete: true
wizard_complete_label: ''
preview: 0
preview_label: ''
preview_title: ''
preview_message: ''
preview_attributes: { }
preview_excluded_elements: { }
preview_exclude_empty: true
draft: none
draft_multiple: false
draft_auto_save: false
draft_saved_message: ''
draft_loaded_message: ''
confirmation_type: page
confirmation_title: ''
confirmation_message: ''
confirmation_url: ''
confirmation_attributes: { }
confirmation_back: true
confirmation_back_label: ''
confirmation_back_attributes: { }
limit_total: null
limit_total_message: ''
limit_user: null
limit_user_message: ''
purge: none
purge_days: null
entity_limit_total: null
entity_limit_user: null
results_disabled: false
results_disabled_ignore: false
token_update: false
access:
create:
roles:
- anonymous
- authenticated
users: { }
permissions: { }
view_any:
roles: { }
users: { }
permissions: { }
update_any:
roles: { }
users: { }
permissions: { }
delete_any:
roles: { }
users: { }
permissions: { }
purge_any:
roles: { }
users: { }
permissions: { }
view_own:
roles: { }
users: { }
permissions: { }
update_own:
roles: { }
users: { }
permissions: { }
delete_own:
roles: { }
users: { }
permissions: { }
handlers: { }
name: 'Webform Encrypt Test'
type: module
description: 'Provides test config for webform_encrypt module tests.'
package: 'Webform'
core: 8.x
dependencies:
- webform_encrypt:webform_encrypt