Skip to content

Commit 4bf6e1c

Browse files
committed
ACP2E-3854: Bundled/Merged JS not part of SRI Hashes
1 parent 364dcdb commit 4bf6e1c

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Csp\Plugin;
9+
10+
use Magento\Csp\Model\SubresourceIntegrity\HashGenerator;
11+
use Magento\Csp\Model\SubresourceIntegrityCollector;
12+
use Magento\Csp\Model\SubresourceIntegrityFactory;
13+
use Magento\Deploy\Service\Bundle;
14+
use Magento\Framework\App\Filesystem\DirectoryList;
15+
use Magento\Framework\App\Utility\Files;
16+
use Magento\Framework\Exception\FileSystemException;
17+
use Magento\Framework\Filesystem;
18+
19+
class GenerateBundleAssetIntegrity
20+
{
21+
/**
22+
* @var HashGenerator
23+
*/
24+
private HashGenerator $hashGenerator;
25+
26+
/**
27+
* @var SubresourceIntegrityFactory
28+
*/
29+
private SubresourceIntegrityFactory $integrityFactory;
30+
31+
/**
32+
* @var SubresourceIntegrityCollector
33+
*/
34+
private SubresourceIntegrityCollector $integrityCollector;
35+
36+
/**
37+
* @var Filesystem
38+
*/
39+
private Filesystem $filesystem;
40+
41+
/**
42+
* @var Files
43+
*/
44+
private Files $utilityFiles;
45+
46+
/**
47+
* @param HashGenerator $hashGenerator
48+
* @param SubresourceIntegrityFactory $integrityFactory
49+
* @param SubresourceIntegrityCollector $integrityCollector
50+
* @param Filesystem $filesystem
51+
* @param Files $utilityFiles
52+
*/
53+
public function __construct(
54+
HashGenerator $hashGenerator,
55+
SubresourceIntegrityFactory $integrityFactory,
56+
SubresourceIntegrityCollector $integrityCollector,
57+
Filesystem $filesystem,
58+
Files $utilityFiles
59+
) {
60+
$this->hashGenerator = $hashGenerator;
61+
$this->integrityFactory = $integrityFactory;
62+
$this->integrityCollector = $integrityCollector;
63+
$this->filesystem = $filesystem;
64+
$this->utilityFiles = $utilityFiles;
65+
}
66+
67+
/**
68+
* @param Bundle $subject
69+
* @param string|null $result
70+
* @param string $area
71+
* @param string $theme
72+
* @param string $locale
73+
* @return void
74+
* @throws FileSystemException
75+
*/
76+
public function afterDeploy(Bundle $subject, ?string $result, string $area, string $theme, string $locale)
77+
{
78+
if (PHP_SAPI == 'cli') {
79+
$pubStaticDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
80+
$bundleDir = $pubStaticDir->getAbsolutePath($area . '/' . $theme . '/' . $locale) .
81+
"/". Bundle::BUNDLE_JS_DIR;
82+
$files = $this->utilityFiles->getFiles([$bundleDir], '*.js');
83+
84+
foreach ($files as $file) {
85+
$integrity = $this->integrityFactory->create(
86+
[
87+
"data" => [
88+
'hash' => $this->hashGenerator->generate(
89+
file_get_contents($file)
90+
),
91+
'path' => $area . '/' . $theme . '/' . $locale .
92+
"/" . Bundle::BUNDLE_JS_DIR . '/' . basename($file)
93+
]
94+
]
95+
);
96+
97+
$this->integrityCollector->collect($integrity);
98+
}
99+
}
100+
}
101+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Csp\Plugin;
9+
10+
use Magento\Csp\Model\SubresourceIntegrityRepositoryPool;
11+
use Magento\Csp\Model\SubresourceIntegrityRepository;
12+
use Magento\Csp\Model\SubresourceIntegrity\HashGenerator;
13+
use Magento\Csp\Model\SubresourceIntegrityFactory;
14+
use Magento\Framework\App\Area;
15+
use Magento\Framework\App\Filesystem\DirectoryList;
16+
use Magento\Framework\Filesystem;
17+
use Magento\Framework\View\Asset\LocalInterface;
18+
use Magento\Framework\View\Asset\MergeStrategy\FileExists;
19+
20+
class GenerateMergedAssetIntegrity
21+
{
22+
/**
23+
* @var SubresourceIntegrityRepository
24+
*/
25+
private SubresourceIntegrityRepository $sourceIntegrityRepository;
26+
27+
/**
28+
* @var HashGenerator
29+
*/
30+
private HashGenerator $hashGenerator;
31+
32+
/**
33+
* @var SubresourceIntegrityFactory
34+
*/
35+
private SubresourceIntegrityFactory $integrityFactory;
36+
37+
/**
38+
* @var Filesystem
39+
*/
40+
private Filesystem $filesystem;
41+
42+
/**
43+
* @param SubresourceIntegrityRepositoryPool $sourceIntegrityRepositoryPool
44+
* @param HashGenerator $hashGenerator
45+
* @param SubresourceIntegrityFactory $integrityFactory
46+
* @param Filesystem $filesystem
47+
*/
48+
public function __construct(
49+
SubresourceIntegrityRepositoryPool $sourceIntegrityRepositoryPool,
50+
HashGenerator $hashGenerator,
51+
SubresourceIntegrityFactory $integrityFactory,
52+
Filesystem $filesystem
53+
) {
54+
$this->sourceIntegrityRepository = $sourceIntegrityRepositoryPool->get(Area::AREA_FRONTEND);
55+
$this->hashGenerator = $hashGenerator;
56+
$this->integrityFactory = $integrityFactory;
57+
$this->filesystem = $filesystem;
58+
}
59+
60+
/**
61+
* @param FileExists $subject
62+
* @param string|null $result
63+
* @param array $assetsToMerge
64+
* @param LocalInterface $resultAsset
65+
* @return string|null
66+
* @throws \Magento\Framework\Exception\FileSystemException
67+
*/
68+
public function afterMerge(FileExists $subject, ?string $result, array $assetsToMerge, LocalInterface $resultAsset)
69+
{
70+
if ($resultAsset->getContentType() !== 'js') {
71+
return $result;
72+
}
73+
$pubStaticDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
74+
$absolutePath = $pubStaticDir->getAbsolutePath() . $resultAsset->getRelativeSourceFilePath();
75+
$integrity = $this->integrityFactory->create(
76+
[
77+
"data" => [
78+
'hash' => $this->hashGenerator->generate(file_get_contents($absolutePath)),
79+
'path' => $resultAsset->getRelativeSourceFilePath()
80+
]
81+
]
82+
);
83+
84+
$this->sourceIntegrityRepository->save($integrity);
85+
86+
return $result;
87+
}
88+
}

app/code/Magento/Csp/etc/di.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@
128128
<type name="Magento\RequireJs\Model\FileManager">
129129
<plugin name="addResourceIntegrityAfterAssetCreate" type="Magento\Csp\Plugin\GenerateAssetIntegrity"/>
130130
</type>
131+
<type name="Magento\Deploy\Service\Bundle">
132+
<plugin name="addResourceIntegrityAfterBundleDeploy" type="Magento\Csp\Plugin\GenerateBundleAssetIntegrity" />
133+
</type>
134+
<type name="Magento\Framework\View\Asset\MergeStrategy\FileExists">
135+
<plugin name="addResourceIntegrityAfterMergeFile" type="Magento\Csp\Plugin\GenerateMergedAssetIntegrity" />
136+
</type>
131137
<preference for="Magento\Deploy\Package\Processor\PostProcessor\Map" type="Magento\Csp\Model\Deploy\Package\Processor\PostProcessor\Map" />
132138
<type name="Magento\Csp\Model\Deploy\Package\Processor\PostProcessor\Map">
133139
<arguments>

0 commit comments

Comments
 (0)