Repository: googlemaps/js-api-loader
Pull request #62 (2020-10-08 23:22:20)

feat: add nonce attribute

codecov[bot]: # [Codecov](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=h1) Report
> Merging [#62](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=desc) into [master](https://codecov.io/gh/googlemaps/js-api-loader/commit/73b202db6a443ae4638280c3e4ad7b92a4a79ca3?el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/googlemaps/js-api-loader/pull/62/graphs/tree.svg?width=650&height=150&src=pr&token=aAmgcWFXMs)](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##            master       #62   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines           81        85    +4     
  Branches        13        14    +1     
=========================================
+ Hits            81        85    +4     
```


| [Impacted Files](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/index.ts](https://codecov.io/gh/googlemaps/js-api-loader/pull/62/diff?src=pr&el=tree#diff-c3JjL2luZGV4LnRz) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=footer). Last update [73b202d...a2261b9](https://codecov.io/gh/googlemaps/js-api-loader/pull/62?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/examples/index.html b/examples/index.html
index ffbf6f2..dfa8abb 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -18,6 +18,11 @@
 <html>
   <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+    <meta
+      http-equiv="Content-Security-Policy"
+      content="script-src 'nonce-caffe67d7b989af3a1c7f4a1a6c79bd9fb2b4eb0'"
+    />
+
     <title>Loader Example</title>
     <style>
       html,
@@ -28,9 +33,16 @@
         padding: 0;
       }
     </style>
-    <script type="text/javascript" src="../dist/index.dev.js"></script>
+    <script
+      nonce="caffe67d7b989af3a1c7f4a1a6c79bd9fb2b4eb0"
+      type="text/javascript"
+      src="../dist/index.dev.js"
+    ></script>
 
-    <script type="text/javascript">
+    <script
+      nonce="caffe67d7b989af3a1c7f4a1a6c79bd9fb2b4eb0"
+      type="text/javascript"
+    >
       const mapOptions = {
         center: {
           lat: 0,
@@ -43,6 +55,7 @@
         apiKey: "",
         version: "weekly",
         libraries: ["places"],
+        nonce: "caffe67d7b989af3a1c7f4a1a6c79bd9fb2b4eb0",
       });
 
       // Promise
@@ -68,6 +81,5 @@
 
   <body>
     <div id="map" class="map"></div>
-    <div id="map2" class="map"></div>
   </body>
 </html>
diff --git a/src/index.ts b/src/index.ts
index 35ed926..02e2076 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -144,6 +144,10 @@ export interface LoaderOptions {
    * Use a custom url and path to load the Google Maps API script.
    */
   url?: string;
+  /**
+   * Use a cryptographic nonce attribute.
+   */
+  nonce?: string;
 }
 
 /**
@@ -197,6 +201,11 @@ export class Loader {
    */
   mapIds: string[];
 
+  /**
+   * See [[LoaderOptions.nonce]]
+   */
+  nonce: string | null;
+
   /**
    * See [[LoaderOptions.url]]
    */
@@ -225,6 +234,7 @@ export class Loader {
     region,
     version,
     mapIds,
+    nonce,
     url = "https://maps.googleapis.com/maps/api/js",
   }: LoaderOptions) {
     this.version = version;
@@ -234,6 +244,7 @@ export class Loader {
     this.language = language;
     this.region = region;
     this.mapIds = mapIds;
+    this.nonce = nonce;
     this.url = url;
   }
   /**
@@ -311,9 +322,9 @@ export class Loader {
   private setScript(): void {
     if (this.id && document.getElementById(this.id)) {
       this.callback();
-      return;      
+      return;
     }
-    
+
     const url = this.createUrl();
     const script = document.createElement("script");
     script.id = this.id;
@@ -322,6 +333,11 @@ export class Loader {
     script.onerror = this.loadErrorCallback.bind(this);
     script.defer = true;
     script.async = true;
+
+    if (this.nonce) {
+      script.nonce = this.nonce;
+    }
+
     document.head.appendChild(script);
   }
 


Test patch:
diff --git a/src/index.test.ts b/src/index.test.ts
index 727cff2..fede38f 100644
--- a/src/index.test.ts
+++ b/src/index.test.ts
@@ -17,7 +17,7 @@
 import { Loader, LoaderOptions } from ".";
 
 afterEach(() => {
-  document.getElementsByTagName('html')[0].innerHTML = ''; 
+  document.getElementsByTagName("html")[0].innerHTML = "";
 });
 
 test.each([
@@ -65,8 +65,8 @@ test("setScript adds a script to head with correct attributes", () => {
 });
 
 test("setScript does not add second script with same id", () => {
-  new Loader({ apiKey: "foo", id: "bar" })['setScript']();
-  new Loader({ apiKey: "foo", id: "bar" })['setScript']();
+  new Loader({ apiKey: "foo", id: "bar" })["setScript"]();
+  new Loader({ apiKey: "foo", id: "bar" })["setScript"]();
 
   expect(document.head.childNodes.length).toBe(1);
 });
@@ -143,3 +143,11 @@ test("loader should wait if already loading", () => {
 
   loader.load();
 });
+
+test("setScript adds a nonce", () => {
+  const nonce = "bar";
+  const loader = new Loader({ apiKey: "foo", nonce });
+  loader["setScript"]();
+  const script = document.head.childNodes[0] as HTMLScriptElement;
+  expect(script.nonce).toBe(nonce);
+});