Skip to main content

Inject JavaScript within PDF document body

Project description

Inject JavaScript

Inject JavaScript within PDF document body

Byte size of Inject_javascript Open Issues Open Pull Requests Latest commits



Requirements

Note, the following steps are not required if installing this project via Pip.

Python version 3 based dependencies may be installed via one of the following methods...

  • Scoped within current user...
pip3 install --user -r requirements.txt
  • Scoped with a Virtual Environment local to the directory of this project...
pip3 install --user pipenv

pipenv install -r requirements.txt

Note, review Python Guide -- virtualenvs for more information on Python Virtual Environments.

  • Or scopped for the entire system...
sudo pip3 install -r requirements.txt

Note, generally installing dependencies system-wide is not recommended.


Quick Start

Install this project via Pip

pip3 install --user --upgrade inject-javascript

Examples of running as command-line utility

  • Print available options and exit
inject-pdf-javascript --help
  • Inject .js into .pdf and save to .pdf
inject-pdf-javascript --js index.js\
 --pdf document.pdf\
 --save-path enhanced.pdf\
 --escape
  • Inject .js into .pdf and overwrite .pdf
inject-pdf-javascript --js index.js\
 --pdf document.pdf\
 --escape\
 --clobber

Example of inheriting and modifying the Inject_JavaScript class...

#!/usr/bin/env python3


from argparse import ArgumentParser


from inject_javascript import Inject_JavaScript
from inject_javascript.lib import error


class Customized_Inject_JavaScript(Inject_JavaScript):
    """
    Customizes Inject_JavaScript class
    """

    def return_js_data(self, js_path = None):
        """
        Customizes how JavaScript data is processed prior to returning
        """
        js_data = super(Customized_Inject_JavaScript, self).return_js_data(js_path = js_path)

        return js_data


if __main__ == '__name__':
    """
    Code that is run if this file is executed as a script instead of imported
    """
    ## Command line argument parsing only if being called as a script

      arg_parser = ArgumentParser(
          prog = basename(argv[0]),
          usage = '%(prog)s --pdf "/tmp/boring.pdf" --js "/dir/script.js"',
          epilog = 'For more projects see: https://github.com/S0AndS0')

      arg_parser.add_argument('--pdf-path', '--pdf',
                              help = 'Out path to save PDF',
                              required = True)

      arg_parser.add_argument('--js-path', '--js',
                              help = 'JavaScript to inject into downloaded PDF',
                              required = True)

      arg_parser.add_argument('--save-path',
                              help = 'Path to save enhanced PDF to, ignored if clobber is True')

      arg_parser.add_argument('--escape',
                              help = 'Prevent replacing/escaping of specific character combos',
                              action = 'store_true',
                              default = False)

      arg_parser.add_argument('--clobber',
                              help = 'Overwrite preexisting/input PDF',
                              action = 'store_true',
                              default = False)

      arg_parser.add_argument('--verbose', '-v',
                              help = 'Loudness of this script',
                              action = 'count')

      verbose = arg_parser.parse_known_args()[0].verbose
      args = vars(arg_parser.parse_args())

      ## Use provided command line options
      injector = Customized_inject_javascript(clobber = args.get('clobber'),
                                              escape = args.get('escape'),
                                              verbose = verbose)

      injected_path = injector.inject_pdf_with_javascript(pdf_path = args.get('pdf_path'),
                                                          js_path = args.get('js_path'),
                                                          save_path = args.get('save_path'))

      if verbose > 0:
          print('Enhanced file maybe found at: {0}'.format(injected_path))

Notes

The inject_javascript.py script currently is limited to injecting JavaScript into the document body of PDF file(s), which means certain APIs are not available such as request. Please submit a Pull Request for injecting folder level script features if additional API functionality is desired.


The --escape command-line option will double-down on backslashes (\), for example...

if (typeof app !== 'undefined') {
  var script_context = 'pdf';
} else {
  var script_context = 'browser';
};

if (script_context === 'pdf') {
  window.alert('Script context is -> PDF\nExpect features to be limited.');
} else {
  window.alert('Script context is -> Browser\nExpect features to _mostly_ be available.')
}

... the above code if injected with the --escape option would result in the following changes...

var script_context = typeof app !== 'undefined' ? 'pdf' : 'browser';

if (script_context === 'pdf') {
  window.alert('Script context is -> PDF\\nExpect features to be limited.');
} else {
  window.alert('Script context is -> Browser\\nExpect features to _mostly_ be available.')
}

... while the default behavior of inject_javascript.py is to not add additional backslashes, generally such modifications are required for JavaScript to run properly within PDF(s).


Adobe Acrobat PDF readers as of last documentation checks run JavaScript based on version 1.5 of ISO-16262 (ECMA-262 Edition 3 from December 1999), meaning that some newer ECMA Script features may not be available, thus it may be a good idea to utilize a JavaScript transpiler such as TypeScript.

tsconfig.json

{
  "compilerOptions": {
    "target": "es3",
    "module": "none",
    "lib": ["dom","es5"],
    "locale": "en-US",
    "noImplicitAny": false,
    "sourceMap": true,
    "outDir": "js"
  },
  "exclude": [
    "node_modules"
  ],
  "files": [
    "ts/index.ts"
  ]
}

Note, above example configurations may transpile JavaScript of a version that is higher than supported by PDF readers of your target audience.

ts/index.ts

let hello = (arg: string) => {
  window.alert(`Hello ${arg}!`);
};

hello('world');

js/index.js

var hello = function (arg) {
    window.alert("Hello " + arg + "!");
};
hello('world');
//# sourceMappingURL=index.js.map

Attribution


License

Documentation for injecting JavaScript within PDF document body
Copyright (C) 2020 S0AndS0

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, version 3 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

For further details review full length version of AGPL-3.0 License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inject_javascript-0.0.8.tar.gz (8.5 kB view hashes)

Uploaded source

Built Distribution

inject_javascript-0.0.8-py3-none-any.whl (21.3 kB view hashes)

Uploaded py3

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Huawei Huawei PSF Sponsor Microsoft Microsoft PSF Sponsor NVIDIA NVIDIA PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page