From 2a7e5b8a54f424d7c8da5a4073ae93a9b722dbc6 Mon Sep 17 00:00:00 2001
From: Jonas Jenwald <jonas.jenwald@gmail.com>
Date: Mon, 27 Feb 2017 12:08:41 +0100
Subject: [PATCH] Support the `newWindow` flag in white-listed `app.launchURL`
 JavaScript actions (PR 7794 follow-up)

A simple follow-up to PR 7794, which let's us add support for the `newWindow` parameter; refer to https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/js_api_reference.pdf#G5.1507380.

The patch also fixes an embarrassing oversight regarding the placement of the case-insensitive flag, and also allows arbitrary white-space at the beginning of JS actions.
---
 src/core/obj.js              | 15 ++++++++++-----
 test/unit/annotation_spec.js |  6 +++++-
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/src/core/obj.js b/src/core/obj.js
index 6d96bbcc3..556a5757a 100644
--- a/src/core/obj.js
+++ b/src/core/obj.js
@@ -703,12 +703,17 @@ var Catalog = (function CatalogClosure() {
               'app.launchURL',
               'window.open'
             ];
-            var regex = new RegExp('^(?:' + URL_OPEN_METHODS.join('|') + ')' +
-                                   '\\((?:\'|\")(\\S+)(?:\'|\")(?:,|\\))');
+            var regex = new RegExp(
+              '^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') +
+              ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i');
 
-            var jsUrl = regex.exec(stringToPDFString(js), 'i');
-            if (jsUrl && jsUrl[1]) {
-              url = jsUrl[1];
+            var jsUrl = regex.exec(stringToPDFString(js));
+            if (jsUrl && jsUrl[2]) {
+              url = jsUrl[2];
+
+              if (jsUrl[3] === 'true' && jsUrl[1] === 'app.launchURL') {
+                resultObj.newWindow = true;
+              }
               break;
             }
           }
diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js
index 9498e221f..beaa83e0f 100644
--- a/test/unit/annotation_spec.js
+++ b/test/unit/annotation_spec.js
@@ -611,6 +611,7 @@ describe('annotation', function() {
         var jsEntry = params.jsEntry;
         var expectedUrl = params.expectedUrl;
         var expectedUnsafeUrl = params.expectedUnsafeUrl;
+        var expectedNewWindow = params.expectedNewWindow;
 
         var actionDict = new Dict();
         actionDict.set('Type', Name.get('Action'));
@@ -636,7 +637,7 @@ describe('annotation', function() {
         expect(data.url).toEqual(expectedUrl);
         expect(data.unsafeUrl).toEqual(expectedUnsafeUrl);
         expect(data.dest).toBeUndefined();
-        expect(data.newWindow).toBeFalsy();
+        expect(data.newWindow).toEqual(expectedNewWindow);
       }
 
       // Check that we reject a 'JS' entry containing arbitrary JavaScript.
@@ -644,12 +645,14 @@ describe('annotation', function() {
         jsEntry: 'function someFun() { return "qwerty"; } someFun();',
         expectedUrl: undefined,
         expectedUnsafeUrl: undefined,
+        expectedNewWindow: undefined,
       });
       // Check that we accept a white-listed {string} 'JS' entry.
       checkJsAction({
         jsEntry: 'window.open(\'http://www.example.com/test.pdf\')',
         expectedUrl: new URL('http://www.example.com/test.pdf').href,
         expectedUnsafeUrl: 'http://www.example.com/test.pdf',
+        expectedNewWindow: undefined,
       });
       // Check that we accept a white-listed {Stream} 'JS' entry.
       checkJsAction({
@@ -657,6 +660,7 @@ describe('annotation', function() {
                    'app.launchURL("http://www.example.com/test.pdf", true)'),
         expectedUrl: new URL('http://www.example.com/test.pdf').href,
         expectedUnsafeUrl: 'http://www.example.com/test.pdf',
+        expectedNewWindow: true,
       });
     });