Skip to content

Commit 65cf42c

Browse files
author
magento packaging service
committed
Magento Release 2.4.6-p9
1 parent fc35000 commit 65cf42c

File tree

1,639 files changed

+59769
-40670
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,639 files changed

+59769
-40670
lines changed

app/code/Magento/AdminAnalytics/ViewModel/Metadata.php

+29-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
namespace Magento\AdminAnalytics\ViewModel;
1010

1111
use Magento\Config\Model\Config\Backend\Admin\Custom;
12+
use Magento\Csp\Helper\CspNonceProvider;
1213
use Magento\Framework\App\Config\ScopeConfigInterface;
14+
use Magento\Framework\App\ObjectManager;
1315
use Magento\Framework\App\ProductMetadataInterface;
1416
use Magento\Backend\Model\Auth\Session;
1517
use Magento\Framework\App\State;
@@ -21,6 +23,11 @@
2123
*/
2224
class Metadata implements ArgumentInterface
2325
{
26+
/**
27+
* @var string
28+
*/
29+
private $nonce;
30+
2431
/**
2532
* @var State
2633
*/
@@ -41,22 +48,33 @@ class Metadata implements ArgumentInterface
4148
*/
4249
private $config;
4350

51+
/**
52+
* @var CspNonceProvider
53+
*/
54+
private $nonceProvider;
55+
4456
/**
4557
* @param ProductMetadataInterface $productMetadata
4658
* @param Session $authSession
4759
* @param State $appState
4860
* @param ScopeConfigInterface $config
61+
* @param CspNonceProvider|null $nonceProvider
4962
*/
5063
public function __construct(
5164
ProductMetadataInterface $productMetadata,
5265
Session $authSession,
5366
State $appState,
54-
ScopeConfigInterface $config
67+
ScopeConfigInterface $config,
68+
CspNonceProvider $nonceProvider = null
5569
) {
5670
$this->productMetadata = $productMetadata;
5771
$this->authSession = $authSession;
5872
$this->appState = $appState;
5973
$this->config = $config;
74+
75+
$this->nonceProvider = $nonceProvider ?: ObjectManager::getInstance()->get(CspNonceProvider::class);
76+
77+
$this->nonce = $this->nonceProvider->generateNonce();
6078
}
6179

6280
/**
@@ -156,4 +174,14 @@ public function getCurrentUserRoleName(): string
156174
{
157175
return $this->authSession->getUser()->getRole()->getRoleName();
158176
}
177+
178+
/**
179+
* Get a random nonce for each request.
180+
*
181+
* @return string
182+
*/
183+
public function getNonce(): string
184+
{
185+
return $this->nonce;
186+
}
159187
}
+14-11
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
{
22
"name": "magento/module-admin-analytics",
33
"description": "N/A",
4+
"type": "magento2-module",
5+
"license": [
6+
"OSL-3.0",
7+
"AFL-3.0"
8+
],
49
"config": {
510
"sort-packages": true
611
},
12+
"version": "100.4.5-p6",
713
"require": {
814
"php": "~8.1.0||~8.2.0",
9-
"magento/framework": "*",
10-
"magento/module-backend": "*",
11-
"magento/module-config": "*",
12-
"magento/module-store": "*",
13-
"magento/module-ui": "*",
14-
"magento/module-release-notification": "*"
15+
"magento/framework": "103.0.*",
16+
"magento/module-backend": "102.0.*",
17+
"magento/module-config": "101.2.*",
18+
"magento/module-store": "101.1.*",
19+
"magento/module-ui": "101.2.*",
20+
"magento/module-release-notification": "100.4.*",
21+
"magento/module-csp": "100.4.*"
1522
},
16-
"type": "magento2-module",
17-
"license": [
18-
"OSL-3.0",
19-
"AFL-3.0"
20-
],
2123
"autoload": {
2224
"files": [
2325
"registration.php"
@@ -27,3 +29,4 @@
2729
}
2830
}
2931
}
32+

