|
1234 | 1234 |
|
1235 | 1235 | function parseTrustedTypes(cspString) { |
1236 | 1236 | const policies = new Set(); |
| 1237 | + let allowDuplicates = false; |
| 1238 | + let ttDirectiveFound = false; |
1237 | 1239 | const ttRegex = /trusted-types\s+([^;]+)/gi; |
1238 | 1240 | let match; |
| 1241 | + |
1239 | 1242 | while ((match = ttRegex.exec(cspString)) !== null) { |
1240 | | - match[1].trim().split(/\s+/) |
1241 | | - .forEach(name => { |
1242 | | - if (name !== "'allow-duplicates'" && name !== "'none'") { |
| 1243 | + ttDirectiveFound = true; |
| 1244 | + |
| 1245 | + const policyNames = match[1].trim().split(/\s+/); |
| 1246 | + for (const name of policyNames) { |
| 1247 | + if (name === "'allow-duplicates'") { |
| 1248 | + allowDuplicates = true; |
| 1249 | + } else if (name !== "'none'") { |
1243 | 1250 | policies.add(name.replace(/'/g, '')); |
1244 | 1251 | } |
1245 | | - }); |
| 1252 | + } |
1246 | 1253 | } |
1247 | | - return Array.from(policies); |
| 1254 | + return { names: policies, allowDuplicates: allowDuplicates, ttDirectiveFound: ttDirectiveFound }; |
1248 | 1255 | } |
1249 | 1256 |
|
1250 | | - async function getAvailablePolicyNamesOptimized() { |
1251 | | - if (_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.getPolicyNames) { |
1252 | | - const existingNames = _unsafeWindow.trustedTypes.getPolicyNames(); |
1253 | | - if (existingNames.length > 0) { |
1254 | | - return new Set(existingNames); |
1255 | | - } |
1256 | | - } |
| 1257 | + async function getCspTrustedTypesInfo() { |
| 1258 | + const combinedPolicies = new Set(); |
| 1259 | + let combinedAllowDuplicates = false; |
| 1260 | + let combinedTtDirectiveFound = false; |
1257 | 1261 |
|
1258 | 1262 | const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]'); |
1259 | 1263 | if (meta) { |
1260 | | - const metaNames = parseTrustedTypes(meta.content); |
1261 | | - if (metaNames.length > 0) { |
1262 | | - return new Set(metaNames); |
| 1264 | + const metaResult = parseTrustedTypes(meta.content); |
| 1265 | + metaResult.names.forEach(name => combinedPolicies.add(name)); |
| 1266 | + if (metaResult.allowDuplicates) { |
| 1267 | + combinedAllowDuplicates = true; |
| 1268 | + } |
| 1269 | + if (metaResult.ttDirectiveFound) { |
| 1270 | + combinedTtDirectiveFound = true; |
1263 | 1271 | } |
1264 | 1272 | } |
1265 | 1273 |
|
|
1273 | 1281 | .map(h => h.substring(26).trim()) |
1274 | 1282 | .join('; '); |
1275 | 1283 |
|
1276 | | - const headerNames = parseTrustedTypes(cspHeader); |
1277 | | - if (headerNames.length > 0) { |
1278 | | - resolve(new Set(headerNames)); |
1279 | | - } else { |
1280 | | - resolve(new Set()); |
| 1284 | + const headerResult = parseTrustedTypes(cspHeader); |
| 1285 | + headerResult.names.forEach(name => combinedPolicies.add(name)); |
| 1286 | + if (headerResult.allowDuplicates) { |
| 1287 | + combinedAllowDuplicates = true; |
1281 | 1288 | } |
| 1289 | + if (headerResult.ttDirectiveFound) { |
| 1290 | + combinedTtDirectiveFound = true; |
| 1291 | + } |
| 1292 | + |
| 1293 | + resolve({ |
| 1294 | + names: combinedPolicies, |
| 1295 | + allowDuplicates: combinedAllowDuplicates, |
| 1296 | + ttDirectiveFound: combinedTtDirectiveFound |
| 1297 | + }); |
1282 | 1298 | }, |
1283 | 1299 | onerror: function(error) { |
1284 | | - resolve(new Set()); |
| 1300 | + resolve({ |
| 1301 | + names: combinedPolicies, |
| 1302 | + allowDuplicates: combinedAllowDuplicates, |
| 1303 | + ttDirectiveFound: combinedTtDirectiveFound |
| 1304 | + }); |
1285 | 1305 | } |
1286 | 1306 | }); |
1287 | 1307 | }); |
|
1297 | 1317 | } |
1298 | 1318 |
|
1299 | 1319 | async function createPolicy() { |
1300 | | - if (_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.createPolicy && isTrustedTypesEnforced()) { |
1301 | | - const allowedNames = await getAvailablePolicyNamesOptimized(); |
| 1320 | + if (!(_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.createPolicy && isTrustedTypesEnforced())) { |
| 1321 | + return; |
| 1322 | + } |
1302 | 1323 |
|
1303 | | - if (allowedNames.size === 0) { |
1304 | | - escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy('pagetual_default', { |
1305 | | - createHTML: (string, sink) => string |
1306 | | - }); |
1307 | | - return; |
| 1324 | + const { names: allowedNames, allowDuplicates, ttDirectiveFound } = await getCspTrustedTypesInfo(); |
| 1325 | + |
| 1326 | + if (ttDirectiveFound && !allowDuplicates) { |
| 1327 | + debug("CSP Trusted Types is enforced without 'allow-duplicates'. " + |
| 1328 | + "Skipping policy creation to avoid conflicts with the page."); |
| 1329 | + return; |
| 1330 | + } |
| 1331 | + |
| 1332 | + const MY_POLICY_NAME = 'pvcep_default'; |
| 1333 | + |
| 1334 | + try { |
| 1335 | + escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy(MY_POLICY_NAME, { |
| 1336 | + createHTML: (string, sink) => string, |
| 1337 | + createScriptURL: string => string, |
| 1338 | + createScript: string => string |
| 1339 | + }); |
| 1340 | + return; |
| 1341 | + } catch (e) { |
| 1342 | + } |
| 1343 | + |
| 1344 | + const existingPolicies = new Set(_unsafeWindow.trustedTypes.getPolicyNames()); |
| 1345 | + for (const name of allowedNames) { |
| 1346 | + if (name === '*' || existingPolicies.has(name)) { |
| 1347 | + continue; |
1308 | 1348 | } |
1309 | 1349 |
|
1310 | | - for (const name of allowedNames) { |
1311 | | - if (name === '*') continue; |
1312 | | - try { |
1313 | | - escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy(name, { |
1314 | | - createHTML: (string, sink) => string |
1315 | | - }); |
1316 | | - break; |
1317 | | - } catch (e) { |
1318 | | - console.warn(`create '${name}' failed`); |
1319 | | - return; |
1320 | | - } |
| 1350 | + try { |
| 1351 | + escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy(name, { |
| 1352 | + createHTML: (string, sink) => string, |
| 1353 | + createScriptURL: string => string, |
| 1354 | + createScript: string => string |
| 1355 | + }); |
| 1356 | + return; |
| 1357 | + } catch (e) { |
| 1358 | + debug(`create '${name}' failed, trying next...`); |
1321 | 1359 | } |
1322 | 1360 | } |
| 1361 | + debug("Could not create any trusted types policy."); |
1323 | 1362 | } |
1324 | 1363 |
|
1325 | 1364 | var escapeHTMLPolicy; |
|
0 commit comments