vite-plugin-sri4 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/dist/index.cjs +196 -0
- package/dist/index.js +194 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# vite-plugin-sri4
|
|
2
|
+
|
|
3
|
+
A Vite plugin to generate Subresource Integrity (SRI) hashes for your assets during the build process. This plugin computes SRI hashes for JavaScript and CSS files and injects them as `integrity` and `crossorigin="anonymous"` attributes into your HTML, ensuring your resources have not been tampered with when loaded by browsers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic SRI Generation:** Computes SRI hashes for assets (chunks and files) using a configurable algorithm (default is `sha384`).
|
|
8
|
+
- **HTML Injection:** Automatically injects `integrity` and `crossorigin` attributes into `<script>` and `<link>` tags in your HTML.
|
|
9
|
+
- **CORS Support Check:** For external resources, a CORS check is performed to verify access via `Access-Control-Allow-Origin`.
|
|
10
|
+
- **Bypass Domains:** Option to specify domains to bypass SRI injection.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
If the plugin has been published to npm:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install vite-plugin-sri4 --save-dev
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Alternatively, if you're developing locally, you can use npm link or install via a relative path.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
Add the plugin to your Vite configuration by updating your vite.config.js or vite.config.ts file:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
// vite.config.js
|
|
27
|
+
import { defineConfig } from 'vite';
|
|
28
|
+
import sri from 'vite-plugin-sri4';
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
plugins: [
|
|
32
|
+
sri({
|
|
33
|
+
// Optional. The security hash algorithm. Defaults to "sha384".
|
|
34
|
+
algorithm: 'sha384',
|
|
35
|
+
// Optional. Domains to bypass SRI injection.
|
|
36
|
+
bypassDomains: ['example.com']
|
|
37
|
+
})
|
|
38
|
+
]
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Now, when you run the build command:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm run build
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The plugin will process the generated bundles, compute SRI hashes, and inject the attributes into the HTML.
|
|
49
|
+
|
|
50
|
+
## Plugin Options
|
|
51
|
+
|
|
52
|
+
* algorithm (string):
|
|
53
|
+
The hash algorithm used for computing SRI. Default is sha384. You may change it to other supported algorithms like sha256.
|
|
54
|
+
* bypassDomains (Array<string>):
|
|
55
|
+
Array of domain names where SRI injection should be skipped. This allows external resources from specified domains to be excluded from SRI checks (for example, when they may not support CORS).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
var fetch = require('node-fetch');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Compute the SRI (Subresource Integrity) hash for the given content.
|
|
8
|
+
* @param {string | Buffer} content - The content to hash.
|
|
9
|
+
* @param {string} algorithm - The SHA algorithm to use (default is 'sha384').
|
|
10
|
+
* @returns {string} - The SRI string in the format "algorithm-base64hash".
|
|
11
|
+
*/
|
|
12
|
+
function computeSri(content, algorithm = 'sha384') {
|
|
13
|
+
const hash = crypto.createHash(algorithm)
|
|
14
|
+
.update(content)
|
|
15
|
+
.digest('base64');
|
|
16
|
+
return `${algorithm}-${hash}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Check if an external resource supports CORS.
|
|
21
|
+
* It sends a HEAD request to the given URL and examines the "Access-Control-Allow-Origin" header.
|
|
22
|
+
* Adjust the logic to match your security policy.
|
|
23
|
+
* @param {string} url - The URL to check.
|
|
24
|
+
* @returns {Promise<boolean>} - A promise that resolves to true if CORS is enabled.
|
|
25
|
+
*/
|
|
26
|
+
async function externalResourceIsCorsEnabled(url) {
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
29
|
+
const acao = response.headers.get('access-control-allow-origin');
|
|
30
|
+
// Adjust the check as needed. This example allows "*" or domains including 'your-domain.com'.
|
|
31
|
+
if (acao && (acao === '*' || acao.includes('your-domain.com'))) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.warn(`Failed to fetch CORS headers from ${url}:`, error);
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Helper function to perform an asynchronous replacement in a string.
|
|
43
|
+
* @param {string} str - The input string.
|
|
44
|
+
* @param {RegExp} regex - The regular expression to match parts of the string.
|
|
45
|
+
* @param {Function} asyncFn - An async function to compute the replacement.
|
|
46
|
+
* @returns {Promise<string>} - The string with replaced values.
|
|
47
|
+
*/
|
|
48
|
+
async function replaceAsync(str, regex, asyncFn) {
|
|
49
|
+
const matches = [];
|
|
50
|
+
str.replace(regex, (...args) => {
|
|
51
|
+
matches.push(args);
|
|
52
|
+
return '';
|
|
53
|
+
});
|
|
54
|
+
for (const args of matches) {
|
|
55
|
+
const match = args[0];
|
|
56
|
+
const replacement = await asyncFn(...args);
|
|
57
|
+
str = str.replace(match, replacement);
|
|
58
|
+
}
|
|
59
|
+
return str;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Determines if the URL belongs to a domain specified in the bypassDomains array.
|
|
64
|
+
* If so, the SRI injection will be skipped for that resource.
|
|
65
|
+
* @param {string} url - The URL to check.
|
|
66
|
+
* @param {Array<string>} bypassDomains - Array of domains to bypass SRI injection.
|
|
67
|
+
* @returns {boolean} - True if the URL should bypass SRI injection.
|
|
68
|
+
*/
|
|
69
|
+
function isBypassDomain(url, bypassDomains = []) {
|
|
70
|
+
if (!bypassDomains.length) return false;
|
|
71
|
+
try {
|
|
72
|
+
// If url starts with '//' assume default protocol 'http:'
|
|
73
|
+
const parsedUrl = url.startsWith('//') ? new URL(url, 'http://dummy') : new URL(url);
|
|
74
|
+
// Checks if the hostname ends with any of the bypass domains.
|
|
75
|
+
return bypassDomains.some((domain) => parsedUrl.hostname === domain || parsedUrl.hostname.endsWith(`.${domain}`));
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* vite-plugin-sri4
|
|
83
|
+
*
|
|
84
|
+
* Plugin options:
|
|
85
|
+
* - algorithm: The algorithm used to compute SRI hash (default: 'sha384').
|
|
86
|
+
* - bypassDomains: Array of domains for which to skip injecting the integrity attribute.
|
|
87
|
+
*
|
|
88
|
+
* This plugin works during the build process:
|
|
89
|
+
* 1. In the generateBundle hook, it calculates the SRI hash for all assets/chunks and stores them in sriMap.
|
|
90
|
+
* 2. In the transformIndexHtml hook, it injects the integrity and crossorigin attributes into the HTML.
|
|
91
|
+
* For external links, it verifies via a CORS check if the resource supports cross-origin access.
|
|
92
|
+
*
|
|
93
|
+
* @param {Object} options - Plugin configuration options.
|
|
94
|
+
* @returns {Object} - The Vite plugin.
|
|
95
|
+
*/
|
|
96
|
+
function sri(options = {}) {
|
|
97
|
+
// Use the provided algorithm from options, defaulting to 'sha384' if not specified.
|
|
98
|
+
const algorithm = options.algorithm || 'sha384';
|
|
99
|
+
// Array for domains to bypass SRI injection.
|
|
100
|
+
const bypassDomains = options.bypassDomains || [];
|
|
101
|
+
// Map to store SRI hashes for assets; key is the file name.
|
|
102
|
+
const sriMap = {};
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
name: 'vite-plugin-sri4',
|
|
106
|
+
apply: 'build',
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The generateBundle hook iterates through each asset or chunk in the bundle,
|
|
110
|
+
* computes its SRI hash, and stores it in the sriMap.
|
|
111
|
+
*/
|
|
112
|
+
async generateBundle(_, bundle) {
|
|
113
|
+
for (const fileName in bundle) {
|
|
114
|
+
const chunk = bundle[fileName];
|
|
115
|
+
if (chunk.type === 'chunk' || chunk.type === 'asset') {
|
|
116
|
+
const content = chunk.code || chunk.source;
|
|
117
|
+
if (content) {
|
|
118
|
+
sriMap[fileName] = computeSri(content, algorithm);
|
|
119
|
+
console.log(`Computed SRI for ${fileName}: ${sriMap[fileName]}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The transformIndexHtml hook processes the generated HTML and injects the integrity and crossorigin attributes.
|
|
127
|
+
* For external resources, a CORS check is performed first.
|
|
128
|
+
* If the URL belongs to a bypass domain, the injection is skipped.
|
|
129
|
+
* @param {string} html - The HTML content to transform.
|
|
130
|
+
* @returns {Promise<string>} - The transformed HTML.
|
|
131
|
+
*/
|
|
132
|
+
async transformIndexHtml(html) {
|
|
133
|
+
// Determines if a URL is external by checking if it starts with http://, https://, or //
|
|
134
|
+
const isExternalUrl = (url) => /^(https?:)?\/\//i.test(url);
|
|
135
|
+
|
|
136
|
+
// Process <script> tags.
|
|
137
|
+
html = await replaceAsync(
|
|
138
|
+
html,
|
|
139
|
+
/(<script[^>]+src="([^"]+)"[^>]*>)/g,
|
|
140
|
+
async (match, tag, src) => {
|
|
141
|
+
// Skip SRI injection for external URLs that are in the bypass list.
|
|
142
|
+
if (isExternalUrl(src) && isBypassDomain(src, bypassDomains)) {
|
|
143
|
+
console.log(`Skipping SRI injection for bypass domain: ${src}`);
|
|
144
|
+
return tag;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (isExternalUrl(src)) {
|
|
148
|
+
// For external links not bypassed, perform a CORS check.
|
|
149
|
+
const corsOk = await externalResourceIsCorsEnabled(src);
|
|
150
|
+
if (!corsOk) {
|
|
151
|
+
console.warn(`External resource ${src} does not support CORS. Skipping SRI injection.`);
|
|
152
|
+
return tag;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// For relative URLs or valid external URLs, use the file name as the key.
|
|
156
|
+
const fileName = src.startsWith('/') ? src.slice(1) : src;
|
|
157
|
+
if (sriMap[fileName]) {
|
|
158
|
+
return tag.replace(/>$/, ` integrity="${sriMap[fileName]}" crossorigin="anonymous">`);
|
|
159
|
+
}
|
|
160
|
+
return tag;
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Process <link> tags.
|
|
165
|
+
html = await replaceAsync(
|
|
166
|
+
html,
|
|
167
|
+
/(<link[^>]+href="([^"]+)"[^>]*>)/g,
|
|
168
|
+
async (match, tag, href) => {
|
|
169
|
+
// Skip SRI injection for external URLs that are in the bypass list.
|
|
170
|
+
if (isExternalUrl(href) && isBypassDomain(href, bypassDomains)) {
|
|
171
|
+
console.log(`Skipping SRI injection for bypass domain: ${href}`);
|
|
172
|
+
return tag;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (isExternalUrl(href)) {
|
|
176
|
+
// For external links not in the bypass list, perform a CORS check.
|
|
177
|
+
const corsOk = await externalResourceIsCorsEnabled(href);
|
|
178
|
+
if (!corsOk) {
|
|
179
|
+
console.warn(`External resource ${href} does not support CORS. Skipping SRI injection.`);
|
|
180
|
+
return tag;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const fileName = href.startsWith('/') ? href.slice(1) : href;
|
|
184
|
+
if (sriMap[fileName]) {
|
|
185
|
+
return tag.replace(/>$/, ` integrity="${sriMap[fileName]}" crossorigin="anonymous">`);
|
|
186
|
+
}
|
|
187
|
+
return tag;
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
return html;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
module.exports = sri;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compute the SRI (Subresource Integrity) hash for the given content.
|
|
6
|
+
* @param {string | Buffer} content - The content to hash.
|
|
7
|
+
* @param {string} algorithm - The SHA algorithm to use (default is 'sha384').
|
|
8
|
+
* @returns {string} - The SRI string in the format "algorithm-base64hash".
|
|
9
|
+
*/
|
|
10
|
+
function computeSri(content, algorithm = 'sha384') {
|
|
11
|
+
const hash = createHash(algorithm)
|
|
12
|
+
.update(content)
|
|
13
|
+
.digest('base64');
|
|
14
|
+
return `${algorithm}-${hash}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if an external resource supports CORS.
|
|
19
|
+
* It sends a HEAD request to the given URL and examines the "Access-Control-Allow-Origin" header.
|
|
20
|
+
* Adjust the logic to match your security policy.
|
|
21
|
+
* @param {string} url - The URL to check.
|
|
22
|
+
* @returns {Promise<boolean>} - A promise that resolves to true if CORS is enabled.
|
|
23
|
+
*/
|
|
24
|
+
async function externalResourceIsCorsEnabled(url) {
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
27
|
+
const acao = response.headers.get('access-control-allow-origin');
|
|
28
|
+
// Adjust the check as needed. This example allows "*" or domains including 'your-domain.com'.
|
|
29
|
+
if (acao && (acao === '*' || acao.includes('your-domain.com'))) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.warn(`Failed to fetch CORS headers from ${url}:`, error);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Helper function to perform an asynchronous replacement in a string.
|
|
41
|
+
* @param {string} str - The input string.
|
|
42
|
+
* @param {RegExp} regex - The regular expression to match parts of the string.
|
|
43
|
+
* @param {Function} asyncFn - An async function to compute the replacement.
|
|
44
|
+
* @returns {Promise<string>} - The string with replaced values.
|
|
45
|
+
*/
|
|
46
|
+
async function replaceAsync(str, regex, asyncFn) {
|
|
47
|
+
const matches = [];
|
|
48
|
+
str.replace(regex, (...args) => {
|
|
49
|
+
matches.push(args);
|
|
50
|
+
return '';
|
|
51
|
+
});
|
|
52
|
+
for (const args of matches) {
|
|
53
|
+
const match = args[0];
|
|
54
|
+
const replacement = await asyncFn(...args);
|
|
55
|
+
str = str.replace(match, replacement);
|
|
56
|
+
}
|
|
57
|
+
return str;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Determines if the URL belongs to a domain specified in the bypassDomains array.
|
|
62
|
+
* If so, the SRI injection will be skipped for that resource.
|
|
63
|
+
* @param {string} url - The URL to check.
|
|
64
|
+
* @param {Array<string>} bypassDomains - Array of domains to bypass SRI injection.
|
|
65
|
+
* @returns {boolean} - True if the URL should bypass SRI injection.
|
|
66
|
+
*/
|
|
67
|
+
function isBypassDomain(url, bypassDomains = []) {
|
|
68
|
+
if (!bypassDomains.length) return false;
|
|
69
|
+
try {
|
|
70
|
+
// If url starts with '//' assume default protocol 'http:'
|
|
71
|
+
const parsedUrl = url.startsWith('//') ? new URL(url, 'http://dummy') : new URL(url);
|
|
72
|
+
// Checks if the hostname ends with any of the bypass domains.
|
|
73
|
+
return bypassDomains.some((domain) => parsedUrl.hostname === domain || parsedUrl.hostname.endsWith(`.${domain}`));
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* vite-plugin-sri4
|
|
81
|
+
*
|
|
82
|
+
* Plugin options:
|
|
83
|
+
* - algorithm: The algorithm used to compute SRI hash (default: 'sha384').
|
|
84
|
+
* - bypassDomains: Array of domains for which to skip injecting the integrity attribute.
|
|
85
|
+
*
|
|
86
|
+
* This plugin works during the build process:
|
|
87
|
+
* 1. In the generateBundle hook, it calculates the SRI hash for all assets/chunks and stores them in sriMap.
|
|
88
|
+
* 2. In the transformIndexHtml hook, it injects the integrity and crossorigin attributes into the HTML.
|
|
89
|
+
* For external links, it verifies via a CORS check if the resource supports cross-origin access.
|
|
90
|
+
*
|
|
91
|
+
* @param {Object} options - Plugin configuration options.
|
|
92
|
+
* @returns {Object} - The Vite plugin.
|
|
93
|
+
*/
|
|
94
|
+
function sri(options = {}) {
|
|
95
|
+
// Use the provided algorithm from options, defaulting to 'sha384' if not specified.
|
|
96
|
+
const algorithm = options.algorithm || 'sha384';
|
|
97
|
+
// Array for domains to bypass SRI injection.
|
|
98
|
+
const bypassDomains = options.bypassDomains || [];
|
|
99
|
+
// Map to store SRI hashes for assets; key is the file name.
|
|
100
|
+
const sriMap = {};
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
name: 'vite-plugin-sri4',
|
|
104
|
+
apply: 'build',
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The generateBundle hook iterates through each asset or chunk in the bundle,
|
|
108
|
+
* computes its SRI hash, and stores it in the sriMap.
|
|
109
|
+
*/
|
|
110
|
+
async generateBundle(_, bundle) {
|
|
111
|
+
for (const fileName in bundle) {
|
|
112
|
+
const chunk = bundle[fileName];
|
|
113
|
+
if (chunk.type === 'chunk' || chunk.type === 'asset') {
|
|
114
|
+
const content = chunk.code || chunk.source;
|
|
115
|
+
if (content) {
|
|
116
|
+
sriMap[fileName] = computeSri(content, algorithm);
|
|
117
|
+
console.log(`Computed SRI for ${fileName}: ${sriMap[fileName]}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The transformIndexHtml hook processes the generated HTML and injects the integrity and crossorigin attributes.
|
|
125
|
+
* For external resources, a CORS check is performed first.
|
|
126
|
+
* If the URL belongs to a bypass domain, the injection is skipped.
|
|
127
|
+
* @param {string} html - The HTML content to transform.
|
|
128
|
+
* @returns {Promise<string>} - The transformed HTML.
|
|
129
|
+
*/
|
|
130
|
+
async transformIndexHtml(html) {
|
|
131
|
+
// Determines if a URL is external by checking if it starts with http://, https://, or //
|
|
132
|
+
const isExternalUrl = (url) => /^(https?:)?\/\//i.test(url);
|
|
133
|
+
|
|
134
|
+
// Process <script> tags.
|
|
135
|
+
html = await replaceAsync(
|
|
136
|
+
html,
|
|
137
|
+
/(<script[^>]+src="([^"]+)"[^>]*>)/g,
|
|
138
|
+
async (match, tag, src) => {
|
|
139
|
+
// Skip SRI injection for external URLs that are in the bypass list.
|
|
140
|
+
if (isExternalUrl(src) && isBypassDomain(src, bypassDomains)) {
|
|
141
|
+
console.log(`Skipping SRI injection for bypass domain: ${src}`);
|
|
142
|
+
return tag;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (isExternalUrl(src)) {
|
|
146
|
+
// For external links not bypassed, perform a CORS check.
|
|
147
|
+
const corsOk = await externalResourceIsCorsEnabled(src);
|
|
148
|
+
if (!corsOk) {
|
|
149
|
+
console.warn(`External resource ${src} does not support CORS. Skipping SRI injection.`);
|
|
150
|
+
return tag;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// For relative URLs or valid external URLs, use the file name as the key.
|
|
154
|
+
const fileName = src.startsWith('/') ? src.slice(1) : src;
|
|
155
|
+
if (sriMap[fileName]) {
|
|
156
|
+
return tag.replace(/>$/, ` integrity="${sriMap[fileName]}" crossorigin="anonymous">`);
|
|
157
|
+
}
|
|
158
|
+
return tag;
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Process <link> tags.
|
|
163
|
+
html = await replaceAsync(
|
|
164
|
+
html,
|
|
165
|
+
/(<link[^>]+href="([^"]+)"[^>]*>)/g,
|
|
166
|
+
async (match, tag, href) => {
|
|
167
|
+
// Skip SRI injection for external URLs that are in the bypass list.
|
|
168
|
+
if (isExternalUrl(href) && isBypassDomain(href, bypassDomains)) {
|
|
169
|
+
console.log(`Skipping SRI injection for bypass domain: ${href}`);
|
|
170
|
+
return tag;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (isExternalUrl(href)) {
|
|
174
|
+
// For external links not in the bypass list, perform a CORS check.
|
|
175
|
+
const corsOk = await externalResourceIsCorsEnabled(href);
|
|
176
|
+
if (!corsOk) {
|
|
177
|
+
console.warn(`External resource ${href} does not support CORS. Skipping SRI injection.`);
|
|
178
|
+
return tag;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const fileName = href.startsWith('/') ? href.slice(1) : href;
|
|
182
|
+
if (sriMap[fileName]) {
|
|
183
|
+
return tag.replace(/>$/, ` integrity="${sriMap[fileName]}" crossorigin="anonymous">`);
|
|
184
|
+
}
|
|
185
|
+
return tag;
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return html;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { sri as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-plugin-sri4",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Vite plugin to generate Subresource Integrity (SRI) hashes for output files.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "rollup -c",
|
|
19
|
+
"dev": "rollup -c -w",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"test:coverage": "vitest run --coverage"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"node-fetch": "^3.3.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"vite": "^4.0.0 || ^5.0.0 || ^6.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@rollup/plugin-commonjs": "^25.0.8",
|
|
32
|
+
"@rollup/plugin-node-resolve": "^15.3.1",
|
|
33
|
+
"@vitest/coverage-v8": "^3.0.5",
|
|
34
|
+
"rollup": "^4.0.0",
|
|
35
|
+
"vite": "^6.1.0",
|
|
36
|
+
"vitest": "^3.0.5"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"vite",
|
|
40
|
+
"plugin",
|
|
41
|
+
"sri",
|
|
42
|
+
"subresource integrity"
|
|
43
|
+
],
|
|
44
|
+
"author": "Zac",
|
|
45
|
+
"license": "ISC",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/7a6163/vite-plugin-sri4.git"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/7a6163/vite-plugin-sri4/issues"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/7a6163/vite-plugin-sri4#readme"
|
|
57
|
+
}
|