diff --git a/HOOKS.md b/HOOKS.md index 863e17d73..b845200f9 100644 --- a/HOOKS.md +++ b/HOOKS.md @@ -1,5 +1,6 @@ ## Actions + site-reviews//form (Contracts\FormContract $form) site-reviews/action (string $hook, array $args) site-reviews/activated () site-reviews/addon/register (Application $app) @@ -37,7 +38,6 @@ site-reviews/review/updated/post_ids (Review $review, array $assignedPostIds) site-reviews/review/updated/user_ids (Review $review, array $assignedUserIds) site-reviews/review/verified (Review $review) - site-reviews/review-form (Contracts\FormContract $form) site-reviews/route/request (Request $request, string $hook) site-reviews/route/get// (Request $request) site-reviews/route// (Request $request) @@ -51,6 +51,12 @@ ## Filters + site-reviews//build/fields (string $rendered, Contracts\FormContract $form): string + site-reviews//build/response (string $rendered, Contracts\FormContract $form): string + site-reviews//build/submit_button (string $rendered, Contracts\FormContract $form): string + site-reviews//fields/all (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array + site-reviews//fields/hidden (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array + site-reviews//fields/visible (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array site-reviews/addon/api-url (string $apiUrl): string site-reviews/addon/documentation (array $documentation): array site-reviews/addon/documentation/tabs (array $tabs): array @@ -135,9 +141,6 @@ site-reviews/field/element/ (string $className, Contracts\FieldContract $field): string site-reviews/flyoutmenu/enabled (bool $bool): bool site-reviews/flyoutmenu/items (array $items): array - site-reviews/form/build/fields (string $rendered, Contracts\FormContract $form): string - site-reviews/form/build/response (string $rendered, Contracts\FormContract $form): string - site-reviews/form/build/submit_button (string $rendered, Contracts\FormContract $form): string site-reviews/fusion-builder/controls/site_review (array $parameters): array site-reviews/fusion-builder/controls/site_reviews (array $parameters): array site-reviews/fusion-builder/controls/site_reviews_form (array $parameters): array @@ -149,10 +152,7 @@ site-reviews/interpolate/ (array $context, string $template, array $data): array site-reviews/is-local-server (bool $bool): bool site-reviews/metabox-form/fields (array $fields, Contracts\FormContract $form): array - site-reviews/metabox-form/fields/all (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array - site-reviews/metabox-form/fields/hidden (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array site-reviews/metabox-form/fields/order (array $order): array - site-reviews/metabox-form/fields/visible (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array site-reviews/notices (array $notices): array site-reviews/notification/emails (array $emails, Review $review): array site-reviews/notification/tag/ (string $value, Review $review): string @@ -196,9 +196,6 @@ site-reviews/rest-api/summary/parameters (array $parameters): array site-reviews/rest-api/summary/schema/properties (array $properties): array site-reviews/review-form/fields (array[] $fields, Contracts\FormContract $form): array - site-reviews/review-form/fields/all (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array - site-reviews/review-form/fields/hidden (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array - site-reviews/review-form/fields/visible (Contracts\FieldContract[] $fields, Contracts\FormContract $form): array site-reviews/review-form/order (array $order): array site-reviews/review-form/referer (string $referer): string site-reviews/review-table/clauses (array $clauses, array $postClauses, \WP_Query $query): array diff --git a/languages/site-reviews-en_US.mo b/languages/site-reviews-en_US.mo index bd2ca2b59..0952ec397 100644 Binary files a/languages/site-reviews-en_US.mo and b/languages/site-reviews-en_US.mo differ diff --git a/languages/site-reviews-en_US.po b/languages/site-reviews-en_US.po index b7a4d48af..8de3efe67 100644 --- a/languages/site-reviews-en_US.po +++ b/languages/site-reviews-en_US.po @@ -92,7 +92,7 @@ msgstr "This review is based on my own experience and is my genuine opinion." msgid "Show more" msgstr "Show more" -#: plugin/Commands/CreateReview.php:165, views/pages/documentation/support/common-problems-and-solutions.php:89 +#: plugin/Commands/CreateReview.php:162, views/pages/documentation/support/common-problems-and-solutions.php:89 msgid "" "Your review could not be submitted and the error has been logged. Please " "notify the site administrator." @@ -100,11 +100,11 @@ msgstr "" "Your review could not be submitted and the error has been logged. Please " "notify the site administrator." -#: plugin/Commands/CreateReview.php:169 +#: plugin/Commands/CreateReview.php:166 msgid "Your review has been submitted!" msgstr "Your review has been submitted!" -#: plugin/Commands/CreateReview.php:170 +#: plugin/Commands/CreateReview.php:167 msgid "Your review has been submitted and is pending approval." msgstr "Your review has been submitted and is pending approval." @@ -380,11 +380,11 @@ msgstr "Write review of a user of a role" msgid "Write review of a specific user" msgstr "Write review of a specific user" -#: plugin/Modules/Html/Form.php:24 +#: plugin/Modules/Html/Form.php:26 msgid "Submit Form" msgstr "Submit Form" -#: plugin/Modules/Html/Form.php:25 +#: plugin/Modules/Html/Form.php:27 msgid "Submitting, please wait..." msgstr "Submitting, please wait..." @@ -412,7 +412,7 @@ msgstr "The CAPTCHA verification failed, please try again." msgid "The review submission failed. Please notify the site administrator." msgstr "The review submission failed. Please notify the site administrator." -#: plugin/Modules/Validator/DefaultValidator.php:27 +#: plugin/Modules/Validator/DefaultValidator.php:28 msgid "Please fix the form errors." msgstr "Please fix the form errors." @@ -428,6 +428,10 @@ msgstr "You must be logged in to submit a review." msgid "You have already submitted a review." msgstr "You have already submitted a review." +#: plugin/Modules/Validator/SignatureValidator.php:29 +msgid "This review cannot be submitted because the form was modified." +msgstr "This review cannot be submitted because the form was modified." + #: plugin/Integrations/UltimateMember/Controllers/ProfileController.php:41 msgid "Reviews" msgstr "Reviews" diff --git a/languages/site-reviews.pot b/languages/site-reviews.pot index 7c7598af5..8fee6aa25 100644 --- a/languages/site-reviews.pot +++ b/languages/site-reviews.pot @@ -1886,15 +1886,15 @@ msgctxt "admin-text" msgid "The %s table was successly converted to InnoDB." msgstr "" -#: plugin/Commands/CreateReview.php:165, views/pages/documentation/support/common-problems-and-solutions.php:89 +#: plugin/Commands/CreateReview.php:162, views/pages/documentation/support/common-problems-and-solutions.php:89 msgid "Your review could not be submitted and the error has been logged. Please notify the site administrator." msgstr "" -#: plugin/Commands/CreateReview.php:169 +#: plugin/Commands/CreateReview.php:166 msgid "Your review has been submitted!" msgstr "" -#: plugin/Commands/CreateReview.php:170 +#: plugin/Commands/CreateReview.php:167 msgid "Your review has been submitted and is pending approval." msgstr "" @@ -4848,11 +4848,11 @@ msgctxt "admin-text" msgid "Unapproved Review (Site Reviews)" msgstr "" -#: plugin/Modules/Html/Form.php:24 +#: plugin/Modules/Html/Form.php:26 msgid "Submit Form" msgstr "" -#: plugin/Modules/Html/Form.php:25 +#: plugin/Modules/Html/Form.php:27 msgid "Submitting, please wait..." msgstr "" @@ -4885,7 +4885,7 @@ msgstr "" msgid "The review submission failed. Please notify the site administrator." msgstr "" -#: plugin/Modules/Validator/DefaultValidator.php:27 +#: plugin/Modules/Validator/DefaultValidator.php:28 msgid "Please fix the form errors." msgstr "" @@ -4901,6 +4901,10 @@ msgstr "" msgid "You have already submitted a review." msgstr "" +#: plugin/Modules/Validator/SignatureValidator.php:29 +msgid "This review cannot be submitted because the form was modified." +msgstr "" + #: views/integrations/multilingualpress/assigned_posts-field.php:5 msgctxt "admin-text" msgid "Synchronize Assigned Posts" diff --git a/plugin/Commands/CreateReview.php b/plugin/Commands/CreateReview.php index 3c04e4aee..432c061e2 100644 --- a/plugin/Commands/CreateReview.php +++ b/plugin/Commands/CreateReview.php @@ -11,7 +11,6 @@ use GeminiLabs\SiteReviews\Helpers\Str; use GeminiLabs\SiteReviews\Helpers\Url; use GeminiLabs\SiteReviews\Modules\Avatar; -use GeminiLabs\SiteReviews\Modules\Encryption; use GeminiLabs\SiteReviews\Modules\Validator\CustomValidator; use GeminiLabs\SiteReviews\Modules\Validator\DefaultValidator; use GeminiLabs\SiteReviews\Modules\Validator\DuplicateValidator; @@ -82,9 +81,7 @@ public function isRequestValid(): bool Arr::consolidate(glsr()->settings('settings.forms.required.options')), $this->request->toArray(), )); - $request->merge([ - 'excluded' => glsr(Encryption::class)->encrypt(implode(',', $excluded)), - ]); + $request->merge(compact('excluded')); $validators = glsr()->filterArray('validators', [ // order is intentional DefaultValidator::class, DuplicateValidator::class, diff --git a/plugin/Controllers/MetaboxController.php b/plugin/Controllers/MetaboxController.php index 04233f234..6c96e7216 100644 --- a/plugin/Controllers/MetaboxController.php +++ b/plugin/Controllers/MetaboxController.php @@ -13,17 +13,6 @@ class MetaboxController extends AbstractController { - /** - * @filter site-reviews/metabox-form/fields - */ - public function filterFieldOrder(array $config): array - { - $order = array_keys($config); - $order = glsr()->filterArray('metabox-form/fields/order', $order); - $ordered = array_intersect_key(array_merge(array_flip($order), $config), $config); - return $ordered; - } - /** * @action add_meta_boxes_{glsr()->post_type} */ diff --git a/plugin/Controllers/PublicController.php b/plugin/Controllers/PublicController.php index aa808e050..d335e30a4 100644 --- a/plugin/Controllers/PublicController.php +++ b/plugin/Controllers/PublicController.php @@ -37,16 +37,6 @@ public function fetchPagedReviewsAjax(Request $request): void wp_send_json_success($response); } - /** - * @filter site-reviews/config/forms/review-form - */ - public function filterFieldOrder(array $config): array - { - $order = array_keys($config); - $order = glsr()->filterArray('review-form/order', $order); - return array_intersect_key(array_merge(array_flip($order), $config), $config); - } - /** * @filter site-reviews/render/view */ diff --git a/plugin/Defaults/CustomFieldsDefaults.php b/plugin/Defaults/CustomFieldsDefaults.php index 5bba91bdd..194d40b0c 100644 --- a/plugin/Defaults/CustomFieldsDefaults.php +++ b/plugin/Defaults/CustomFieldsDefaults.php @@ -36,6 +36,7 @@ class CustomFieldsDefaults extends DefaultsAbstract 'email', 'excluded', 'form_id', + 'form_signature', 'ID', 'ip_address', 'is_approved', diff --git a/plugin/Hooks/MetaboxHooks.php b/plugin/Hooks/MetaboxHooks.php index 482f6f9c8..3cc3532cf 100644 --- a/plugin/Hooks/MetaboxHooks.php +++ b/plugin/Hooks/MetaboxHooks.php @@ -9,7 +9,6 @@ class MetaboxHooks extends AbstractHooks public function run(): void { $this->hook(MetaboxController::class, [ - ['filterFieldOrder', 'site-reviews/metabox-form/fields', 30], ['registerMetaBoxes', "add_meta_boxes_{$this->type}"], ['removeMetaBoxes', 'do_meta_boxes'], ['renderPinnedAction', 'post_submitbox_misc_actions'], diff --git a/plugin/Hooks/PublicHooks.php b/plugin/Hooks/PublicHooks.php index c8bc6a45f..427297f0c 100644 --- a/plugin/Hooks/PublicHooks.php +++ b/plugin/Hooks/PublicHooks.php @@ -11,7 +11,6 @@ public function run(): void $this->hook(PublicController::class, [ ['enqueueAssets', 'wp_enqueue_scripts', 999], // run after all addons ['fetchPagedReviewsAjax', 'site-reviews/route/ajax/fetch-paged-reviews'], - ['filterFieldOrder', 'site-reviews/config/forms/review-form', 11], ['filterRenderView', 'site-reviews/render/view'], ['renderSchema', 'wp_footer'], ['submitReview', 'site-reviews/route/public/submit-review'], diff --git a/plugin/Modules/Html/Form.php b/plugin/Modules/Html/Form.php index 2a3610f25..38e5d1d54 100644 --- a/plugin/Modules/Html/Form.php +++ b/plugin/Modules/Html/Form.php @@ -9,6 +9,7 @@ use GeminiLabs\SiteReviews\Helpers\Cast; use GeminiLabs\SiteReviews\Helpers\Str; use GeminiLabs\SiteReviews\Modules\Captcha; +use GeminiLabs\SiteReviews\Modules\Encryption; use GeminiLabs\SiteReviews\Modules\Honeypot; use GeminiLabs\SiteReviews\Modules\Sanitizer; use GeminiLabs\SiteReviews\Modules\Style; @@ -16,6 +17,7 @@ class Form extends \ArrayObject implements FormContract { protected Arguments $args; + protected array $config; protected Arguments $session; public function __construct(array $args = [], array $values = []) @@ -28,9 +30,12 @@ public function __construct(array $args = [], array $values = []) $args['id'] = glsr(Sanitizer::class, ['values' => $args])->sanitizeIdHash(''); } $this->args = glsr()->args($args); + $this->config = $this->mergeconfig(); $this->loadSession($values); parent::__construct($this->fieldsAll(), \ArrayObject::STD_PROP_LIST | \ArrayObject::ARRAY_AS_PROPS); array_map([$this, 'normalizeConditions'], $this->fields()); + glsr()->action("{$this->formName()}/form", $this); + $this->signForm(); } public function args(): Arguments @@ -57,13 +62,24 @@ public function config(): array return []; } + public function configHidden(): array + { + return []; + } + public function field(string $name, array $args): FieldContract { - $field = new Field(wp_parse_args($args, compact('name'))); + $className = $this->fieldClass(); + $field = new $className(wp_parse_args($args, compact('name'))); $this->normalizeField($field); return $field; } + public function fieldClass(): string + { + return Field::class; + } + /** * @return FieldContract[] */ @@ -80,6 +96,13 @@ public function fieldsFor(string $group): array return array_filter($this->fields(), fn ($field) => $group === $field->group); } + public function formName(): string + { + $formName = (new \ReflectionClass($this))->getShortName(); + $formName = Str::dashCase($formName); + return $formName; + } + /** * @return FieldContract[] */ @@ -149,7 +172,7 @@ protected function buildFields(): string $fields[] = $field->build(); } $rendered = implode("\n", $fields); - $rendered = glsr()->filterString('form/build/fields', $rendered, $this); + $rendered = glsr()->filterString("{$this->formName()}/build/fields", $rendered, $this); return $rendered; } @@ -164,7 +187,7 @@ protected function buildResponse(): string 'has_errors' => !empty($this->session->errors), ]); $rendered = $captcha.$response; - $rendered = glsr()->filterString('form/build/response', $rendered, $this); + $rendered = glsr()->filterString("{$this->formName()}/build/response", $rendered, $this); return $rendered; } @@ -177,7 +200,7 @@ protected function buildSubmitButton(): string 'text' => $this->args->button_text, ], ]); - $rendered = glsr()->filterString('form/build/submit_button', $rendered, $this); + $rendered = glsr()->filterString("{$this->formName()}/build/submit_button", $rendered, $this); return $rendered; } @@ -220,8 +243,8 @@ protected function classAttrSubmitButton(): string */ protected function fieldsAll(): array { - $fields = array_merge($this->fieldsHidden(), $this->fieldsVisible()); - $fields = array_values($fields); + $fields = array_values(array_merge($this->fieldsHidden(), $this->fieldsVisible())); + $fields = glsr()->filterArray("{$this->formName()}/fields/all", $fields, $this); return $fields; } @@ -230,7 +253,18 @@ protected function fieldsAll(): array */ protected function fieldsHidden(): array { - return []; + $fields = []; + foreach ($this->config as $name => $args) { + if ('hidden' !== $args['type']) { + continue; + } + $field = $this->field($name, $args); + if ($field->isValid()) { + $fields[$name] = $field; + } + } + $fields = glsr()->filterArray("{$this->formName()}/fields/hidden", $fields, $this); + return $fields; } /** @@ -239,15 +273,36 @@ protected function fieldsHidden(): array protected function fieldsVisible(): array { $fields = []; - foreach ($this->config() as $name => $args) { + foreach ($this->config as $name => $args) { + if ('hidden' === $args['type']) { + continue; + } $field = $this->field($name, $args); if ($field->isValid()) { $fields[$name] = $field; } } + $fields = glsr()->filterArray("{$this->formName()}/fields/visible", $fields, $this); return $fields; } + protected function mergeConfig(): array + { + $assignmentKeys = ['assigned_posts', 'assigned_terms', 'assigned_users']; + $config = $this->config(); + foreach ($this->configHidden() as $name => $value) { + if (in_array($name, $assignmentKeys) && array_key_exists($name, $config)) { + continue; // allow visible assignment fields + } + $config[$name] = [ + 'type' => 'hidden', + 'value' => $value, + ]; + } + $config = array_filter($config, fn ($args) => !empty($args['type'])); + return $config; + } + /** * @todo Should this be done manually? This shouldn't be run when getting field rules for validation */ @@ -349,4 +404,19 @@ protected function normalizeFieldValue(FieldContract $field): void } $field->value = $value; } + + protected function signForm(): void + { + $hidden = $this->hidden(); + $values = []; + foreach ($hidden as $field) { + $values[$field->original_name] = $field->value; + } + $signatureField = $this->field('form_signature', [ + 'type' => 'hidden', + 'value' => glsr(Encryption::class)->encrypt(maybe_serialize($values)), + ]); + $fields = array_values(array_merge($hidden, [$signatureField], $this->visible())); + $this->exchangeArray($fields); + } } diff --git a/plugin/Modules/Html/MetaboxForm.php b/plugin/Modules/Html/MetaboxForm.php index 6bf870d7b..1bfd6fd68 100644 --- a/plugin/Modules/Html/MetaboxForm.php +++ b/plugin/Modules/Html/MetaboxForm.php @@ -43,14 +43,15 @@ public function config(): array 'data-value' => esc_js($value), ]); } - return $config; + $order = array_keys($config); + $order = glsr()->filterArray('metabox-form/fields/order', $order); + $ordered = array_intersect_key(array_merge(array_flip($order), $config), $config); + return $ordered; } - public function field(string $name, array $args): FieldContract + public function fieldClass(): string { - $field = new MetaboxField(wp_parse_args($args, compact('name'))); - $this->normalizeField($field); - return $field; + return MetaboxField::class; } protected function buildFields(): string @@ -66,36 +67,6 @@ protected function buildFields(): string return $rendered; } - /** - * @return FieldContract[] - */ - protected function fieldsAll(): array - { - $fields = parent::fieldsAll(); - $fields = glsr()->filterArray('metabox-form/fields/all', $fields, $this); - return $fields; - } - - /** - * @return FieldContract[] - */ - protected function fieldsHidden(): array - { - $fields = []; - $fields = glsr()->filterArray('metabox-form/fields/hidden', $fields, $this); - return $fields; - } - - /** - * @return FieldContract[] - */ - protected function fieldsVisible(): array - { - $fields = parent::fieldsVisible(); - $fields = glsr()->filterArray('metabox-form/fields/visible', $fields, $this); - return $fields; - } - /** * Normalize the field with the form's session data. * Any normalization that is not specific to the form or session data diff --git a/plugin/Modules/Html/ReviewForm.php b/plugin/Modules/Html/ReviewForm.php index e2cfc2ad5..70c06a0e0 100644 --- a/plugin/Modules/Html/ReviewForm.php +++ b/plugin/Modules/Html/ReviewForm.php @@ -24,40 +24,13 @@ public function config(): array { $config = glsr()->config('forms/review-form'); $config = glsr()->filterArray('review-form/fields', $config, $this); - return $config; - } - - public function field(string $name, array $args): FieldContract - { - $field = new ReviewField(wp_parse_args($args, compact('name'))); - $this->normalizeField($field); - return $field; - } - - public function loadSession(array $values): void - { - $this->session = glsr()->args([ - 'errors' => glsr()->session()->array('form_errors'), - 'failed' => glsr()->session()->cast('form_invalid', 'bool'), - 'message' => glsr()->session()->cast('form_message', 'string'), - 'values' => $values ?: glsr()->session()->array('form_values'), - ]); + $order = array_keys($config); + $order = glsr()->filterArray('review-form/order', $order); + $ordered = array_intersect_key(array_merge(array_flip($order), $config), $config); + return $ordered; } - /** - * @return FieldContract[] - */ - protected function fieldsAll(): array - { - $fields = parent::fieldsAll(); - $fields = glsr()->filterArray('review-form/fields/all', $fields, $this); - return $fields; - } - - /** - * @return FieldContract[] - */ - protected function fieldsHidden(): array + public function configHidden(): array { do_action('litespeed_nonce', 'submit-review'); // @litespeedcache $referer = glsr()->filterString('review-form/referer', wp_get_referer()); @@ -69,22 +42,26 @@ protected function fieldsHidden(): array 'assigned_posts' => $this->args->assigned_posts, 'assigned_terms' => $this->args->assigned_terms, 'assigned_users' => $this->args->assigned_users, - 'excluded' => glsr(Encryption::class)->encrypt($this->args->cast('hide', 'string')), + 'excluded' => $this->args->cast('hide', 'string'), 'form_id' => $this->args->id, 'terms_exist' => Cast::toInt(!in_array('terms', $this->args->cast('hide', 'array'))), ]; - $fields = []; - foreach ($config as $name => $value) { - $field = $this->field($name, [ - 'type' => 'hidden', - 'value' => $value, - ]); - if ($field->isValid()) { - $fields[$name] = $field; - } - } - $fields = glsr()->filterArray('review-form/fields/hidden', $fields, $this); - return $fields; + return $config; + } + + public function fieldClass(): string + { + return ReviewField::class; + } + + public function loadSession(array $values): void + { + $this->session = glsr()->args([ + 'errors' => glsr()->session()->array('form_errors'), + 'failed' => glsr()->session()->cast('form_invalid', 'bool'), + 'message' => glsr()->session()->cast('form_message', 'string'), + 'values' => $values ?: glsr()->session()->array('form_values'), + ]); } /** @@ -94,7 +71,6 @@ protected function fieldsVisible(): array { $fields = parent::fieldsVisible(); $fields = array_filter($fields, fn ($field) => !in_array($field->original_name, $this->args->cast('hide', 'array'))); - $fields = glsr()->filterArray('review-form/fields/visible', $fields, $this); return $fields; } } diff --git a/plugin/Modules/Html/SettingForm.php b/plugin/Modules/Html/SettingForm.php index 154714baf..742a5ac8b 100644 --- a/plugin/Modules/Html/SettingForm.php +++ b/plugin/Modules/Html/SettingForm.php @@ -41,16 +41,16 @@ public function config(): array public function field(string $name, array $args): FieldContract { - $args = wp_parse_args($args, [ - 'name' => $name, - ]); if (str_starts_with($name, 'settings.')) { $parts = explode('.', $name); $args['group'] = count($parts) > 2 ? $parts[1] : ''; } - $field = new SettingField($args); - $this->normalizeField($field); - return $field; + return parent::field($name, $args); + } + + public function fieldClass(): string + { + return SettingField::class; } protected function buildFields(): string diff --git a/plugin/Modules/Validator/DefaultValidator.php b/plugin/Modules/Validator/DefaultValidator.php index ed0be8f6b..57efa2f6c 100644 --- a/plugin/Modules/Validator/DefaultValidator.php +++ b/plugin/Modules/Validator/DefaultValidator.php @@ -3,6 +3,7 @@ namespace GeminiLabs\SiteReviews\Modules\Validator; use GeminiLabs\SiteReviews\Defaults\ValidateReviewDefaults; +use GeminiLabs\SiteReviews\Helpers\Arr; use GeminiLabs\SiteReviews\Helpers\Cast; use GeminiLabs\SiteReviews\Modules\Html\ReviewForm; use GeminiLabs\SiteReviews\Modules\Validator; @@ -35,12 +36,12 @@ public function request(): Request public function rules(): array { - // exclude fields omitted with the hide option - $excluded = Cast::toArray($this->request->decrypt('excluded')); $form = new ReviewForm([], $this->request->toArray()); // skip fields which are conditionally hidden $fields = array_filter($form->visible(), fn ($field) => !$field->is_hidden); $rules = array_filter(wp_list_pluck($fields, 'validation', 'original_name')); + // exclude fields omitted with the hide option + $excluded = Arr::convertFromString($this->request->cast('excluded', 'string')); $rules = array_diff_key($rules, array_flip($excluded)); return glsr()->filterArray('validation/rules', $rules, $this->request); } diff --git a/plugin/Modules/Validator/SignatureValidator.php b/plugin/Modules/Validator/SignatureValidator.php new file mode 100644 index 000000000..6bcc3f80a --- /dev/null +++ b/plugin/Modules/Validator/SignatureValidator.php @@ -0,0 +1,34 @@ +request->decrypt('form_signature'); + $values = maybe_unserialize($signature); + $values = wp_parse_args($values, ['form_id' => '']); + foreach ($values as $key => $value) { + if (Cast::toString($value) !== $this->request->cast($key, 'string')) { + $isValid = false; + glsr_log()->debug($values); + break; + } + } + return glsr()->filterBool('validate/signature', $isValid, $this->request); + } + + public function performValidation(): void + { + if (!$this->isValid()) { + $this->fail( + __('This review cannot be submitted because the form was modified.', 'site-reviews'), + 'The form signature could not be verified.' + ); + } + } +} diff --git a/plugin/Modules/Validator/ValidateForm.php b/plugin/Modules/Validator/ValidateForm.php index 8928f2bfb..42e1a9007 100644 --- a/plugin/Modules/Validator/ValidateForm.php +++ b/plugin/Modules/Validator/ValidateForm.php @@ -82,6 +82,7 @@ public function validators(array $validatorClasses = []): array { $defaults = [ // order is intentional DefaultValidator::class, + SignatureValidator::class, CustomValidator::class, PermissionValidator::class, DuplicateValidator::class,