PluginProbe
The Innovative Form Builder – IvyForms / 0.9.1
The Innovative Form Builder – IvyForms v0.9.1
1.5.1 1.5 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 All 27 releases
ivyforms / backend / src / Factory / Security / CaptchaProviderResolver.php

CaptchaProviderResolver.php in The Innovative Form Builder – IvyForms 0.9.1, at backend/src/Factory/Security/CaptchaProviderResolver.php

249 lines 6.5 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\Factory\Security;
9
10 // phpcs:disable PSR1.Files.SideEffects
11 if (!defined('ABSPATH')) {
12 exit; // Exit if accessed directly
13 }
14
15 use IvyForms\Services\Settings\SettingsService;
16
17 /**
18 * Resolver for determining which CAPTCHA provider to use
19 *
20 * Handles the business logic of provider selection based on form fields,
21 * configuration validation, and conflict detection.
22 *
23 * @package IvyForms\Factory\Security
24 */
25 class CaptchaProviderResolver
26 {
27 // Provider constants
28 public const PROVIDER_RECAPTCHA = 'recaptcha';
29 public const PROVIDER_HCAPTCHA = 'hcaptcha';
30 public const PROVIDER_TURNSTILE = 'turnstile';
31 public const PROVIDER_NONE = 'none';
32
33
34 private SettingsService $settingsService;
35
36 /** @var array<string, array<string>> */
37 private array $requiredKeys;
38
39 /** @var array<string, string> */
40 private array $fieldTypeMapping;
41
42 /**
43 * @param SettingsService $settingsService
44 * @param array<string, array<string>> $requiredKeys Provider required keys mapping
45 * @param array<string, string> $fieldTypeMapping Field type to provider mapping
46 */
47 public function __construct(
48 SettingsService $settingsService,
49 array $requiredKeys = [],
50 array $fieldTypeMapping = []
51 ) {
52 $this->settingsService = $settingsService;
53 $this->requiredKeys = $requiredKeys ?: $this->getDefaultRequiredKeys();
54 $this->fieldTypeMapping = $fieldTypeMapping ?: $this->getDefaultFieldTypeMapping();
55 }
56
57 /**
58 * Get the first configured provider
59 *
60 * @return string
61 */
62 public function getActiveProvider(): string
63 {
64 $providers = [
65 self::PROVIDER_RECAPTCHA,
66 self::PROVIDER_HCAPTCHA,
67 self::PROVIDER_TURNSTILE,
68 ];
69
70 foreach ($providers as $provider) {
71 if ($this->isConfigured($provider)) {
72 return $provider;
73 }
74 }
75
76 return self::PROVIDER_NONE;
77 }
78
79 /**
80 * Determine CAPTCHA provider based on form fields
81 *
82 * @param array<object> $formFields Array of form field objects
83 * @return string
84 */
85 public function resolveProviderForForm(array $formFields): string
86 {
87 foreach ($formFields as $field) {
88 $fieldType = $field->getType();
89 if (isset($this->fieldTypeMapping[$fieldType])) {
90 $provider = $this->fieldTypeMapping[$fieldType];
91 if ($this->isConfigured($provider)) {
92 return $provider;
93 }
94 }
95 }
96
97 return self::PROVIDER_NONE;
98 }
99
100 /**
101 * Check if a provider is properly configured
102 *
103 * @param string $provider
104 * @return bool
105 */
106 public function isConfigured(string $provider): bool
107 {
108 if (!isset($this->requiredKeys[$provider])) {
109 return false;
110 }
111
112 $settings = $this->settingsService->getSetting('security', $provider);
113 if (!is_array($settings)) {
114 return false;
115 }
116
117 $requiredKeys = $this->requiredKeys[$provider];
118 foreach ($requiredKeys as $key) {
119 if (empty($settings[$key])) {
120 return false;
121 }
122 }
123
124 return true;
125 }
126
127 /**
128 * Get all configured providers
129 *
130 * @return array<string>
131 */
132 public function getConfiguredProviders(): array
133 {
134 $configured = [];
135 $allProviders = [
136 self::PROVIDER_RECAPTCHA,
137 self::PROVIDER_HCAPTCHA,
138 self::PROVIDER_TURNSTILE,
139 ];
140
141 foreach ($allProviders as $provider) {
142 if ($this->isConfigured($provider)) {
143 $configured[] = $provider;
144 }
145 }
146
147 return $configured;
148 }
149
150 /**
151 * Check if form has multiple CAPTCHA field types (conflict detection)
152 *
153 * @param array<object> $formFields Array of form field objects
154 * @return array{hasConflict: bool, foundTypes: array<string>}
155 */
156 public function checkFormCaptchaConflicts(array $formFields): array
157 {
158 $foundTypes = [];
159
160 foreach ($formFields as $field) {
161 $fieldType = $field->getType();
162 if (isset($this->fieldTypeMapping[$fieldType])) {
163 if (!in_array($fieldType, $foundTypes, true)) {
164 $foundTypes[] = $fieldType;
165 }
166 }
167 }
168
169 return [
170 'hasConflict' => count($foundTypes) > 1,
171 'foundTypes' => $foundTypes,
172 ];
173 }
174
175 /**
176 * Get provider status summary
177 *
178 * @param array<string> $supportedProviders List of supported providers from factory
179 * @return array<string, array{supported: bool, configured: bool}>
180 */
181 public function getProviderStatus(array $supportedProviders = []): array
182 {
183 $status = [];
184 $allProviders = [
185 self::PROVIDER_RECAPTCHA,
186 self::PROVIDER_HCAPTCHA,
187 self::PROVIDER_TURNSTILE,
188 ];
189
190 foreach ($allProviders as $provider) {
191 $status[$provider] = [
192 'supported' => in_array($provider, $supportedProviders, true),
193 'configured' => $this->isConfigured($provider),
194 ];
195 }
196
197 return $status;
198 }
199
200 /**
201 * Get configuration requirements for a provider
202 *
203 * @param string $provider
204 * @return array<string>
205 */
206 public function getProviderRequiredKeys(string $provider): array
207 {
208 return $this->requiredKeys[$provider] ?? [];
209 }
210
211 /**
212 * Get field type mapping
213 *
214 * @return array<string, string>
215 */
216 public function getFieldTypeMapping(): array
217 {
218 return $this->fieldTypeMapping;
219 }
220
221 /**
222 * Get default required keys for providers
223 *
224 * @return array<string, array<string>>
225 */
226 private function getDefaultRequiredKeys(): array
227 {
228 return [
229 self::PROVIDER_RECAPTCHA => ['siteKey', 'secretKey'],
230 self::PROVIDER_HCAPTCHA => ['siteKey', 'secretKey'],
231 self::PROVIDER_TURNSTILE => ['siteKey', 'secretKey'],
232 ];
233 }
234
235 /**
236 * Get default field type to provider mapping
237 *
238 * @return array<string, string>
239 */
240 private function getDefaultFieldTypeMapping(): array
241 {
242 return [
243 'recaptcha' => self::PROVIDER_RECAPTCHA,
244 'hcaptcha' => self::PROVIDER_HCAPTCHA,
245 'turnstile' => self::PROVIDER_TURNSTILE,
246 ];
247 }
248 }
249