From 383899395bf599359d60337edb651af0592f82cb Mon Sep 17 00:00:00 2001
From: Justin Wind <justin.wind+git@gmail.com>
Date: Sat, 26 Mar 2022 14:59:30 -0700
Subject: [PATCH] throw simpler errors on some invalid inputs

---
 lib/common.js           |  6 ++++++
 lib/mystery-box.js      |  9 +++++++++
 test/lib/common.js      |  8 ++++++++
 test/lib/mystery-box.js | 20 ++++++++++++++++++++
 4 files changed, 43 insertions(+)

diff --git a/lib/common.js b/lib/common.js
index fb3ec97..a47226f 100644
--- a/lib/common.js
+++ b/lib/common.js
@@ -25,6 +25,9 @@ const fileScope = (filename) => {
  * @returns {String}
  */
 const base64ToBase64URL = (input) => {
+  if (!input) {
+    return input;
+  }
   return input
     .replace(/=/g, '')
     .replace(/\+/g, '-')
@@ -38,6 +41,9 @@ const base64ToBase64URL = (input) => {
  * @returns {String}
  */
 const base64URLToBase64 = (input) => {
+  if (!input) {
+    return input;
+  }
   return base64RePad(input)
     .replace(/-/g, '+')
     .replace(/_/, '/');
diff --git a/lib/mystery-box.js b/lib/mystery-box.js
index be12245..6198cc8 100644
--- a/lib/mystery-box.js
+++ b/lib/mystery-box.js
@@ -208,6 +208,10 @@ class MysteryBox {
       end: 0,
     };
 
+    if (!box) {
+      throw new RangeError('nothing to unpack');
+    }
+
     const raw = Buffer.from(common.base64URLToBase64(box), 'base64');
     let offset = 0;
 
@@ -219,6 +223,11 @@ class MysteryBox {
     const v = this.versionParameters[version];
     offset += v.versionBytes;
 
+    const minBytes = v.versionBytes + v.flagsBytes + v.ivBytes + v.saltBytes + v.tagBytes;
+    if (raw.length < minBytes) {
+      throw new RangeError('not enough to unpack');
+    }
+
     const flags = raw.slice(offset, offset + v.flagsBytes).readUInt8(0);
     offset += v.flagsBytes;
 
diff --git a/test/lib/common.js b/test/lib/common.js
index 9b4615f..f5df10c 100644
--- a/test/lib/common.js
+++ b/test/lib/common.js
@@ -26,6 +26,10 @@ describe('Common', function () {
       const result = common.base64ToBase64URL(b64);
       assert.strictEqual(result, expected);
     });
+    it('covers empty', function () {
+      const result = common.base64ToBase64URL(undefined);
+      assert.strictEqual(result, undefined);
+    });
   }); // base64ToBase64URL
 
   describe('base64URLToBase64', function () {
@@ -35,6 +39,10 @@ describe('Common', function () {
       const result = common.base64URLToBase64(b64url);
       assert.strictEqual(result, expected);
     });
+    it('covers empty', function () {
+      const result = common.base64URLToBase64(undefined);
+      assert.strictEqual(result, undefined);
+    });
   }); // base64URLToBase64
 
   describe('base64RePad', function () {
diff --git a/test/lib/mystery-box.js b/test/lib/mystery-box.js
index 8d228e6..a6e69b9 100644
--- a/test/lib/mystery-box.js
+++ b/test/lib/mystery-box.js
@@ -161,6 +161,26 @@ describe('MysteryBox', function () {
       const decryptedResult = await mb.unpack(encryptedResult);
       assert.deepStrictEqual(decryptedResult, object);
     });
+
+    it('handles undefined', async function () {
+      try {
+        await mb.unpack();
+        assert.fail(noExpectedException);
+      } catch (e) {
+        assert(e instanceof RangeError, noExpectedException);
+      }
+    });
+
+    it('handles incomplete', async function () {
+      const encryptedResult = await mb.pack({ foo: 'bar' });
+      try {
+        await mb.unpack(encryptedResult.slice(0, 6));
+        assert.fail(noExpectedException);
+      } catch (e) {
+        assert(e instanceof RangeError, noExpectedException);
+      }
+    });
+
   }); // pack, unpack
 
 }); // MysteryBox
\ No newline at end of file
-- 
2.49.0