Răsfoiți Sursa

refactor(examples): improve security when rendering HTML strings [TRI-003] (#14)

Lucas Nogueira 3 ani în urmă
părinte
comite
2a7bf6d912

+ 20 - 13
examples/api/src/App.svelte

@@ -90,25 +90,28 @@
   let selected = views[0];
 
   let responses = writable([]);
-  let response = ''
 
   function select(view) {
     selected = view;
   }
 
   function onMessage(value) {
-    responses.update(r => [`[${new Date().toLocaleTimeString()}]` + ': ' + (typeof value === "string" ? value : JSON.stringify(value)), ...r])
+    responses.update(r => [{ text: `[${new Date().toLocaleTimeString()}]` + ': ' + (typeof value === "string" ? value : JSON.stringify(value)) }, ...r])
+  }
+
+  // this function is renders HTML without sanitizing it so it's insecure
+  // we only use it with our own input data
+  function insecureRenderHtml(html) {
+    responses.update(r => [{ html }, ...r])
+  }
+
+  function clear() {
+    responses.update(() => []);
   }
 
   function onLogoClick() {
     open("https://tauri.studio/");
   }
-
-  onMount(() => {
-    responses.subscribe(r => {
-      response = r.join('\n')
-    })
-  })
 </script>
 
 <main>
@@ -136,16 +139,20 @@
       {/each}
     </div>
     <div class="content">
-      <svelte:component this={selected.component} {onMessage} />
+      <svelte:component this={selected.component} {onMessage} {insecureRenderHtml} />
     </div>
   </div>
   <div id="response" style="white-space: pre-line">
     <p class="flex row just-around">
       <strong>Tauri Console</strong>
-      <span class="nv" on:click={()=> {
-        responses.update(() => []);
-        }}>clear</span>
+      <span class="nv" on:click={clear}>clear</span>
     </p>
-    {@html response}
+    {#each $responses as r}
+      {#if r.text}
+      <p>{r.text}</p>
+      {:else}
+      {@html r.html}
+      {/if}
+    {/each}
   </div>
 </main>

+ 2 - 1
examples/api/src/components/Dialog.svelte

@@ -3,6 +3,7 @@
   import { readBinaryFile } from "@tauri-apps/api/fs";
 
   export let onMessage;
+  export let insecureRenderHtml;
   let defaultPath = null;
   let filter = null;
   let multiple = false;
@@ -51,7 +52,7 @@
                     new Uint8Array(response),
                     function (base64) {
                       var src = "data:image/png;base64," + base64;
-                      onMessage('<img src="' + src + '"></img>');
+                      insecureRenderHtml('<img src="' + src + '"></img>');
                     }
                   );
                 } else {

+ 3 - 2
examples/api/src/components/FileSystem.svelte

@@ -3,6 +3,7 @@
   import { convertFileSrc } from "@tauri-apps/api/tauri";
 
   export let onMessage;
+  export let insecureRenderHtml;
 
   let pathToRead = "";
   let img;
@@ -42,11 +43,11 @@
           if (pathToRead.includes(".png") || pathToRead.includes(".jpg")) {
             arrayBufferToBase64(new Uint8Array(response), function (base64) {
               const src = "data:image/png;base64," + base64;
-              onMessage('<img src="' + src + '"></img>');
+              insecureRenderHtml('<img src="' + src + '"></img>');
             });
           } else {
             const value = String.fromCharCode.apply(null, response);
-            onMessage(
+            insecureRenderHtml(
               '<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>'
             );
             setTimeout(() => {

+ 71 - 61
examples/multiwindow/index.html

@@ -1,74 +1,84 @@
 <!DOCTYPE html>
 <html>
-  <body>
-    <div id="window-label"></div>
-    <div id="container"></div>
-    <div id="response"></div>
 
-    <script>
-      var WebviewWindow = window.__TAURI__.window.WebviewWindow
-      var thisTauriWindow = window.__TAURI__.window.getCurrent()
-      var windowLabel = thisTauriWindow.label
-      var windowLabelContainer = document.getElementById('window-label')
-      windowLabelContainer.innerHTML = 'This is the ' + windowLabel + ' window.'
+<head>
+  <style>
+    #response {
+      white-space: pre-wrap;
+    }
+  </style>
+</head>
 
-      var container = document.getElementById('container')
+<body>
+  <div id="window-label"></div>
+  <div id="container"></div>
+  <div id="response"></div>
 
-      function createWindowMessageBtn(label) {
-        var tauriWindow = WebviewWindow.getByLabel(label)
-        var button = document.createElement('button')
-        button.innerHTML = 'Send message to ' + label
-        button.addEventListener('click', function () {
-          tauriWindow.emit('clicked', 'message from ' + windowLabel)
-        })
-        container.appendChild(button)
-      }
+  <script>
+    var WebviewWindow = window.__TAURI__.window.WebviewWindow
+    var thisTauriWindow = window.__TAURI__.window.getCurrent()
+    var windowLabel = thisTauriWindow.label
+    var windowLabelContainer = document.getElementById('window-label')
+    windowLabelContainer.innerText = 'This is the ' + windowLabel + ' window.'
 
-      // global listener
-      window.__TAURI__.event.listen('clicked', function (event) {
-        responseContainer.innerHTML +=
-          'Got ' + JSON.stringify(event) + ' on global listener<br><br>'
-      })
-      window.__TAURI__.event.listen('tauri://window-created', function (event) {
-        createWindowMessageBtn(event.payload.label)
-      })
+    var container = document.getElementById('container')
 
-      var responseContainer = document.getElementById('response')
-      // listener tied to this window
-      thisTauriWindow.listen('clicked', function (event) {
-        responseContainer.innerHTML +=
-          'Got ' + JSON.stringify(event) + ' on window listener<br><br>'
+    function createWindowMessageBtn(label) {
+      var tauriWindow = WebviewWindow.getByLabel(label)
+      var button = document.createElement('button')
+      button.innerText = 'Send message to ' + label
+      button.addEventListener('click', function () {
+        tauriWindow.emit('clicked', 'message from ' + windowLabel)
       })
+      container.appendChild(button)
+    }
 
-      var createWindowButton = document.createElement('button')
-      createWindowButton.innerHTML = 'Create window'
-      createWindowButton.addEventListener('click', function () {
-        var webviewWindow = new WebviewWindow(Math.random().toString())
-        webviewWindow.once('tauri://created', function () {
-          responseContainer.innerHTML += 'Created new webview'
-        })
-        webviewWindow.once('tauri://error', function () {
-          responseContainer.innerHTML += 'Error creating new webview'
-        })
-      })
-      container.appendChild(createWindowButton)
+    // global listener
+    window.__TAURI__.event.listen('clicked', function (event) {
+      responseContainer.innerHTML +=
+        'Got ' + JSON.stringify(event) + ' on global listener\n\n'
+    })
+    window.__TAURI__.event.listen('tauri://window-created', function (event) {
+      createWindowMessageBtn(event.payload.label)
+    })
 
-      var globalMessageButton = document.createElement('button')
-      globalMessageButton.innerHTML = 'Send global message'
-      globalMessageButton.addEventListener('click', function () {
-        // emit to all windows
-        window.__TAURI__.event.emit('clicked', 'message from ' + windowLabel)
+    var responseContainer = document.getElementById('response')
+    // listener tied to this window
+    thisTauriWindow.listen('clicked', function (event) {
+      responseContainer.innerText +=
+        'Got ' + JSON.stringify(event) + ' on window listener\n\n'
+    })
+
+    var createWindowButton = document.createElement('button')
+    createWindowButton.innerHTML = 'Create window'
+    createWindowButton.addEventListener('click', function () {
+      var webviewWindow = new WebviewWindow(Math.random().toString())
+      webviewWindow.once('tauri://created', function () {
+        responseContainer.innerHTML += 'Created new webview'
+      })
+      webviewWindow.once('tauri://error', function () {
+        responseContainer.innerHTML += 'Error creating new webview'
       })
-      container.appendChild(globalMessageButton)
+    })
+    container.appendChild(createWindowButton)
 
-      var allWindows = window.__TAURI__.window.getAll()
-      for (var index in allWindows) {
-        var label = allWindows[index].label
-        if (label === windowLabel) {
-          continue
-        }
-        createWindowMessageBtn(label)
+    var globalMessageButton = document.createElement('button')
+    globalMessageButton.innerHTML = 'Send global message'
+    globalMessageButton.addEventListener('click', function () {
+      // emit to all windows
+      window.__TAURI__.event.emit('clicked', 'message from ' + windowLabel)
+    })
+    container.appendChild(globalMessageButton)
+
+    var allWindows = window.__TAURI__.window.getAll()
+    for (var index in allWindows) {
+      var label = allWindows[index].label
+      if (label === windowLabel) {
+        continue
       }
-    </script>
-  </body>
-</html>
+      createWindowMessageBtn(label)
+    }
+  </script>
+</body>
+
+</html>

+ 1 - 1
examples/resources/index.html

@@ -13,7 +13,7 @@
       const div = document.querySelector('div')
       window.__TAURI__.event.listen('message', (event) => {
         const p = document.createElement('p')
-        p.innerHTML = event.payload
+        p.innerText = event.payload
         div.appendChild(p)
       })
     </script>

+ 1 - 1
examples/sidecar/index.html

@@ -13,7 +13,7 @@
       const div = document.querySelector('div')
       window.__TAURI__.event.listen('message', (event) => {
         const p = document.createElement('p')
-        p.innerHTML = event.payload
+        p.innerText = event.payload
         div.appendChild(p)
       })
     </script>

+ 1 - 1
examples/state/index.html

@@ -31,7 +31,7 @@
       const responseContainer = document.querySelector('#response')
 
       function updateResponse(response) {
-        responseContainer.innerHTML =
+        responseContainer.innerText =
           typeof response === 'string' ? response : JSON.stringify(response)
       }