PluginProbe
The Innovative Form Builder – IvyForms / 0.8
The Innovative Form Builder – IvyForms v0.8
1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 1.2 1.3
ivyforms / backend / src / Services / Security / RecaptchaCredentialsValidator.php

RecaptchaCredentialsValidator.php in The Innovative Form Builder – IvyForms 0.8, at backend/src/Services/Security/RecaptchaCredentialsValidator.php

183 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @copyright © Melograno Venture Studio. All rights reserved.
5 * @licence See COPYING.md for license details.
6 */
7
8 namespace IvyForms\Services\Security;
9
10 // phpcs:disable PSR1.Files.SideEffects
11 if (!defined('ABSPATH')) {
12 exit; // Exit if accessed directly
13 }
14
15 use IvyForms\Services\Translations\BackendStrings;
16
17 /**
18 * Handles reCAPTCHA credentials validation
19 *
20 * Extracted from RecaptchaService to reduce complexity
21 *
22 * @package IvyForms\Services\Security
23 */
24 class RecaptchaCredentialsValidator
25 {
26 /**
27 * Validate reCAPTCHA key format
28 *
29 * @param string $key
30 * @return bool
31 */
32 public static function validateKeyFormat(string $key): bool
33 {
34 if (empty($key)) {
35 return false;
36 }
37
38 // reCAPTCHA keys are typically 40 characters long
39 if (strlen($key) !== 40) {
40 return false;
41 }
42
43 // Basic format validation - should contain alphanumeric characters and some special chars
44 if (!preg_match('/^[A-Za-z0-9_-]+$/', $key)) {
45 return false;
46 }
47
48 // reCAPTCHA site and secret keys typically start with specific prefixes
49 $validPrefixes = ['6L', '6I']; // Common reCAPTCHA key prefixes
50
51 foreach ($validPrefixes as $prefix) {
52 if (strpos($key, $prefix) === 0) {
53 return true;
54 }
55 }
56
57 return false;
58 }
59
60 /**
61 * Validate both site key and secret key formats
62 *
63 * @param string $siteKey
64 * @param string $secretKey
65 * @return array{success: bool, message: string}
66 */
67 public static function validateKeyFormats(string $siteKey, string $secretKey): array
68 {
69 $strings = BackendStrings::getSecurityStrings();
70
71 if (!self::validateKeyFormat($siteKey)) {
72 return [
73 'success' => false,
74 'message' => $strings['recaptcha_invalid_site_key']
75 ];
76 }
77
78 if (!self::validateKeyFormat($secretKey)) {
79 return [
80 'success' => false,
81 'message' => $strings['recaptcha_invalid_key_format']
82 ];
83 }
84
85 return ['success' => true, 'message' => ''];
86 }
87
88 /**
89 * Process Google API verification result
90 *
91 * @param array<string, mixed>|false $verificationResult
92 * @return array{success: bool, message: string}
93 */
94 public static function processVerificationResult($verificationResult): array
95 {
96 $strings = BackendStrings::getSecurityStrings();
97
98 if ($verificationResult === false) {
99 return [
100 'success' => false,
101 'message' => $strings['recaptcha_validation_network_error']
102 ];
103 }
104
105 return self::checkErrorCodes($verificationResult, $strings);
106 }
107
108 /**
109 * Check for specific error codes in verification result
110 *
111 * @param array<string, mixed> $verificationResult
112 * @param array<string, string> $strings
113 * @return array{success: bool, message: string}
114 */
115 private static function checkErrorCodes(array $verificationResult, array $strings): array
116 {
117 if (!isset($verificationResult['error-codes'])) {
118 return self::handleSuccessCase($verificationResult, $strings);
119 }
120
121 $errorCodes = $verificationResult['error-codes'];
122
123 if (in_array('invalid-input-secret', $errorCodes)) {
124 return [
125 'success' => false,
126 'message' => $strings['recaptcha_invalid_secret_key']
127 ];
128 }
129
130 if (in_array('missing-input-secret', $errorCodes)) {
131 return [
132 'success' => false,
133 'message' => $strings['recaptcha_keys_required']
134 ];
135 }
136
137 // If we get 'invalid-input-response' or 'missing-input-response',
138 // it means the secret key is valid but our test token is invalid
139 if (self::hasValidSecretKeyErrors($errorCodes)) {
140 return [
141 'success' => true,
142 'message' => $strings['recaptcha_credentials_valid']
143 ];
144 }
145
146 return self::handleSuccessCase($verificationResult, $strings);
147 }
148
149 /**
150 * Check if error codes indicate valid secret key
151 *
152 * @param array<string> $errorCodes
153 * @return bool
154 */
155 private static function hasValidSecretKeyErrors(array $errorCodes): bool
156 {
157 return in_array('invalid-input-response', $errorCodes) ||
158 in_array('missing-input-response', $errorCodes);
159 }
160
161 /**
162 * Handle the success case of verification
163 *
164 * @param array<string, mixed> $verificationResult
165 * @param array<string, string> $strings
166 * @return array{success: bool, message: string}
167 */
168 private static function handleSuccessCase(array $verificationResult, array $strings): array
169 {
170 if (!$verificationResult['success']) {
171 return [
172 'success' => false,
173 'message' => $strings['recaptcha_unable_to_validate']
174 ];
175 }
176
177 return [
178 'success' => true,
179 'message' => $strings['recaptcha_credentials_valid']
180 ];
181 }
182 }
183