FIX: Do not explode in IE11

FIX: Do not explode in IE11

diff --git a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
index a95fc0b..edb084b 100644
--- a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
+++ b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
@@ -1,7 +1,15 @@
 {{#if canEnableEncrypt}}
   <div class="control-group pref-title">
     <label class="control-label">{{i18n 'encrypt.title'}}</label>
-    {{#if isSecureContext}}
+    {{#if isIE11}}
+      <div class="alert alert-error">
+        <p>{{i18n 'encrypt.preferences.ie11'}}</p>
+      </div>
+    {{else if isInsecureContext}}
+      <div class="alert alert-error">
+        <p>{{i18n 'encrypt.preferences.insecure_context'}}</p>
+      </div>
+    {{else}}
       <div class="controls">
         {{#if isCurrentUser}}
           {{#if isEncryptEnabled}}
@@ -48,10 +56,6 @@
           {{/if}}
         {{/if}}
       </div>
-    {{else}}
-      <div class="alert alert-error">
-        <p>{{i18n 'encrypt.preferences.insecure_context'}}</p>
-      </div>
     {{/if}}
   </div>
 {{/if}}
diff --git a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6 b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
index 7da9f03..0ca0fc6 100644
--- a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
+++ b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
@@ -27,7 +27,9 @@ export default {
 
     component.setProperties({
       /** crypto.subtle is only available in secure contexts. */
-      isSecureContext: window.isSecureContext,
+      isInsecureContext: !window.isSecureContext,
+      /** Not all algorithms are available in IE11. */
+      isIE11: this.capabilities.isIE11,
       /** Whether current user is the same as model user. */
       isCurrentUser,
       /** Whether plugin is enabled for current user. */
diff --git a/assets/javascripts/lib/protocol_v1.js.es6 b/assets/javascripts/lib/protocol_v1.js.es6
index 503ba38..20ef1d6 100644
--- a/assets/javascripts/lib/protocol_v1.js.es6
+++ b/assets/javascripts/lib/protocol_v1.js.es6
@@ -3,16 +3,6 @@ import {
   bufferToBase64
 } from "discourse/plugins/discourse-encrypt/lib/base64";
 
-/**
- * @var {TextEncoder} textEncoder
- */
-const textEncoder = new TextEncoder();
-
-/**
- * @var {TextDecoder} textDecoder
- */
-const textDecoder = new TextDecoder();
-
 /*
  * Key generation
  */
@@ -22,7 +12,7 @@ function getPassphraseKey(passphrase, salt) {
     window.crypto.subtle
       .importKey(
         "raw",
-        textEncoder.encode(passphrase),
+        new TextEncoder().encode(passphrase),
         { name: "PBKDF2" },
         false,
         ["deriveBits", "deriveKey"]
@@ -46,7 +36,7 @@ function getPassphraseKey(passphrase, salt) {
 }
 
 function plaintextToBuffer(plaintext) {
-  return textEncoder.encode(
+  return new TextEncoder().encode(
     typeof plaintext === "object"
       ? JSON.stringify(plaintext, Object.keys(plaintext).sort())
       : JSON.stringify(plaintext)
@@ -101,7 +91,7 @@ export function exportIdentity(identity, passphrase) {
 
   const publicPromise = identityPromise.then(exported =>
     bufferToBase64(
-      textEncoder.encode(
+      new TextEncoder().encode(
         JSON.stringify({
           encryptPublic: exported.encryptPublic,
           signPublic: exported.signPublic
@@ -122,7 +112,7 @@ export function exportIdentity(identity, passphrase) {
         window.crypto.subtle.encrypt(
           { name: "AES-GCM", iv, tagLength: 128 },
           key,
-          textEncoder.encode(JSON.stringify(exported))
+          new TextEncoder().encode(JSON.stringify(exported))
         )
       )
       .then(
@@ -131,7 +121,7 @@ export function exportIdentity(identity, passphrase) {
       );
   } else {
     privatePromise = identityPromise.then(exported =>
-      bufferToBase64(textEncoder.encode(JSON.stringify(exported)))
+      bufferToBase64(new TextEncoder().encode(JSON.stringify(exported)))
     );
   }
 
@@ -163,7 +153,7 @@ export function importIdentity(identity, passphrase, extractable) {
   }
 
   return decrypted.then(exported => {
-    identity = JSON.parse(textDecoder.decode(exported));
+    identity = JSON.parse(new TextDecoder().decode(exported));
     return Ember.RSVP.Promise.all([
       window.crypto.subtle.importKey(
         "jwk",
@@ -246,7 +236,7 @@ export function decrypt(key, ciphertext) {
   return new Ember.RSVP.Promise((resolve, reject) => {
     window.crypto.subtle
       .decrypt({ name: "AES-GCM", iv, tagLength: 128 }, key, encrypted)
-      .then(buffer => JSON.parse(textDecoder.decode(buffer)))
+      .then(buffer => JSON.parse(new TextDecoder().decode(buffer)))
       .then(resolve, reject);
   });
 }
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 6d8dff1..fcb2271 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -34,6 +34,7 @@ en:
         user_has_no_key: "Unfortunately {{username}} did not enable encrypted messages."
 
       preferences:
+        ie11: "The required cipher suite is unavailable in Internet Explorer 11."
         insecure_context: "Encryption cannot be used in an insecure context (not HTTPS)."
 
         status_enabled: "You have enabled encryption and activated it on this device."

GitHub sha: 60124969

2 Likes