[COEP] Improve error messages for COEP

This refactors the implementation and increases color contrast
for the messages.

Bug: chromium:1051473
Change-Id: I21ce4b306d84c6a74fc4182738ab56e6ca952bca
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2089900
Reviewed-by: Peter Marshall <[email protected]>
Commit-Queue: Sigurd Schneider <[email protected]>
diff --git a/front_end/network/RequestHeadersView.js b/front_end/network/RequestHeadersView.js
index 4ad2503..2016dc4 100644
--- a/front_end/network/RequestHeadersView.js
+++ b/front_end/network/RequestHeadersView.js
@@ -124,7 +124,7 @@
   }
 
   /**
-   * @param {!{name:string,value:(string|undefined),headerNotSet:(boolean|undefined),headerValueIncorrect:(boolean|undefined),details:(string|undefined)}} header
+   * @param {!{name:string,value:(string|undefined),headerNotSet:(boolean|undefined),headerValueIncorrect:(boolean|undefined),details:(!{explanation:string,examples:!Array<!{codeSnippet:string,comment:(string|undefined)}>}|undefined)}} header
    * @return {!DocumentFragment}
    */
   _formatHeaderObject(header) {
@@ -143,7 +143,17 @@
       }
     }
     if (header.details) {
-      fragment.createChild('div', 'header-details').innerHTML = header.details;
+      const detailsNode = fragment.createChild('div', 'header-details');
+      const callToAction = detailsNode.createChild('div', 'call-to-action');
+      const callToActionBody = callToAction.createChild('div', 'call-to-action-body');
+      callToActionBody.createChild('div', 'explanation').textContent = header.details.explanation;
+      for (const example of header.details.examples) {
+        const exampleNode = callToActionBody.createChild('div', 'example');
+        exampleNode.createChild('code').textContent = example.codeSnippet;
+        if (example.comment) {
+          exampleNode.createChild('span', 'comment').textContent = example.comment;
+        }
+      }
     }
     return fragment;
   }
@@ -892,27 +902,27 @@
     Protocol.Network.BlockedReason.CoepFrameResourceNeedsCoepHeader, {
       name: 'cross-origin-embedder-policy',
       value: null,
-      details: `<div class='call-to-action'><div class='call-to-action-body'>
-                <div class='explanation'>To embedd this frame in your document,
-                the response needs to enable the Cross Origin Embedder Policy by specifying the following response header:
-                <div class='source-code'>Cross-Origin-Embedder-Policy: require-corp</div>
-                </div>
-            </div>`
+      details: {
+          explanation:
+              ls
+          `To embed this frame in your document, the response needs to enable the cross-origin embedder policy by specifying the following response header:`,
+          examples: [{codeSnippet:'Cross-Origin-Embedder-Policy: require-corp'}]
+      }
     }
   ],
   [
     Protocol.Network.BlockedReason.CorpNotSameOriginAfterDefaultedToSameOriginByCoep, {
       name: 'cross-origin-resource-policy',
       value: null,
-      details: `<div class='call-to-action'><div class='call-to-action-body'>
-                <div class='explanation'>To use this resource from a different origin,
-                  the server needs to specify a <code>Cross-Origin-Resource-Policy<code> response header, e.g.:</div>
-                  <div><code>Cross-Origin-Resource-Policy: same-site</code> &mdash;
-                  Choose this option if the resource and the document are served from the same site.</div>
-              <div><code>Cross-Origin-Resource-Policy: cross-origin</code> &mdash;
-                  <span class='explanation warning'>Only do this if an arbitrary website including this resource does not impose a security risk.</span></div>
-                </div>
-            </div>`
+      details: {
+        explanation:
+            ls
+            `To use this resource from a different origin, the server needs to specify a cross-origin resource policy in the response headers:`,
+        examples: [
+          {codeSnippet:'Cross-Origin-Resource-Policy: same-site', comment: ls`Choose this option if the resource and the document are served from the same site.` },
+          {codeSnippet:'Cross-Origin-Resource-Policy: cross-origin', comment: ls`Only choose this option if an arbitrary website including this resource does not impose a security risk.` },
+        ]
+      }
     }
   ],
   [
@@ -920,10 +930,12 @@
       name: 'cross-origin-opener-policy',
       value: null,
       headerValueIncorrect: false,
-      details: `<div class='call-to-action'><div class='call-to-action-body'>
-             <div class='explanation'>This document was blocked from loading in an <code>iframe</code> with a <code>sandbox</code> attribute because it specified a <code>Cross-Origin-Opener-Policy</code>.</div>
-           </div>
-         </div>`
+      details: {
+        explanation:
+        ls
+        `This document was blocked from loading in an iframe with a sandbox attribute because this document specified a cross-origin opener policy.`,
+        examples: []
+      }
     }
   ],
   [
@@ -931,13 +943,14 @@
       name: 'cross-origin-resource-policy',
       value: null,
       headerValueIncorrect: true,
-      details: `<div class='call-to-action'><div class='call-to-action-body'>
-             <div class='explanation'>To use this resource from a different site,
-               the server may relax the <code>Cross-Origin-Resource-Policy</code> response header:</div>
-               <div><code>Cross-Origin-Resource-Policy: cross-origin</code> &mdash;
-                 <span class='explanation warning'>Only do this if an arbitrary website including this resource does not impose a security risk.</span></div>
-             </div>
-          </div>`
+      details: {
+        explanation:
+            ls
+            `To use this resource from a different site, the server may relax the cross-origin resource policy response header:`,
+        examples: [
+          {codeSnippet:'Cross-Origin-Resource-Policy: cross-origin', comment: ls`Only choose this option if an arbitrary website including this resource does not impose a security risk.` },
+        ]
+      }
     }
   ],
   [
@@ -945,15 +958,15 @@
       name: 'cross-origin-resource-policy',
       value: null,
       headerValueIncorrect: true,
-      details: `<div class='call-to-action'><div class='call-to-action-body'>
-             <div class='explanation'>To use this resource from a different origin,
-             the server may relax the <code>Cross-Origin-Resource-Policy</code> response header:</div>
-             <div><code>Cross-Origin-Resource-Policy: same-site</code> &mdash;
-                 Choose this option if the resource and the document are served from the same site.</div>
-             <div><code>Cross-Origin-Resource-Policy: cross-origin</code> &mdash;
-                 <span class='explanation warning'>Only do this if an arbitrary website including this resource does not impose a security risk.</span></div>
-           </div>
-         </div>`
+      details: {
+        explanation:
+            ls
+            `To use this resource from a different origin, the server may relax the cross-origin resource policy response header:`,
+            examples: [
+              {codeSnippet:'Cross-Origin-Resource-Policy: same-site', comment: ls`Choose this option if the resource and the document are served from the same site.` },
+              {codeSnippet:'Cross-Origin-Resource-Policy: cross-origin', comment: ls`Only choose this option if an arbitrary website including this resource does not impose a security risk.` },
+            ]
+      }
     }
   ],
 ]);