Skip to content

Commit

Permalink
Adding changes to COOP audit similar to HSTS audit (recommendations f…
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastian9er committed Nov 21, 2024
1 parent 5abe536 commit b2851bf
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 63 deletions.
24 changes: 12 additions & 12 deletions core/audits/origin-isolation.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as i18n from '../lib/i18n/i18n.js';
import {Audit} from './audit.js';

const UIStrings = {
/** 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". */
/** 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". */
title: 'Ensure the proper usage of the COOP header to isolate the origin.',
/** 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". */
description: 'Deployment of the COOP header allows isolation of the top-level document to not share a browsing context group with cross-origin documents. ' +
Expand Down Expand Up @@ -45,14 +45,14 @@ class OriginIsolation extends Audit {
/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<{coopHeaders: string[]}>}
* @return {Promise<coopHeaders: string[]>}
*/
static async getRawCoop(artifacts, context) {
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
const mainResource =
await MainResource.request({devtoolsLog, URL: artifacts.URL}, context);

var coopHeaders =
let coopHeaders =
mainResource.responseHeaders
.filter(h => {
return h.name.toLowerCase() === 'cross-origin-opener-policy';
Expand All @@ -62,7 +62,7 @@ class OriginIsolation extends Audit {
// Sanitize the header value.
coopHeaders = coopHeaders.map(v => v.toLowerCase().replace(/\s/g, ''));

return {coopHeaders};
return coopHeaders;
}

/**
Expand Down Expand Up @@ -95,7 +95,7 @@ class OriginIsolation extends Audit {
severity: str_(i18n.UIStrings.itemSeverityHigh),
description: str_(UIStrings.noCoop),
directive: undefined,
})
});
}

for (const actualDirective of coopHeaders) {
Expand All @@ -104,8 +104,8 @@ class OriginIsolation extends Audit {
syntax.push({
severity: str_(i18n.UIStrings.itemSeverityLow),
description: str_(UIStrings.invalidSyntax),
directive: actualDirective
})
directive: actualDirective,
});
}
}

Expand All @@ -120,7 +120,7 @@ class OriginIsolation extends Audit {
str_(i18n.UIStrings.itemSeverityLow))),
];

return {score: violations.length ? 0 : 1, results};
return {score: violations.length || syntax.length > 1 ? 0 : 1, results};
}

/**
Expand All @@ -129,15 +129,15 @@ class OriginIsolation extends Audit {
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
const {coopHeaders} = await this.getRawCoop(artifacts, context);
const coopHeaders = await this.getRawCoop(artifacts, context);
const {score, results} = this.constructResults(coopHeaders);

/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
/* eslint-disable max-len */
{ key: 'description', valueType: 'text', subItemsHeading: {key: 'description'}, label: str_(i18n.UIStrings.columnDescription)},
{ key: 'directive', valueType: 'code', subItemsHeading: {key: 'directive'}, label: str_(UIStrings.columnDirective)},
{ key: 'severity', valueType: 'text', subItemsHeading: {key: 'severity'}, label: str_(UIStrings.columnSeverity)},
{key: 'description', valueType: 'text', subItemsHeading: {key: 'description'}, label: str_(i18n.UIStrings.columnDescription)},
{key: 'directive', valueType: 'code', subItemsHeading: {key: 'directive'}, label: str_(UIStrings.columnDirective)},
{key: 'severity', valueType: 'text', subItemsHeading: {key: 'severity'}, label: str_(UIStrings.columnSeverity)},
/* eslint-enable max-len */
];
const details = Audit.makeTableDetails(headings, results);
Expand Down
2 changes: 1 addition & 1 deletion core/config/default-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ const defaultConfig = {
{id: 'notification-on-start', weight: 1, group: 'best-practices-trust-safety'},
{id: 'csp-xss', weight: 0, group: 'best-practices-trust-safety'},
{id: 'has-hsts', weight: 0, group: 'best-practices-trust-safety'},
{id: 'origin-isolation', weight: 0, group: 'best-practices-trust-safety'},
{id: 'origin-isolation', weight: 0},
// User Experience
{id: 'paste-preventing-inputs', weight: 3, group: 'best-practices-ux'},
{id: 'image-aspect-ratio', weight: 1, group: 'best-practices-ux'},
Expand Down
75 changes: 25 additions & 50 deletions core/test/audits/origin-isolation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ it('marked N/A if no violations found', async () => {
]),
},
};
const results = await OriginIsolation.audit(artifacts, {computedCache: new Map()});
const results =
await OriginIsolation.audit(artifacts, {computedCache: new Map()});
expect(results.details.items).toHaveLength(0);
expect(results.notApplicable).toBeTruthy();
});
Expand All @@ -49,20 +50,14 @@ it('No COOP header found', async () => {
},
};

const results = await OriginIsolation.audit(artifacts, {computedCache: new Map()});
const results =
await OriginIsolation.audit(artifacts, {computedCache: new Map()});
expect(results.notApplicable).toBeFalsy();
expect(results.details.items[0].severity).toBeDisplayString('High');
expect(results.details.items[0].description)
.toBeDisplayString('No COOP header found');
expect(results.details.items).toMatchObject([
{
severity: {
i18nId: "core/lib/i18n/i18n.js | itemSeverityHigh",
values: undefined,
formattedDefault: 'High'
},
description: {
i18nId: "core/audits/origin-isolation.js | noCoop",
values: undefined,
formattedDefault: 'No COOP header found'
},
directive: undefined,
},
]);
Expand All @@ -87,21 +82,15 @@ it('Messed up directive.', async () => {
},
};

const results = await OriginIsolation.audit(artifacts, {computedCache: new Map()});
const results =
await OriginIsolation.audit(artifacts, {computedCache: new Map()});
expect(results.notApplicable).toBeFalsy();
expect(results.details.items[0].severity).toBeDisplayString('Low');
expect(results.details.items[0].description)
.toBeDisplayString('Invalid syntax');
expect(results.details.items).toMatchObject([
{
severity: {
i18nId: "core/lib/i18n/i18n.js | itemSeverityLow",
values: undefined,
formattedDefault: 'Low'
},
description: {
i18nId: "core/audits/origin-isolation.js | invalidSyntax",
values: undefined,
formattedDefault: 'Invalid syntax'
},
directive: "foodirective",
directive: 'foodirective',
},
]);
});
Expand All @@ -128,7 +117,7 @@ describe('getRawCoop', () => {
]),
},
};
const {coopHeaders} =
const coopHeaders =
await OriginIsolation.getRawCoop(artifacts, {computedCache: new Map()});
expect(coopHeaders).toEqual([
`same-origin`,
Expand Down Expand Up @@ -156,7 +145,7 @@ describe('getRawCoop', () => {
]),
},
};
const {coopHeaders} =
const coopHeaders =
await OriginIsolation.getRawCoop(artifacts, {computedCache: new Map()});
expect(coopHeaders).toEqual([
``,
Expand Down Expand Up @@ -184,7 +173,7 @@ describe('getRawCoop', () => {
]),
},
};
const {coopHeaders} =
const coopHeaders =
await OriginIsolation.getRawCoop(artifacts, {computedCache: new Map()});
expect(coopHeaders).toEqual([
``,
Expand All @@ -194,48 +183,34 @@ describe('getRawCoop', () => {

describe('constructResults', () => {
it('passes with no findings', () => {
const {score, results} = OriginIsolation.constructResults([ 'same-origin' ]);
const {score, results} = OriginIsolation.constructResults(['same-origin']);
expect(score).toEqual(1);
expect(results).toEqual([]);
});

it('constructs result based on misconfigured COOP header', () => {
const {score, results} = OriginIsolation.constructResults([ 'foo-directive' ]);
const {score, results} =
OriginIsolation.constructResults(['foo-directive']);
expect(score).toEqual(1);
expect(results[0].severity).toBeDisplayString('Low');
expect(results[0].description)
.toBeDisplayString('Invalid syntax');
expect(results).toMatchObject([
{
description: {
formattedDefault: 'Invalid syntax',
i18nId: 'core/audits/origin-isolation.js | invalidSyntax',
values: undefined,
},
directive: 'foo-directive',
severity: {
formattedDefault: 'Low',
i18nId: 'core/lib/i18n/i18n.js | itemSeverityLow',
values: undefined,
},
},
]);
});

it('returns single item for no COOP', () => {
const {score, results} = OriginIsolation.constructResults([]);
expect(score).toEqual(0);
expect(results[0].severity).toBeDisplayString('High');
expect(results[0].description)
.toBeDisplayString('No COOP header found');
expect(results).toMatchObject([
{
description: {
formattedDefault: 'No COOP header found',
i18nId: 'core/audits/origin-isolation.js | noCoop',
values: undefined,
},
directive: undefined,
severity: {
formattedDefault: 'High',
i18nId: 'core/lib/i18n/i18n.js | itemSeverityHigh',
values: undefined,
},

},
]);
});
Expand Down

0 comments on commit b2851bf

Please sign in to comment.