lighthouse 12.2.3-dev.20241211 → 12.2.3
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/cli/test/smokehouse/core-tests.js +0 -8
- package/core/audits/byte-efficiency/render-blocking-resources.js +1 -1
- package/core/computed/metrics/cumulative-layout-shift.js +4 -4
- package/core/computed/metrics/lantern-metric.js +2 -4
- package/core/computed/navigation-insights.d.ts +1 -1
- package/core/computed/network-analysis.js +1 -13
- package/core/computed/trace-engine-result.d.ts +0 -4
- package/core/computed/trace-engine-result.js +4 -30
- package/core/config/default-config.js +0 -4
- package/core/gather/gatherers/seo/font-size.d.ts +0 -1
- package/core/gather/gatherers/seo/font-size.js +11 -20
- package/core/lib/trace-engine.d.ts +1 -1
- package/core/lib/trace-engine.js +1 -1
- package/package.json +2 -2
- package/shared/localization/locales/ar-XB.json +0 -60
- package/shared/localization/locales/ar.json +0 -60
- package/shared/localization/locales/bg.json +0 -60
- package/shared/localization/locales/ca.json +0 -60
- package/shared/localization/locales/cs.json +0 -60
- package/shared/localization/locales/da.json +0 -60
- package/shared/localization/locales/de.json +0 -60
- package/shared/localization/locales/el.json +0 -60
- package/shared/localization/locales/en-GB.json +0 -60
- package/shared/localization/locales/en-US.json +40 -154
- package/shared/localization/locales/en-XL.json +40 -154
- package/shared/localization/locales/es-419.json +0 -60
- package/shared/localization/locales/es.json +0 -60
- package/shared/localization/locales/fi.json +0 -60
- package/shared/localization/locales/fil.json +0 -60
- package/shared/localization/locales/fr.json +0 -60
- package/shared/localization/locales/he.json +0 -60
- package/shared/localization/locales/hi.json +0 -60
- package/shared/localization/locales/hr.json +0 -60
- package/shared/localization/locales/hu.json +0 -60
- package/shared/localization/locales/id.json +0 -60
- package/shared/localization/locales/it.json +0 -60
- package/shared/localization/locales/ja.json +0 -60
- package/shared/localization/locales/ko.json +0 -60
- package/shared/localization/locales/lt.json +0 -60
- package/shared/localization/locales/lv.json +0 -60
- package/shared/localization/locales/nl.json +0 -60
- package/shared/localization/locales/no.json +0 -60
- package/shared/localization/locales/pl.json +0 -60
- package/shared/localization/locales/pt-PT.json +0 -60
- package/shared/localization/locales/pt.json +0 -60
- package/shared/localization/locales/ro.json +0 -60
- package/shared/localization/locales/ru.json +0 -60
- package/shared/localization/locales/sk.json +0 -60
- package/shared/localization/locales/sl.json +0 -60
- package/shared/localization/locales/sr-Latn.json +0 -60
- package/shared/localization/locales/sr.json +0 -60
- package/shared/localization/locales/sv.json +0 -60
- package/shared/localization/locales/ta.json +0 -60
- package/shared/localization/locales/te.json +0 -60
- package/shared/localization/locales/th.json +0 -60
- package/shared/localization/locales/tr.json +0 -60
- package/shared/localization/locales/uk.json +0 -60
- package/shared/localization/locales/vi.json +0 -60
- package/shared/localization/locales/zh-HK.json +0 -60
- package/shared/localization/locales/zh-TW.json +0 -60
- package/shared/localization/locales/zh.json +0 -60
- package/types/artifacts.d.ts +2 -2
- package/core/audits/has-hsts.d.ts +0 -44
- package/core/audits/has-hsts.js +0 -208
- package/core/audits/origin-isolation.d.ts +0 -40
- package/core/audits/origin-isolation.js +0 -155
|
@@ -2621,66 +2621,6 @@
|
|
|
2621
2621
|
"flow-report/src/i18n/ui-strings.js | title": {
|
|
2622
2622
|
"message": "Lighthouse 用户流报告"
|
|
2623
2623
|
},
|
|
2624
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js | description": {
|
|
2625
|
-
"message": "当元素在没有任何用户互动的情况下移动时,就会发生布局偏移。[调查布局偏移的原因](https://web.dev/articles/optimize-cls),例如在网页加载时添加、移除元素或元素字体发生了变化。"
|
|
2626
|
-
},
|
|
2627
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js | title": {
|
|
2628
|
-
"message": "布局偏移原因"
|
|
2629
|
-
},
|
|
2630
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js | description": {
|
|
2631
|
-
"message": "您的第一个网络请求最为重要。您可通过避免重定向、确保服务器快速响应以及启用文本压缩,缩短其延迟时间。"
|
|
2632
|
-
},
|
|
2633
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js | title": {
|
|
2634
|
-
"message": "文档请求延迟"
|
|
2635
|
-
},
|
|
2636
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js | description": {
|
|
2637
|
-
"message": "建议您将 [font-display](https://developer.chrome.com/blog/font-display) 设为 swap 或 optional,确保文本始终可见。通过[替换字体指标](https://developer.chrome.com/blog/font-fallbacks)可进一步优化 swap,缓解布局偏移。"
|
|
2638
|
-
},
|
|
2639
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js | title": {
|
|
2640
|
-
"message": "字体显示"
|
|
2641
|
-
},
|
|
2642
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js | description": {
|
|
2643
|
-
"message": "请从持续时间最长的阶段开始检查。[几处延迟可降低到最小](https://web.dev/articles/optimize-inp#optimize_interactions)。如需缩短处理时长,请[优化主线程(通常是 JS)成本](https://web.dev/articles/optimize-long-tasks)。"
|
|
2644
|
-
},
|
|
2645
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js | title": {
|
|
2646
|
-
"message": "按阶段划分的 INP"
|
|
2647
|
-
},
|
|
2648
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js | description": {
|
|
2649
|
-
"message": "使 LCP 图像能够立即从 HTML 中[被发现](https://web.dev/articles/optimize-lcp#1_eliminate_resource_load_delay),并[避免延迟加载](https://web.dev/articles/lcp-lazy-loading),以此优化 LCP"
|
|
2650
|
-
},
|
|
2651
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js | title": {
|
|
2652
|
-
"message": "发现 LCP 请求"
|
|
2653
|
-
},
|
|
2654
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/LCPPhases.js | description": {
|
|
2655
|
-
"message": "每个[阶段都有特定的改进策略](https://web.dev/articles/optimize-lcp#lcp-breakdown)。理想情况下,大部分 LCP 时间应该花在加载资源上,而不是浪费在延迟上。"
|
|
2656
|
-
},
|
|
2657
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/LCPPhases.js | title": {
|
|
2658
|
-
"message": "按阶段划分的 LCP"
|
|
2659
|
-
},
|
|
2660
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/RenderBlocking.js | description": {
|
|
2661
|
-
"message": "请求正在屏蔽网页的初始渲染,这可能会延迟 LCP。[延迟或内嵌](https://web.dev/learn/performance/understanding-the-critical-path#render-blocking_resources/)可以将这些网络请求移出关键路径。"
|
|
2662
|
-
},
|
|
2663
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/RenderBlocking.js | title": {
|
|
2664
|
-
"message": "渲染屏蔽请求"
|
|
2665
|
-
},
|
|
2666
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/SlowCSSSelector.js | description": {
|
|
2667
|
-
"message": "如果“重新计算样式”的成本仍然很高,优化选择器可以降低此成本。请对用时较长及慢路径所占百分比较高的[选择器进行优化](https://developer.chrome.com/docs/devtools/performance/selector-stats)。选择器越简单、数量越少,DOM 的规模越小、结构越简单,越能降低匹配成本。"
|
|
2668
|
-
},
|
|
2669
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/SlowCSSSelector.js | title": {
|
|
2670
|
-
"message": "CSS 选择器成本"
|
|
2671
|
-
},
|
|
2672
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/ThirdParties.js | description": {
|
|
2673
|
-
"message": "第三方代码可能会显著影响加载性能。[请减少并推迟加载第三方代码](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/),以优先渲染您的网页内容。"
|
|
2674
|
-
},
|
|
2675
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/ThirdParties.js | title": {
|
|
2676
|
-
"message": "第三方"
|
|
2677
|
-
},
|
|
2678
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/Viewport.js | description": {
|
|
2679
|
-
"message": "此网页的视口未针对移动设备进行优化,因此点按互动可能会[延迟最多 300 毫秒](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/)。"
|
|
2680
|
-
},
|
|
2681
|
-
"node_modules/@paulirish/trace_engine/models/trace/insights/Viewport.js | title": {
|
|
2682
|
-
"message": "视口未针对移动设备进行优化"
|
|
2683
|
-
},
|
|
2684
2624
|
"node_modules/lighthouse-stack-packs/packs/amp.js | efficient-animated-content": {
|
|
2685
2625
|
"message": "对于动画内容,请使用 [`amp-anim`](https://amp.dev/documentation/components/amp-anim/) 尽量减少当内容在屏幕外时的 CPU 使用量。"
|
|
2686
2626
|
},
|
package/types/artifacts.d.ts
CHANGED
|
@@ -510,8 +510,8 @@ declare module Artifacts {
|
|
|
510
510
|
}
|
|
511
511
|
|
|
512
512
|
interface TraceEngineResult {
|
|
513
|
-
data: TraceEngine.Handlers.Types.
|
|
514
|
-
insights: TraceEngine.Insights.Types.
|
|
513
|
+
data: TraceEngine.Handlers.Types.TraceParseData;
|
|
514
|
+
insights: TraceEngine.Insights.Types.TraceInsightData;
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
interface TraceEngineRootCauses {
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export default HasHsts;
|
|
2
|
-
declare class HasHsts extends Audit {
|
|
3
|
-
/**
|
|
4
|
-
* @param {LH.Artifacts} artifacts
|
|
5
|
-
* @param {LH.Audit.Context} context
|
|
6
|
-
* @return {Promise<string[]>}
|
|
7
|
-
*/
|
|
8
|
-
static getRawHsts(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<string[]>;
|
|
9
|
-
/**
|
|
10
|
-
* @param {string} hstsDirective
|
|
11
|
-
* @param {LH.IcuMessage | string} findingDescription
|
|
12
|
-
* @param {LH.IcuMessage=} severity
|
|
13
|
-
* @return {LH.Audit.Details.TableItem}
|
|
14
|
-
*/
|
|
15
|
-
static findingToTableItem(hstsDirective: string, findingDescription: LH.IcuMessage | string, severity?: LH.IcuMessage | undefined): LH.Audit.Details.TableItem;
|
|
16
|
-
/**
|
|
17
|
-
* @param {string[]} hstsHeaders
|
|
18
|
-
* @return {{score: number, results: LH.Audit.Details.TableItem[]}}
|
|
19
|
-
*/
|
|
20
|
-
static constructResults(hstsHeaders: string[]): {
|
|
21
|
-
score: number;
|
|
22
|
-
results: LH.Audit.Details.TableItem[];
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* @param {LH.Artifacts} artifacts
|
|
26
|
-
* @param {LH.Audit.Context} context
|
|
27
|
-
* @return {Promise<LH.Audit.Product>}
|
|
28
|
-
*/
|
|
29
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
30
|
-
}
|
|
31
|
-
export namespace UIStrings {
|
|
32
|
-
let title: string;
|
|
33
|
-
let description: string;
|
|
34
|
-
let noHsts: string;
|
|
35
|
-
let noPreload: string;
|
|
36
|
-
let noSubdomain: string;
|
|
37
|
-
let noMaxAge: string;
|
|
38
|
-
let lowMaxAge: string;
|
|
39
|
-
let invalidSyntax: string;
|
|
40
|
-
let columnDirective: string;
|
|
41
|
-
let columnSeverity: string;
|
|
42
|
-
}
|
|
43
|
-
import { Audit } from './audit.js';
|
|
44
|
-
//# sourceMappingURL=has-hsts.d.ts.map
|
package/core/audits/has-hsts.js
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2024 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {Audit} from './audit.js';
|
|
8
|
-
import {MainResource} from '../computed/main-resource.js';
|
|
9
|
-
import * as i18n from '../lib/i18n/i18n.js';
|
|
10
|
-
|
|
11
|
-
const UIStrings = {
|
|
12
|
-
/** Title of a Lighthouse audit that evaluates the security of a page's HSTS header. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
13
|
-
title: 'Use a strong HSTS policy',
|
|
14
|
-
/** Description of a Lighthouse audit that evaluates the security of a page's HSTS header. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
15
|
-
description: 'Deployment of the HSTS header significantly ' +
|
|
16
|
-
'reduces the risk of downgrading HTTP connections and eavesdropping attacks. ' +
|
|
17
|
-
'A rollout in stages, starting with a low max-age is recommended. ' +
|
|
18
|
-
'[Learn more about using a strong HSTS policy.](https://developer.chrome.com/docs/lighthouse/best-practices/has-hsts)',
|
|
19
|
-
/** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if no HSTS header is deployed. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
20
|
-
noHsts: 'No HSTS header found',
|
|
21
|
-
/** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the preload directive is missing. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
22
|
-
noPreload: 'No `preload` directive found',
|
|
23
|
-
/** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the includeSubDomains directive is missing. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
24
|
-
noSubdomain: 'No `includeSubDomains` directive found',
|
|
25
|
-
/** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the max-age directive is missing. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
26
|
-
noMaxAge: 'No `max-age` directive',
|
|
27
|
-
/** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the provided duration for the max-age directive is too low. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
28
|
-
lowMaxAge: '`max-age` is too low',
|
|
29
|
-
/** Table item value calling out the presence of a syntax error. */
|
|
30
|
-
invalidSyntax: 'Invalid syntax',
|
|
31
|
-
/** Label for a column in a data table; entries will be a directive of the HSTS header. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
32
|
-
columnDirective: 'Directive',
|
|
33
|
-
/** Label for a column in a data table; entries will be the severity of an issue with the HSTS header. "HSTS" stands for "HTTP Strict Transport Security". */
|
|
34
|
-
columnSeverity: 'Severity',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
38
|
-
|
|
39
|
-
class HasHsts extends Audit {
|
|
40
|
-
/**
|
|
41
|
-
* @return {LH.Audit.Meta}
|
|
42
|
-
*/
|
|
43
|
-
static get meta() {
|
|
44
|
-
return {
|
|
45
|
-
id: 'has-hsts',
|
|
46
|
-
scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
|
|
47
|
-
title: str_(UIStrings.title),
|
|
48
|
-
description: str_(UIStrings.description),
|
|
49
|
-
requiredArtifacts: ['devtoolsLogs', 'URL'],
|
|
50
|
-
supportedModes: ['navigation'],
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* @param {LH.Artifacts} artifacts
|
|
57
|
-
* @param {LH.Audit.Context} context
|
|
58
|
-
* @return {Promise<string[]>}
|
|
59
|
-
*/
|
|
60
|
-
static async getRawHsts(artifacts, context) {
|
|
61
|
-
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
62
|
-
const mainResource =
|
|
63
|
-
await MainResource.request({devtoolsLog, URL: artifacts.URL}, context);
|
|
64
|
-
|
|
65
|
-
let hstsHeaders =
|
|
66
|
-
mainResource.responseHeaders
|
|
67
|
-
.filter(h => {
|
|
68
|
-
return h.name.toLowerCase() === 'strict-transport-security';
|
|
69
|
-
})
|
|
70
|
-
.flatMap(h => h.value.split(';'));
|
|
71
|
-
|
|
72
|
-
// Sanitize the header value / directives.
|
|
73
|
-
hstsHeaders = hstsHeaders.map(v => v.toLowerCase().replace(/\s/g, ''));
|
|
74
|
-
|
|
75
|
-
return hstsHeaders;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @param {string} hstsDirective
|
|
80
|
-
* @param {LH.IcuMessage | string} findingDescription
|
|
81
|
-
* @param {LH.IcuMessage=} severity
|
|
82
|
-
* @return {LH.Audit.Details.TableItem}
|
|
83
|
-
*/
|
|
84
|
-
static findingToTableItem(hstsDirective, findingDescription, severity) {
|
|
85
|
-
return {
|
|
86
|
-
directive: hstsDirective,
|
|
87
|
-
description: findingDescription,
|
|
88
|
-
severity,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* @param {string[]} hstsHeaders
|
|
94
|
-
* @return {{score: number, results: LH.Audit.Details.TableItem[]}}
|
|
95
|
-
*/
|
|
96
|
-
static constructResults(hstsHeaders) {
|
|
97
|
-
const rawHsts = [...hstsHeaders];
|
|
98
|
-
const allowedDirectives = ['max-age', 'includesubdomains', 'preload'];
|
|
99
|
-
const violations = [];
|
|
100
|
-
const warnings = [];
|
|
101
|
-
const syntax = [];
|
|
102
|
-
|
|
103
|
-
if (!rawHsts.length) {
|
|
104
|
-
return {
|
|
105
|
-
score: 0,
|
|
106
|
-
results: [{
|
|
107
|
-
severity: str_(i18n.UIStrings.itemSeverityHigh),
|
|
108
|
-
description: str_(UIStrings.noHsts),
|
|
109
|
-
directive: undefined,
|
|
110
|
-
}],
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// No max-age is a violation and renders the HSTS header useless.
|
|
115
|
-
if (!hstsHeaders.toString().includes('max-age')) {
|
|
116
|
-
violations.push({
|
|
117
|
-
severity: str_(i18n.UIStrings.itemSeverityHigh),
|
|
118
|
-
description: str_(UIStrings.noMaxAge),
|
|
119
|
-
directive: 'max-age',
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!hstsHeaders.toString().includes('includesubdomains')) {
|
|
124
|
-
// No includeSubdomains might be even wanted. But would be preferred.
|
|
125
|
-
warnings.push({
|
|
126
|
-
severity: str_(i18n.UIStrings.itemSeverityMedium),
|
|
127
|
-
description: str_(UIStrings.noSubdomain),
|
|
128
|
-
directive: 'includeSubDomains',
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (!hstsHeaders.toString().includes('preload')) {
|
|
133
|
-
// No preload might be even wanted. But would be preferred.
|
|
134
|
-
warnings.push({
|
|
135
|
-
severity: str_(i18n.UIStrings.itemSeverityMedium),
|
|
136
|
-
description: str_(UIStrings.noPreload),
|
|
137
|
-
directive: 'preload',
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
for (const actualDirective of hstsHeaders) {
|
|
142
|
-
// We recommend 2y max-age. But if it's lower than 1y, it's a violation.
|
|
143
|
-
if (actualDirective.includes('max-age') &&
|
|
144
|
-
parseInt(actualDirective.split('=')[1], 10) < 31536000) {
|
|
145
|
-
violations.push({
|
|
146
|
-
severity: str_(i18n.UIStrings.itemSeverityHigh),
|
|
147
|
-
description: str_(UIStrings.lowMaxAge),
|
|
148
|
-
directive: 'max-age',
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// If there is a directive that's not an official HSTS directive.
|
|
153
|
-
if (!allowedDirectives.includes(actualDirective) &&
|
|
154
|
-
!actualDirective.includes('max-age')) {
|
|
155
|
-
syntax.push({
|
|
156
|
-
severity: str_(i18n.UIStrings.itemSeverityLow),
|
|
157
|
-
description: str_(UIStrings.invalidSyntax),
|
|
158
|
-
directive: actualDirective,
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const results = [
|
|
164
|
-
...violations.map(
|
|
165
|
-
f => this.findingToTableItem(
|
|
166
|
-
f.directive, f.description,
|
|
167
|
-
str_(i18n.UIStrings.itemSeverityHigh))),
|
|
168
|
-
...warnings.map(
|
|
169
|
-
f => this.findingToTableItem(
|
|
170
|
-
f.directive, f.description,
|
|
171
|
-
str_(i18n.UIStrings.itemSeverityMedium))),
|
|
172
|
-
...syntax.map(
|
|
173
|
-
f => this.findingToTableItem(
|
|
174
|
-
f.directive, f.description,
|
|
175
|
-
str_(i18n.UIStrings.itemSeverityLow))),
|
|
176
|
-
];
|
|
177
|
-
return {score: violations.length || syntax.length ? 0 : 1, results};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* @param {LH.Artifacts} artifacts
|
|
182
|
-
* @param {LH.Audit.Context} context
|
|
183
|
-
* @return {Promise<LH.Audit.Product>}
|
|
184
|
-
*/
|
|
185
|
-
static async audit(artifacts, context) {
|
|
186
|
-
const hstsHeaders = await this.getRawHsts(artifacts, context);
|
|
187
|
-
const {score, results} = this.constructResults(hstsHeaders);
|
|
188
|
-
|
|
189
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
190
|
-
const headings = [
|
|
191
|
-
/* eslint-disable max-len */
|
|
192
|
-
{key: 'description', valueType: 'text', subItemsHeading: {key: 'description'}, label: str_(i18n.UIStrings.columnDescription)},
|
|
193
|
-
{key: 'directive', valueType: 'code', subItemsHeading: {key: 'directive'}, label: str_(UIStrings.columnDirective)},
|
|
194
|
-
{key: 'severity', valueType: 'text', subItemsHeading: {key: 'severity'}, label: str_(UIStrings.columnSeverity)},
|
|
195
|
-
/* eslint-enable max-len */
|
|
196
|
-
];
|
|
197
|
-
const details = Audit.makeTableDetails(headings, results);
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
score,
|
|
201
|
-
notApplicable: !results.length,
|
|
202
|
-
details,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export default HasHsts;
|
|
208
|
-
export {UIStrings};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export default OriginIsolation;
|
|
2
|
-
declare class OriginIsolation extends Audit {
|
|
3
|
-
/**
|
|
4
|
-
* @param {LH.Artifacts} artifacts
|
|
5
|
-
* @param {LH.Audit.Context} context
|
|
6
|
-
* @return {Promise<string[]>}
|
|
7
|
-
*/
|
|
8
|
-
static getRawCoop(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<string[]>;
|
|
9
|
-
/**
|
|
10
|
-
* @param {string | undefined} coopDirective
|
|
11
|
-
* @param {LH.IcuMessage | string} findingDescription
|
|
12
|
-
* @param {LH.IcuMessage=} severity
|
|
13
|
-
* @return {LH.Audit.Details.TableItem}
|
|
14
|
-
*/
|
|
15
|
-
static findingToTableItem(coopDirective: string | undefined, findingDescription: LH.IcuMessage | string, severity?: LH.IcuMessage | undefined): LH.Audit.Details.TableItem;
|
|
16
|
-
/**
|
|
17
|
-
* @param {string[]} coopHeaders
|
|
18
|
-
* @return {{score: number, results: LH.Audit.Details.TableItem[]}}
|
|
19
|
-
*/
|
|
20
|
-
static constructResults(coopHeaders: string[]): {
|
|
21
|
-
score: number;
|
|
22
|
-
results: LH.Audit.Details.TableItem[];
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* @param {LH.Artifacts} artifacts
|
|
26
|
-
* @param {LH.Audit.Context} context
|
|
27
|
-
* @return {Promise<LH.Audit.Product>}
|
|
28
|
-
*/
|
|
29
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
30
|
-
}
|
|
31
|
-
export namespace UIStrings {
|
|
32
|
-
let title: string;
|
|
33
|
-
let description: string;
|
|
34
|
-
let noCoop: string;
|
|
35
|
-
let invalidSyntax: string;
|
|
36
|
-
let columnDirective: string;
|
|
37
|
-
let columnSeverity: string;
|
|
38
|
-
}
|
|
39
|
-
import { Audit } from './audit.js';
|
|
40
|
-
//# sourceMappingURL=origin-isolation.d.ts.map
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2024 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {Audit} from './audit.js';
|
|
8
|
-
import {MainResource} from '../computed/main-resource.js';
|
|
9
|
-
import * as i18n from '../lib/i18n/i18n.js';
|
|
10
|
-
|
|
11
|
-
const UIStrings = {
|
|
12
|
-
/** Title of a Lighthouse audit that evaluates the security of a page's COOP header for origin isolation. "COOP" stands for "Cross-Origin-Opener-Policy" and should not be translated. */
|
|
13
|
-
title: 'Ensure proper origin isolation with COOP',
|
|
14
|
-
/** Description of a Lighthouse audit that evaluates the security of a page's COOP header for origin isolation. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. "COOP" stands for "Cross-Origin-Opener-Policy", neither should be translated. */
|
|
15
|
-
description: 'The Cross-Origin-Opener-Policy (COOP) can be used to isolate the top-level window from other documents such as pop-ups. [Learn more about deploying the COOP header.](https://web.dev/articles/why-coop-coep#coop)',
|
|
16
|
-
/** Summary text for the results of a Lighthouse audit that evaluates the COOP header for origin isolation. This is displayed if no COOP header is deployed. "COOP" stands for "Cross-Origin-Opener-Policy" and should not be translated. */
|
|
17
|
-
noCoop: 'No COOP header found',
|
|
18
|
-
/** Table item value calling out the presence of a syntax error. */
|
|
19
|
-
invalidSyntax: 'Invalid syntax',
|
|
20
|
-
/** Label for a column in a data table; entries will be a directive of the COOP header. "COOP" stands for "Cross-Origin-Opener-Policy". */
|
|
21
|
-
columnDirective: 'Directive',
|
|
22
|
-
/** Label for a column in a data table; entries will be the severity of an issue with the COOP header. "COOP" stands for "Cross-Origin-Opener-Policy". */
|
|
23
|
-
columnSeverity: 'Severity',
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
27
|
-
|
|
28
|
-
class OriginIsolation extends Audit {
|
|
29
|
-
/**
|
|
30
|
-
* @return {LH.Audit.Meta}
|
|
31
|
-
*/
|
|
32
|
-
static get meta() {
|
|
33
|
-
return {
|
|
34
|
-
id: 'origin-isolation',
|
|
35
|
-
scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
|
|
36
|
-
title: str_(UIStrings.title),
|
|
37
|
-
description: str_(UIStrings.description),
|
|
38
|
-
requiredArtifacts: ['devtoolsLogs', 'URL'],
|
|
39
|
-
supportedModes: ['navigation'],
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @param {LH.Artifacts} artifacts
|
|
46
|
-
* @param {LH.Audit.Context} context
|
|
47
|
-
* @return {Promise<string[]>}
|
|
48
|
-
*/
|
|
49
|
-
static async getRawCoop(artifacts, context) {
|
|
50
|
-
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
51
|
-
const mainResource =
|
|
52
|
-
await MainResource.request({devtoolsLog, URL: artifacts.URL}, context);
|
|
53
|
-
|
|
54
|
-
let coopHeaders =
|
|
55
|
-
mainResource.responseHeaders
|
|
56
|
-
.filter(h => {
|
|
57
|
-
return h.name.toLowerCase() === 'cross-origin-opener-policy';
|
|
58
|
-
})
|
|
59
|
-
.flatMap(h => h.value);
|
|
60
|
-
|
|
61
|
-
// Sanitize the header value.
|
|
62
|
-
coopHeaders = coopHeaders.map(v => v.toLowerCase().replace(/\s/g, ''));
|
|
63
|
-
|
|
64
|
-
return coopHeaders;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @param {string | undefined} coopDirective
|
|
69
|
-
* @param {LH.IcuMessage | string} findingDescription
|
|
70
|
-
* @param {LH.IcuMessage=} severity
|
|
71
|
-
* @return {LH.Audit.Details.TableItem}
|
|
72
|
-
*/
|
|
73
|
-
static findingToTableItem(coopDirective, findingDescription, severity) {
|
|
74
|
-
return {
|
|
75
|
-
directive: coopDirective,
|
|
76
|
-
description: findingDescription,
|
|
77
|
-
severity,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* @param {string[]} coopHeaders
|
|
83
|
-
* @return {{score: number, results: LH.Audit.Details.TableItem[]}}
|
|
84
|
-
*/
|
|
85
|
-
static constructResults(coopHeaders) {
|
|
86
|
-
const rawCoop = [...coopHeaders];
|
|
87
|
-
const allowedDirectives = [
|
|
88
|
-
'unsafe-none', 'same-origin-allow-popups', 'same-origin',
|
|
89
|
-
'noopener-allow-popups',
|
|
90
|
-
];
|
|
91
|
-
const violations = [];
|
|
92
|
-
const syntax = [];
|
|
93
|
-
|
|
94
|
-
if (!rawCoop.length) {
|
|
95
|
-
violations.push({
|
|
96
|
-
severity: str_(i18n.UIStrings.itemSeverityHigh),
|
|
97
|
-
description: str_(UIStrings.noCoop),
|
|
98
|
-
directive: undefined,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for (const actualDirective of coopHeaders) {
|
|
103
|
-
// If there is a directive that's not an official COOP directive.
|
|
104
|
-
if (!allowedDirectives.includes(actualDirective)) {
|
|
105
|
-
syntax.push({
|
|
106
|
-
severity: str_(i18n.UIStrings.itemSeverityLow),
|
|
107
|
-
description: str_(UIStrings.invalidSyntax),
|
|
108
|
-
directive: actualDirective,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const results = [
|
|
114
|
-
...violations.map(
|
|
115
|
-
f => this.findingToTableItem(
|
|
116
|
-
f.directive, f.description,
|
|
117
|
-
str_(i18n.UIStrings.itemSeverityHigh))),
|
|
118
|
-
...syntax.map(
|
|
119
|
-
f => this.findingToTableItem(
|
|
120
|
-
f.directive, f.description,
|
|
121
|
-
str_(i18n.UIStrings.itemSeverityLow))),
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
return {score: violations.length || syntax.length ? 0 : 1, results};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* @param {LH.Artifacts} artifacts
|
|
129
|
-
* @param {LH.Audit.Context} context
|
|
130
|
-
* @return {Promise<LH.Audit.Product>}
|
|
131
|
-
*/
|
|
132
|
-
static async audit(artifacts, context) {
|
|
133
|
-
const coopHeaders = await this.getRawCoop(artifacts, context);
|
|
134
|
-
const {score, results} = this.constructResults(coopHeaders);
|
|
135
|
-
|
|
136
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
137
|
-
const headings = [
|
|
138
|
-
/* eslint-disable max-len */
|
|
139
|
-
{key: 'description', valueType: 'text', subItemsHeading: {key: 'description'}, label: str_(i18n.UIStrings.columnDescription)},
|
|
140
|
-
{key: 'directive', valueType: 'code', subItemsHeading: {key: 'directive'}, label: str_(UIStrings.columnDirective)},
|
|
141
|
-
{key: 'severity', valueType: 'text', subItemsHeading: {key: 'severity'}, label: str_(UIStrings.columnSeverity)},
|
|
142
|
-
/* eslint-enable max-len */
|
|
143
|
-
];
|
|
144
|
-
const details = Audit.makeTableDetails(headings, results);
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
score,
|
|
148
|
-
notApplicable: !results.length,
|
|
149
|
-
details,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export default OriginIsolation;
|
|
155
|
-
export {UIStrings};
|