PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
← All changes | app/Services/Transfer/TransferService.php +40 -0 6.2.14 → 6.2.15 View file →
@@ -3,8 +3,9 @@
3 3 namespace FluentForm\App\Services\Transfer;
4 4
5 5 defined('ABSPATH') or die;
6 6
7 +use FluentForm\App\Services\FormBuilder\AutocompleteTokens;
7 8 use Exception;
8 9 use FluentForm\App\Helpers\Helper;
9 10 use FluentForm\App\Models\Form;
10 11 use FluentForm\App\Models\FormMeta;
@@ -50,8 +51,9 @@
50 51 if (is_array($node)) {
51 52 foreach ($node as $key => &$value) {
52 53 if ('attributes' === $key) {
53 54 $value = self::dropEventHandlerAttributeKeys($value);
55 + $value = self::sanitizeFieldAttributes($value);
54 56 }
55 57 $value = self::sanitizeAttributeControlSetting($key, $value);
56 58 self::sanitizeJsonNode($value);
57 59 }
@@ -59,8 +61,9 @@
59 61 } elseif (is_object($node)) {
60 62 foreach (get_object_vars($node) as $key => $value) {
61 63 if ('attributes' === $key) {
62 64 $value = self::dropEventHandlerAttributeKeys($value);
65 + $value = self::sanitizeFieldAttributes($value);
63 66 }
64 67 $value = self::sanitizeAttributeControlSetting($key, $value);
65 68 self::sanitizeJsonNode($value);
66 69 $node->{$key} = $value;
@@ -69,8 +72,22 @@
69 72 $node = wp_kses_post($node);
70 73 }
71 74 }
72 75
76 + // Scoped to a field's own attributes: sanitizeJsonNode() walks the whole meta
77 + // tree, so matching on key name alone would rewrite any unrelated property
78 + // that happens to be called autocomplete.
79 + private static function sanitizeFieldAttributes($attributes)
80 + {
81 + if (is_object($attributes) && property_exists($attributes, 'autocomplete')) {
82 + $attributes->autocomplete = AutocompleteTokens::sanitize($attributes->autocomplete);
83 + } elseif (is_array($attributes) && array_key_exists('autocomplete', $attributes)) {
84 + $attributes['autocomplete'] = AutocompleteTokens::sanitize($attributes['autocomplete']);
85 + }
86 +
87 + return $attributes;
88 + }
89 +
73 90 private static function sanitizeAttributeControlSetting($key, $value)
74 91 {
75 92 if ('max_repeat_field' === $key) {
76 93 return is_scalar($value) && '' !== trim((string) $value) ? absint($value) : '';
@@ -360,8 +377,9 @@
360 377 $type = sanitize_key(Arr::get($args, 'format', 'csv'));
361 378 if (!in_array($type, ['csv', 'ods', 'xlsx', 'json'])) {
362 379 exit('Invalid requested format');
363 380 }
381 + self::markDownloadStarted(Arr::get($args, 'download_token'));
364 382 if ('json' == $type) {
365 383 self::exportAsJSON($form, $args);
366 384 }
367 385 if (!defined('FLUENTFORM_DOING_CSV_EXPORT')) {
@@ -674,8 +692,30 @@
674 692 $sanitizedTitle = 'export';
675 693 }
676 694
677 695 return $sanitizedTitle . '-' . date('Y-m-d');
696 + }
697 +
698 + /**
699 + * Set a short-lived cookie the admin page polls to know the download has started.
700 + *
701 + * @param string|null $token
702 + * @return void
703 + */
704 + private static function markDownloadStarted($token)
705 + {
706 + $token = substr(sanitize_key((string) $token), 0, 32);
707 +
708 + if (!$token || headers_sent()) {
709 + return;
710 + }
711 +
712 + setcookie('ff_export_' . $token, '1', [
713 + 'expires' => time() + 60,
714 + 'path' => '/',
715 + 'secure' => is_ssl(),
716 + 'samesite' => 'Lax',
717 + ]);
678 718 }
679 719
680 720 private static function sendDownloadHeaders($contentType, $fileName)
681 721 {