wage icon indicating copy to clipboard operation
wage copied to clipboard

webapp: Encryption fails in Chrome

Open str4d opened this issue 4 years ago • 5 comments
trafficstars

Environment

  • OS: Windows 10
  • Browser version: Chrome 89.0.4389.90
  • wage version: fce4b8b5ccf7854b301af60875af56574560d887

What were you trying to do

I generated a new identity, and then tried to encrypt a file to it.

What happened

App.vue:250 Uncaught (in promise) TypeError: Failed to execute 'pipeTo' on 'ReadableStream': parameter 1 is not of type 'WritableStream'.
    at o.encryptSingleFile (App.vue:250)
    at App.vue:231
  encryptSingleFile @ App.vue:250
  (anonymous) @ App.vue:231
  Promise.then (async)    
  encryptSingleFile @ App.vue:250
  (anonymous) @ App.vue:231
  Promise.then (async)    
  (anonymous) @ App.vue:229
  prepareEncryptStream @ App.vue:221
  encryptToRecipients @ App.vue:225

str4d avatar Mar 21 '21 00:03 str4d

Hi. Same issue here in passphrase mode in Chrome. But (strangely) the page works in Firefox...

fyears avatar Nov 11 '21 17:11 fyears

I am now seeing the same exception in Firefox 107 on macOS 13.0.1 with 5de7b79330a142a4fffa42b8631f96e34a984946:

Uncaught (in promise) TypeError: ReadableStream.pipeTo: Argument 1 does not implement interface WritableStream.
    encryptSingleFile App.vue:250
    encryptWithPassphrase App.vue:241
    promise callback*encryptWithPassphrase/< App.vue:239
    prepareEncryptStream App.vue:221
    encryptWithPassphrase App.vue:236
    VueJS 4
    encryptFile EncryptPane.vue:232
    VueJS 33

str4d avatar Nov 21 '22 09:11 str4d

I think the problem is that you're using native streams and polyfilled streams interchangeably. And unfortunately, web-streams-polyfill doesn't support this... 😞

Consider the following snippet: https://github.com/str4d/wage/blob/1a647173026fece59d2985f2547befc93f3e5ffc/www/src/App.vue#L245-L251

this.dropFiles[0] is a native File, so this.dropFiles[0].stream() is a native ReadableStream. However, by loading the polyfill, window.WritableStream is replaced by the polyfill's version, so the constructed this.downloadStream is a polyfilled WritableStream. The native ReadableStream.pipeTo() only works with native WritableStream destinations, so that's why that call throws.

One solution would be to manually convert all your native streams to polyfilled ones before usage. I made a small library to help with that. You add a bit of initialization code:

import { createReadableStreamWrapper, createWritableStreamWrapper } from '@mattiasbuelens/web-streams-adapter';
const toPolyfillReadable = createReadableStreamWrapper(window.ReadableStream);
const toPolyfillWritable = createWritableStreamWrapper(window.WritableStream);

and then you convert where necessary:

encryptSingleFile() {
  let fileStream = toPolyfillReadable(this.dropFiles[0].stream());
  let downloadStream = toPolyfillWritable(this.downloadStream);
  return fileStream.pipeTo(downloadStream).then(this.reset);
},

MattiasBuelens avatar Nov 22 '22 22:11 MattiasBuelens

Aha, that makes a lot of sense in hindsight! I was definitely assuming that the polyfill was handling this for me (or that the interface was being duck-typed). It might be useful to mention the wrapper library in the polyfill library documentation (if it's not already there; I don't recall seeing it when I implemented this). I'll try this and see if it resolves the issue.

str4d avatar Nov 23 '22 01:11 str4d

Aha, that makes a lot of sense in hindsight! I was definitely assuming that the polyfill was handling this for me (or that the interface was being duck-typed).

I was trying to make that work for version 4.0 of the polyfill, but unfortunately I had to throw in the towel (see https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issue-1442802866). 😞

It might be useful to mention the wrapper library in the polyfill library documentation (if it's not already there; I don't recall seeing it when I implemented this).

Yes, the documentation needs improvement. 😅 I'm also considering adding these conversion methods to web-streams-polyfill itself, because they're so commonly needed.

MattiasBuelens avatar Nov 23 '22 08:11 MattiasBuelens