Skip to content

Commit 9310f3f

Browse files
security-package/issues/101: Split config between reCAPTCHA modules.
1 parent 974f94b commit 9310f3f

File tree

2 files changed

+245
-45
lines changed

2 files changed

+245
-45
lines changed

ReCaptchaMigration/Setup/Patch/Data/MigrateConfigFromGeneralScope.php renamed to ReCaptchaMigration/Setup/Patch/Data/CopyConfigFromOldModule.php

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
use Magento\Framework\Setup\Patch\PatchVersionInterface;
1414

1515
/**
16-
* Migrate config values from general to frontend and backend scopes.
16+
* Change namespace from MageSpecialist to Magento
1717
*/
18-
class MigrateConfigFromGeneralScope implements DataPatchInterface, PatchVersionInterface
18+
class CopyConfigFromOldModule implements DataPatchInterface, PatchVersionInterface
1919
{
2020
/**
2121
* @var ModuleDataSetupInterface
@@ -41,70 +41,49 @@ public function __construct(
4141

4242
/**
4343
* @inheritdoc
44+
*
45+
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
46+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
47+
* @SuppressWarnings(PHPMD.NPathComplexity)
4448
*/
4549
public function apply()
4650
{
47-
$this->copyConfig(
48-
[
49-
'recaptcha/general' => 'recaptcha/frontend',
50-
]
51-
);
52-
$this->copyConfig(
53-
[
54-
'recaptcha/general' => 'recaptcha/backend',
55-
]
56-
);
51+
$this->copyConfig([
52+
'msp_securitysuite_recaptcha' => 'recaptcha'
53+
]);
5754
}
5855

5956
/**
60-
* Move config values from srcPath to dstPath.
57+
* Move config from srcPath to dstPath
6158
*
6259
* @param array $paths
6360
*/
6461
private function copyConfig(array $paths): void
6562
{
63+
$connection = $this->moduleDataSetup->getConnection();
64+
65+
$configDataTable = $this->moduleDataSetup->getTable('core_config_data');
66+
6667
foreach ($paths as $srcPath => $dstPath) {
6768
$value = $this->scopeConfig->getValue($srcPath);
6869
if (is_array($value)) {
6970
foreach (array_keys($value) as $v) {
7071
$this->copyConfig([$srcPath . '/' . $v => $dstPath . '/' . $v]);
7172
}
7273
} else {
73-
$this->copyRecord($srcPath, $dstPath);
74-
}
75-
}
76-
}
77-
78-
/**
79-
* Copy one config record.
80-
*
81-
* Skip if record on destination path already exists.
82-
*
83-
* @param string $srcPath
84-
* @param string $dstPath
85-
*/
86-
private function copyRecord(string $srcPath, string $dstPath): void
87-
{
88-
$connection = $this->moduleDataSetup->getConnection();
89-
$configDataTable = $this->moduleDataSetup->getTable('core_config_data');
90-
91-
$dstSelect = $connection->select()
92-
->from($configDataTable)
93-
->where('path = ?', $dstPath);
94-
95-
if (!$connection->fetchOne($dstSelect)) {
96-
$srcSelect = $connection->select()
97-
->from($configDataTable)
98-
->where('path = ?', $srcPath);
74+
$sel = $connection->select()
75+
->from($configDataTable)
76+
->where('path = ?', $srcPath);
9977

100-
$rows = $connection->fetchAll($srcSelect);
101-
foreach ($rows as $row) {
102-
unset($row['config_id']);
103-
$row['path'] = $dstPath;
78+
$rows = $connection->fetchAll($sel);
79+
foreach ($rows as $row) {
80+
unset($row['config_id']);
81+
$row['path'] = $dstPath;
10482

105-
$connection->insert($configDataTable, $row);
83+
$connection->insert($configDataTable, $row);
84+
}
10685
}
107-
};
86+
}
10887
}
10988

