Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add js api key field & hashing for visitor recognition #20

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 122 additions & 4 deletions src/core/TawktoGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require_once __DIR__ . '/../../vendor/autoload.php';
}

use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand Down Expand Up @@ -54,24 +55,44 @@ public function getWidget() {
$display_opts = $options;
// Default value.
$enable_visitor_recognition = TRUE;
$secure_mode_enabled = FALSE;
$js_api_key = NULL;
if (!is_null($display_opts)) {
$display_opts = json_decode($display_opts);

if (!is_null($display_opts->enable_visitor_recognition)) {
$enable_visitor_recognition = $display_opts->enable_visitor_recognition;
}

if (!is_null($display_opts->secure_mode_enabled)) {
$secure_mode_enabled = $display_opts->secure_mode_enabled;
}

if (!is_null($display_opts->js_api_key)) {
$js_api_key = $display_opts->js_api_key;
}
}

if ($enable_visitor_recognition) {
$user = User::load(\Drupal::currentUser()->id());
if ($user) {
$username = $user->get('name')->value;
$usermail = $user->get('mail')->value;
$hash = NULL;

if ($secure_mode_enabled && !is_null($js_api_key)) {
$key = $this->getKey($js_api_key);

if (!is_null($key)) {
$hash = hash_hmac('sha256', $usermail, $key);
}
}

$apiString = 'Tawk_API.visitor = {
name : "' . $username . '",
email : "' . $usermail . '",
};';
name : "' . Html::escape($username) . '",
email : "' . $usermail . '",' .
(!is_null($hash) ? PHP_EOL . 'hash : "' . $hash . '",' : '') .
'};';
}
}

Expand All @@ -95,6 +116,46 @@ public function getWidget() {
return $output;
}

/**
* Get keys.
*
* @return array
* Key module installed and keys
*/
private function getKeyModule() {
$installed = \Drupal::getContainer()->has('key.repository');
$keys = [];

if ($installed) {
$keys = \Drupal::service('key.repository')->getKeysByType('authentication');
}

return [
'installed' => $installed,
'keys' => $keys,
];
}

/**
* Get key value.
*
* @param string $key_id
* Key ID.
*
* @return string|null
* Key value.
*/
private function getKey($key_id) {
$installed = \Drupal::getContainer()->has('key.repository');

if (!$installed) {
return NULL;
}

$key = \Drupal::service('key.repository')->getKey($key_id);
return $key->getKeyValue();
}

/**
* Check widget visibility based on set options.
*
Expand Down Expand Up @@ -214,6 +275,11 @@ public function getIframe() {
if (!is_null($display_opts)) {
$display_opts = json_decode($display_opts);
}

$keyModule = $this->getKeyModule();
$keyModuleInstalled = $keyModule['installed'];
$keys = $keyModule['keys'];

ob_start();
?>
<link href="https://plugins.tawk.to/public/bootstrap/css/bootstrap.min.css" rel="stylesheet">
Expand Down Expand Up @@ -284,7 +350,7 @@ public function getIframe() {
<form id="module_form" class="form-horizontal" action="" method="post">
<div id="fieldset_1">
<div class="panel form-group col-xs-12">
<div class="panel-heading"><strong>Visibility Settings</strong></div>
<div class="panel-heading"><strong>Visibility Options</strong></div>
</div>
<div class="form-group col-xs-12">
<label for="always_display" class="col-xs-6 control-label">Always show Tawk.To widget on every page</label>
Expand Down Expand Up @@ -453,6 +519,53 @@ public function getIframe() {
</div>
</div>
</div>
<div id="fieldset_3">
<div class="panel form-group col-xs-12">
<div class="panel-heading"><strong>Security Options</strong></div>
</div>
<div class="form-group col-xs-12">Note: If Secure Mode is enabled on your property, please enter your Javascript API Key to ensure visitor recognition works correctly.</div>
<div class="form-group col-xs-12">
<label for="secure_mode_enabled" class="col-xs-6 control-label">Secure mode enabled</label>
<div class="col-xs-6 control-label">
<?php
$checked = 'checked';
if (!is_null($display_opts) && !$display_opts->secure_mode_enabled) {
$checked = '';
}
?>
<input type="checkbox" class="checkbox" name="secure_mode_enabled" id="secure_mode_enabled" value="1"
<?php echo $checked ?> />
</div>
</div>
<div class="form-group col-xs-12">
<label for="enable_visitor_recognition" class="col-xs-6 control-label">JavaScript API Key</label>
<div class="col-xs-6 control-label" style="text-align: justify;">
<?php if (!$keyModuleInstalled) { ?>

<span>The <a target="_blank" href="https://www.drupal.org/project/key">Key</a> module is not installed. Please install it and create an <b>Authentication</b> key for JS API Key.</span>

<?php }
else { ?>

<span>Keys:</span>
<select name="js_api_key" id="js_api_key">
<option value="">Select a key</option>
<?php
foreach (array_keys($keys) as $key) {
$selected = 'selected';
if (!is_null($display_opts) && $display_opts->js_api_key !== $key) {
$selected = '';
}
?>
<option value="<?php echo $key; ?>" <?php echo $selected; ?>><?php echo $key; ?></option>
<?php } ?>
</select>
<div>To create a new key, go to <a href="/admin/config/system/keys">/admin/config/system/keys</a>.<br>Tawk.to will use an <b>Authentication</b> key to secure the visitor recognition.</div>

<?php } ?>
</div>
</div>
</div>
<div class="panel-footer">
<div class="col-lg-6 col-xs-12" style="text-align: right; margin-bottom: 10px;">
<button type="submit" value="1" id="module_form_submit_btn" name="submitBlockCategories" class="btn btn-default pull-right"><i class="process-icon-save"></i> Save</button>
Expand Down Expand Up @@ -685,10 +798,15 @@ public function setOptions($options) {
$jsonOpts[$column] = json_encode($non_empty_values);
break;

case 'js_api_key':
$jsonOpts[$column] = trim($value);
break;

case 'show_onfrontpage':
case 'show_oncategory':
case 'always_display':
case 'enable_visitor_recognition':
case 'secure_mode_enabled':
$jsonOpts[$column] = $value == 1;
break;
}
Expand Down