app/code/Magento/AdminAnalytics/view/adminhtml/templates/tracking.phtml

+17-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
/**
88
* @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer
9+
* @var \Magento\Framework\Escaper $escaper
910
*/
1011
?>
1112

@@ -22,18 +23,25 @@
2223
<?php
2324
/** @var \Magento\AdminAnalytics\ViewModel\Metadata $metadata */
2425
$metadata = $block->getMetadata();
26+
$nonce = $escaper->escapeJs($metadata->getNonce());
2527
$scriptString = '
2628
var adminAnalyticsMetadata = {
27-
"secure_base_url": "' . $block->escapeJs($metadata->getSecureBaseUrlForScope()) . '",
28-
"version": "' . $block->escapeJs($metadata->getMagentoVersion()) . '",
29-
"product_edition": "' . $block->escapeJs($metadata->getProductEdition()) . '",
30-
"user": "' . $block->escapeJs($metadata->getCurrentUser()) . '",
31-
"mode": "' . $block->escapeJs($metadata->getMode()) . '",
32-
"store_name_default": "' . $block->escapeJs($metadata->getStoreNameForScope()) . '",
33-
"admin_user_created": "' . $block->escapeJs($metadata->getCurrentUserCreatedDate()) . '",
34-
"admin_user_logdate": "' . $block->escapeJs($metadata->getCurrentUserLogDate()) . '",
35-
"admin_user_role_name": "' . $block->escapeJs($metadata->getCurrentUserRoleName()) . '"
29+
"secure_base_url": "' . $escaper->escapeJs($metadata->getSecureBaseUrlForScope()) . '",
30+
"version": "' . $escaper->escapeJs($metadata->getMagentoVersion()) . '",
31+
"product_edition": "' . $escaper->escapeJs($metadata->getProductEdition()) . '",
32+
"user": "' . $escaper->escapeJs($metadata->getCurrentUser()) . '",
33+
"mode": "' . $escaper->escapeJs($metadata->getMode()) . '",
34+
"store_name_default": "' . $escaper->escapeJs($metadata->getStoreNameForScope()) . '",
35+
"admin_user_created": "' . $escaper->escapeJs($metadata->getCurrentUserCreatedDate()) . '",
36+
"admin_user_logdate": "' . $escaper->escapeJs($metadata->getCurrentUserLogDate()) . '",
37+
"admin_user_role_name": "' . $escaper->escapeJs($metadata->getCurrentUserRoleName()) . '"
3638
};
39+
40+
var digitalData = {
41+
"nonce": "' . $nonce . '"
42+
};
43+
44+
var cspNonce = "' . $nonce . '";
3745
';
3846
?>
3947
<?= /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false); ?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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\AdminNotification\Block\Grid\MassAction;
9+
10+
use Magento\AdminNotification\Controller\Adminhtml\Notification\MarkAsRead;
11+
use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface;
12+
use Magento\Framework\AuthorizationInterface;
13+
14+
/**
15+
* Class checks if mark as read action can be displayed on massaction list
16+
*/
17+
class MarkAsReadVisibility implements VisibilityCheckerInterface
18+
{
19+
/**
20+
* @var AuthorizationInterface
21+
*/
22+
private $authorization;
23+
24+
/**
25+
* @param AuthorizationInterface $authorizationInterface
26+
*/
27+
public function __construct(AuthorizationInterface $authorizationInterface)
28+
{
29+
$this->authorization = $authorizationInterface;
30+
}
31+
32+
/**
33+
* @inheritdoc
34+
*/
35+
public function isVisible()
36+
{
37+
return $this->authorization->isAllowed(MarkAsRead::ADMIN_RESOURCE);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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\AdminNotification\Block\Grid\MassAction;
9+
10+
use Magento\AdminNotification\Controller\Adminhtml\Notification\Remove;
11+
use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface;
12+
use Magento\Framework\AuthorizationInterface;
13+
14+
/**
15+
* Class checks if remove action can be displayed on massaction list
16+
*/
17+
class RemoveVisibility implements VisibilityCheckerInterface
18+
{
19+
/**
20+
* @var AuthorizationInterface
21+
*/
22+
private $authorization;
23+
24+
/**
25+
* @param AuthorizationInterface $authorizationInterface
26+
*/
27+
public function __construct(AuthorizationInterface $authorizationInterface)
28+
{
29+
$this->authorization = $authorizationInterface;
30+
}
31+
32+
/**
33+
* @inheritdoc
34+
*/
35+
public function isVisible()
36+
{
37+
return $this->authorization->isAllowed(Remove::ADMIN_RESOURCE);
38+
}
39+
}

app/code/Magento/AdminNotification/Block/Grid/Renderer/Actions.php

+30-23
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
<?php
2-
declare(strict_types=1);
3-
42
/**
5-
* Adminhtml AdminNotification Severity Renderer
6-
*
73
* Copyright © Magento, Inc. All rights reserved.
84
* See COPYING.txt for license details.
95
*/
6+
declare(strict_types=1);
107

118
namespace Magento\AdminNotification\Block\Grid\Renderer;
129

10+
use Magento\AdminNotification\Controller\Adminhtml\Notification\MarkAsRead;
11+
use Magento\AdminNotification\Controller\Adminhtml\Notification\Remove;
1312
use Magento\Backend\Block\Context;
1413
use Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer;
1514
use Magento\Framework\App\ActionInterface;
@@ -45,33 +44,41 @@ public function __construct(Context $context, Data $urlHelper, array $data = [])
4544
*/
4645
public function render(DataObject $row)
4746
{
48-
$readDetailsHtml = $row->getUrl() ? '<a class="action-details" target="_blank" href="' .
47+
$readDetailsHtml = $row->getUrl() ?
48+
'<a class="action-details" target="_blank" href="' .
4949
$this->escapeUrl($row->getUrl())
5050
. '">' .
5151
__('Read Details') . '</a>' : '';
5252

53-
$markAsReadHtml = !$row->getIsRead() ? '<a class="action-mark" href="' . $this->getUrl(
54-
'*/*/markAsRead/',
55-
['_current' => true, 'id' => $row->getNotificationId()]
56-
) . '">' . __(
57-
'Mark as Read'
58-
) . '</a>' : '';
53+
$markAsReadHtml = !$row->getIsRead()
54+
&& $this->_authorization->isAllowed(MarkAsRead::ADMIN_RESOURCE) ?
55+
'<a class="action-mark" href="' . $this->escapeUrl($this->getUrl(
56+
'*/*/markAsRead/',
57+
['_current' => true, 'id' => $row->getNotificationId()]
58+
)) . '">' . __(
59+
'Mark as Read'
60+
) . '</a>' : '';
61+
62+
$removeUrl = $this->getUrl(
63+
'*/*/remove/',
64+
[
65+
'_current' => true,
66+
'id' => $row->getNotificationId(),
67+
ActionInterface::PARAM_NAME_URL_ENCODED => $this->_urlHelper->getEncodedUrl()
68+
]
69+
);
70+
71+
$removeHtml = $this->_authorization->isAllowed(Remove::ADMIN_RESOURCE) ?
72+
'<a class="action-delete" href="'
73+
. $this->escapeUrl($removeUrl)
74+
.'" onClick="deleteConfirm('. __('\'Are you sure?\'') .', this.href); return false;">'
75+
. __('Remove') . '</a>' : '';
5976

60-
$encodedUrl = $this->_urlHelper->getEncodedUrl();
6177
return sprintf(
62-
'%s%s<a class="action-delete" href="%s" onClick="deleteConfirm(\'%s\', this.href); return false;">%s</a>',
78+
'%s%s%s',
6379
$readDetailsHtml,
6480
$markAsReadHtml,
65-
$this->getUrl(
66-
'*/*/remove/',
67-
[
68-
'_current' => true,
69-
'id' => $row->getNotificationId(),
70-
ActionInterface::PARAM_NAME_URL_ENCODED => $encodedUrl
71-
]
72-
),
73-
__('Are you sure?'),
74-
__('Remove')
81+
$removeHtml,
7582
);
7683
}
7784
}

app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/AjaxMarkAsRead.php

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\AdminNotification\Controller\Adminhtml\Notification;
79

810
use Magento\AdminNotification\Controller\Adminhtml\Notification;
@@ -21,6 +23,13 @@ class AjaxMarkAsRead extends Notification implements HttpPostActionInterface
2123
*/
2224
private $notificationService;
2325

26+
/**
27+
* Authorization level of a basic admin session
28+
*
29+
* @see _isAllowed()
30+
*/
31+
public const ADMIN_RESOURCE = 'Magento_AdminNotification::mark_as_read';
32+
2433
/**
2534
* @param Action\Context $context
2635
* @param NotificationService $notificationService

app/code/Magento/AdminNotification/Test/Unit/Block/Grid/Renderer/ActionsTest.php

+11-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Magento\AdminNotification\Block\Grid\Renderer\Actions;
1616
use Magento\Backend\Block\Context;
1717
use Magento\Framework\DataObject;
18+
use Magento\Framework\AuthorizationInterface;
1819
use Magento\Framework\Escaper;
1920
use Magento\Framework\Url\Helper\Data;
2021
use Magento\Framework\UrlInterface;
@@ -35,16 +36,23 @@ protected function setUp(): void
3536

3637
/** @var Escaper|MockObject $escaperMock */
3738
$escaperMock = $this->createMock(Escaper::class);
38-
$escaperMock->expects($this->once())->method('escapeUrl')->willReturn('https://magento.com');
39+
$escaperMock->expects($this->atLeastOnce())->method('escapeUrl')->willReturn('https://magento.com');
40+
41+
/** @var AuthorizationInterface|MockObject $authorizationMock */
42+
$authorizationMock = $this->getMockForAbstractClass(AuthorizationInterface::class);
43+
$authorizationMock->expects($this->atLeastOnce())
44+
->method('isAllowed')
45+
->willReturn(true);
3946

4047
/** @var UrlInterface|MockObject $urlBuilder */
4148
$urlBuilder = $this->getMockForAbstractClass(UrlInterface::class);
4249
$urlBuilder->expects($this->once())->method('getUrl')->willReturn('http://magento.com');
4350

4451
/** @var Context|MockObject $contextMock */
4552
$contextMock = $this->createMock(Context::class);
46-
$contextMock->expects($this->once())->method('getEscaper')->willReturn($escaperMock);
53+
$contextMock->expects($this->atLeastOnce())->method('getEscaper')->willReturn($escaperMock);
4754
$contextMock->expects($this->once())->method('getUrlBuilder')->willReturn($urlBuilder);
55+
$contextMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock);
4856

4957
/** @var Data|MockObject $urlHelperMock */
5058
$urlHelperMock = $this->createMock(Data::class);
@@ -65,7 +73,7 @@ public function testShouldRenderMessageWhenUrlIsGiven() : void
6573
// Ignoring Code Style at this point due to the long HEREDOC
6674
// phpcs:disable
6775
$expected = <<<HTML
68-
<a class="action-details" target="_blank" href="https://magento.com">Read Details</a><a class="action-delete" href="http://magento.com" onClick="deleteConfirm('Are you sure?', this.href); return false;">Remove</a>
76+
<a class="action-details" target="_blank" href="https://magento.com">Read Details</a><a class="action-delete" href="https://magento.com" onClick="deleteConfirm('Are you sure?', this.href); return false;">Remove</a>
6977
HTML;
7078
// phpcs:enable
7179

0 commit comments

Comments
 (0)