Skip to content

Commit 8efc280

Browse files
authored
Merge pull request #1911 from ShyamGadde/fix/od-on-non-https-site
Handle missing Web Crypto API in non-HTTPS contexts
2 parents ad15727 + 2e48f6f commit 8efc280

File tree

1 file changed

+54
-30
lines changed

1 file changed

+54
-30
lines changed

plugins/optimization-detective/detect.js

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -154,35 +154,52 @@ function getGroupForViewportWidth( viewportWidth, urlMetricGroupStatuses ) {
154154
* @param {string} currentETag - Current ETag.
155155
* @param {string} currentUrl - Current URL.
156156
* @param {URLMetricGroupStatus} urlMetricGroupStatus - URL Metric group status.
157-
* @return {Promise<string>} Session storage key.
157+
* @param {Logger} logger - Logger.
158+
* @return {Promise<string|null>} Session storage key for the current URL or null if crypto is not available or caused an error.
158159
*/
159160
async function getAlreadySubmittedSessionStorageKey(
160161
currentETag,
161162
currentUrl,
162-
urlMetricGroupStatus
163+
urlMetricGroupStatus,
164+
{ warn, error }
163165
) {
164-
const message = [
165-
currentETag,
166-
currentUrl,
167-
urlMetricGroupStatus.minimumViewportWidth,
168-
urlMetricGroupStatus.maximumViewportWidth || '',
169-
].join( '-' );
166+
if ( ! window.crypto || ! window.crypto.subtle ) {
167+
warn(
168+
'Unable to generate sessionStorage key for already-submitted URL since crypto is not available, likely due to to the page not being served via HTTPS.'
169+
);
170+
return null;
171+
}
170172

171-
/*
172-
* Note that the components are hashed for a couple of reasons:
173-
*
174-
* 1. It results in a consistent length string devoid of any special characters that could cause problems.
175-
* 2. Since the key includes the URL, hashing it avoids potential privacy concerns where the sessionStorage is
176-
* examined to see which URLs the client went to.
177-
*
178-
* The SHA-1 algorithm is chosen since it is the fastest and there is no need for cryptographic security.
179-
*/
180-
const msgBuffer = new TextEncoder().encode( message );
181-
const hashBuffer = await crypto.subtle.digest( 'SHA-1', msgBuffer );
182-
const hashHex = Array.from( new Uint8Array( hashBuffer ) )
183-
.map( ( b ) => b.toString( 16 ).padStart( 2, '0' ) )
184-
.join( '' );
185-
return `odSubmitted-${ hashHex }`;
173+
try {
174+
const message = [
175+
currentETag,
176+
currentUrl,
177+
urlMetricGroupStatus.minimumViewportWidth,
178+
urlMetricGroupStatus.maximumViewportWidth || '',
179+
].join( '-' );
180+
181+
/*
182+
* Note that the components are hashed for a couple of reasons:
183+
*
184+
* 1. It results in a consistent length string devoid of any special characters that could cause problems.
185+
* 2. Since the key includes the URL, hashing it avoids potential privacy concerns where the sessionStorage is
186+
* examined to see which URLs the client went to.
187+
*
188+
* The SHA-1 algorithm is chosen since it is the fastest and there is no need for cryptographic security.
189+
*/
190+
const msgBuffer = new TextEncoder().encode( message );
191+
const hashBuffer = await crypto.subtle.digest( 'SHA-1', msgBuffer );
192+
const hashHex = Array.from( new Uint8Array( hashBuffer ) )
193+
.map( ( b ) => b.toString( 16 ).padStart( 2, '0' ) )
194+
.join( '' );
195+
return `odSubmitted-${ hashHex }`;
196+
} catch ( err ) {
197+
error(
198+
'Unable to generate sessionStorage key for already-submitted URL due to error:',
199+
err
200+
);
201+
return null;
202+
}
186203
}
187204

188205
/**
@@ -354,7 +371,8 @@ export default async function detect( {
354371
webVitalsLibrarySrc,
355372
urlMetricGroupCollection,
356373
} ) {
357-
const { log, warn, error } = createLogger( isDebug, consoleLogPrefix );
374+
const logger = createLogger( isDebug, consoleLogPrefix );
375+
const { log, warn, error } = logger;
358376

359377
if ( isDebug ) {
360378
const allUrlMetrics = /** @type Array<UrlMetricDebugData> */ [];
@@ -396,9 +414,13 @@ export default async function detect( {
396414
await getAlreadySubmittedSessionStorageKey(
397415
currentETag,
398416
currentUrl,
399-
urlMetricGroupStatus
417+
urlMetricGroupStatus,
418+
logger
400419
);
401-
if ( alreadySubmittedSessionStorageKey in sessionStorage ) {
420+
if (
421+
null !== alreadySubmittedSessionStorageKey &&
422+
alreadySubmittedSessionStorageKey in sessionStorage
423+
) {
402424
const previousVisitTime = parseInt(
403425
sessionStorage.getItem( alreadySubmittedSessionStorageKey ),
404426
10
@@ -801,10 +823,12 @@ export default async function detect( {
801823
setStorageLock( getCurrentTime() );
802824

803825
// Remember that the URL Metric was submitted for this URL to avoid having multiple entries submitted by the same client.
804-
sessionStorage.setItem(
805-
alreadySubmittedSessionStorageKey,
806-
String( getCurrentTime() )
807-
);
826+
if ( null !== alreadySubmittedSessionStorageKey ) {
827+
sessionStorage.setItem(
828+
alreadySubmittedSessionStorageKey,
829+
String( getCurrentTime() )
830+
);
831+
}
808832

809833
const message = `Sending URL Metric (${ jsonBody.length.toLocaleString() } bytes, ${ Math.round(
810834
percentOfBudget

0 commit comments

Comments
 (0)