PluginProbe
The Innovative Form Builder – IvyForms / 1.5.1
The Innovative Form Builder – IvyForms v1.5.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 1.5.1, at backend/src/Factory/Security/CaptchaProviderResolver.php

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