11089
/**
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\ReCaptchaMigration\Setup\Patch\Data;
9+
10+
use Magento\Framework\App\Config\ScopeConfigInterface;
11+
use Magento\Framework\App\Config\Storage\WriterInterface;
12+
use Magento\Framework\Setup\ModuleDataSetupInterface;
13+
use Magento\Framework\Setup\Patch\DataPatchInterface;
14+
use Magento\Framework\Setup\Patch\PatchVersionInterface;
15+
16+
/**
17+
* Migrate config from frontend and backend scopes to recaptcha modules.
18+
*/
19+
class MigrateConfigToRecaptchaModules implements DataPatchInterface, PatchVersionInterface
20+
{
21+
/**
22+
* @var ModuleDataSetupInterface
23+
*/
24+
private $moduleDataSetup;
25+
26+
/**
27+
* @var ScopeConfigInterface
28+
*/
29+
private $scopeConfig;
30+
31+
/**
32+
* @var WriterInterface
33+
*/
34+
private $writer;
35+
36+
/**
37+
* @param ModuleDataSetupInterface $moduleDataSetup
38+
* @param ScopeConfigInterface $scopeConfig
39+
* @param WriterInterface $writer
40+
*/
41+
public function __construct(
42+
ModuleDataSetupInterface $moduleDataSetup,
43+
ScopeConfigInterface $scopeConfig,
44+
WriterInterface $writer
45+
) {
46+
$this->moduleDataSetup = $moduleDataSetup;
47+
$this->scopeConfig = $scopeConfig;
48+
$this->writer = $writer;
49+
}
50+
51+
/**
52+
* @inheritdoc
53+
*/
54+
public function apply()
55+
{
56+
$scopes = ['frontend', 'backend'];
57+
foreach ($scopes as $scope) {
58+
$this->copyRecaptchaKeys($scope);
59+
$this->copyModuleSpecificRecords($scope);
60+
$this->copyEnabledRecaptcha($scope);
61+
}
62+
}
63+
64+
/**
65+
* Copy 'enabled' reCAPTCHA.
66+
*
67+
* @param string $scope
68+
*/
69+
private function copyEnabledRecaptcha(string $scope): void
70+
{
71+
$type = $this->getActiveRecaptchaType();
72+
if (!$type) {
73+
return;
74+
}
75+
76+
$availableRecaptchaPreferences = $this->getAvailableRecaptchaPreferences();
77+
foreach ($availableRecaptchaPreferences[$scope] as $availableRecaptchaPreference) {
78+
$availableRecaptchaPreferencePath = "recaptcha_$scope/type_for/$availableRecaptchaPreference";
79+
$recaptchaPreferenceEnabled = $this->scopeConfig->getValue($availableRecaptchaPreferencePath);
80+
$recaptchaPreferenceEnabledLegacy = $this->scopeConfig->getValue("recaptcha/general/enabled_for_$availableRecaptchaPreference");
81+
if (null === $recaptchaPreferenceEnabled && null !== $recaptchaPreferenceEnabledLegacy) {
82+
$this->writer->save($availableRecaptchaPreferencePath, (int)$recaptchaPreferenceEnabledLegacy ? $type : null);
83+
}
84+
}
85+
}
86+
87+
/**
88+
* Copy reCAPTCHA keys.
89+
*
90+
* @param string $scope
91+
*/
92+
private function copyRecaptchaKeys(string $scope): void
93+
{
94+
$keys = ['public_key', 'private_key'];
95+
$type = $this->getActiveRecaptchaType();
96+
foreach ($keys as $key) {
97+
$this->copyRecord("recaptcha/general/$key", "recaptcha_$scope/type_$type/$key");
98+
}
99+
}
100+
101+
/**
102+
* Copy module-specific records.
103+
*
104+
* @param string $scope
105+
*/
106+
private function copyModuleSpecificRecords(string $scope): void
107+
{
108+
foreach ($this->getModuleSpecificRecords() as $module => $specificRecords) {
109+
foreach ($specificRecords as $specificRecord) {
110+
$this->copyRecord("recaptcha/general/$specificRecord", "recaptcha_$scope/type_$module/$specificRecord");
111+
}
112+
}
113+
114+
}
115+
116+
/**
117+
* Get module-specific records.
118+
*
119+
* @return array
120+
*/
121+
private function getModuleSpecificRecords(): array
122+
{
123+
return [
124+
'recaptcha' => ['theme', 'size', 'lang'],
125+
'invisible' => ['position'],
126+
'recaptcha_v3' => ['score_threshold', 'position'],
127+
];
128+
}
129+
130+
/**
131+
* Get available recaptcha preferences.
132+
*
133+
* @return array
134+
*/
135+
private function getAvailableRecaptchaPreferences(): array
136+
{
137+
return [
138+
'frontend' => [
139+
'customer_login',
140+
'customer_forgot_password',
141+
'customer_create',
142+
'contact',
143+
'product_review',
144+
'newsletter',
145+
'sendfriend',
146+
],
147+
'backend' => [
148+
'user_login',
149+
'user_forgot_password',
150+
],
151+
];
152+
}
153+
154+
/**
155+
* Get active reCAPTCHA type from config (recaptcha/scope/type).
156+
*
157+
* @return string|null
158+
*/
159+
private function getActiveRecaptchaType(): ?string
160+
{
161+
return $this->scopeConfig->getValue('recaptcha/general/type');
162+
}
163+
164+
/**
165+
* Copy one config record.
166+
*
167+
* Skip if record on destination path already exists.
168+
*
169+
* @param string $srcPath
170+
* @param string $dstPath
171+
*/
172+
private function copyRecord(string $srcPath, string $dstPath): void
173+
{
174+
$connection = $this->moduleDataSetup->getConnection();
175+
$configDataTable = $this->moduleDataSetup->getTable('core_config_data');
176+
177+
$dstSelect = $connection->select()
178+
->from($configDataTable)
179+
->where('path = ?', $dstPath);
180+
181+
if (!$connection->fetchOne($dstSelect)) {
182+
$srcSelect = $connection->select()
183+
->from($configDataTable)
184+
->where('path = ?', $srcPath);
185+
186+
$rows = $connection->fetchAll($srcSelect);
187+
foreach ($rows as $row) {
188+
unset($row['config_id']);
189+
$row['path'] = $dstPath;
190+
191+
$connection->insert($configDataTable, $row);
192+
}
193+
};
194+
}
195+
196+
/**
197+
* @inheritdoc
198+
*/
199+
public static function getDependencies()
200+
{
201+
return [
202+
CopyConfigFromOldModule::class,
203+
];
204+
}
205+
206+
/**
207+
* @inheritdoc
208+
*/
209+
public static function getVersion()
210+
{
211+
return '3.0.0';
212+
}
213+
214+
/**
215+
* @inheritdoc
216+
*/
217+
public function getAliases()
218+
{
219+
return [];
220+
}
221+
}

0 commit comments

Comments
 (0)