├── .gitattributes ├── .github └── workflows │ ├── release.yml │ └── tox.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── ChangeLog ├── HACKING ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── docs ├── Makefile ├── _templates │ └── layout.html ├── change.rst ├── conf.py ├── index.rst ├── javatools.rst ├── overview.rst ├── report.rst └── utils.rst ├── extras ├── cheetah-mode.el ├── cheetah.cfg └── sample.sh ├── javatools ├── __init__.py ├── change.py ├── cheetah │ ├── __init__.py │ ├── change_Addition.tmpl │ ├── change_Change.tmpl │ ├── change_Removal.tmpl │ ├── change_SquashedChange.tmpl │ ├── change_SuperChange.tmpl │ ├── classdiff_AnnotationsChange.tmpl │ ├── classdiff_ClassConstantPoolChange.tmpl │ ├── classdiff_ClassFieldsChange.tmpl │ ├── classdiff_ClassInfoChange.tmpl │ ├── classdiff_ClassMethodsChange.tmpl │ ├── classdiff_FieldChange.tmpl │ ├── classdiff_JavaClassReport.tmpl │ ├── classdiff_MethodAdded.tmpl │ ├── classdiff_MethodChange.tmpl │ ├── classdiff_MethodCodeChange.tmpl │ ├── classdiff_MethodRemoved.tmpl │ ├── data │ │ ├── report.css │ │ └── report.js │ ├── distdiff_DistClassChange.tmpl │ ├── distdiff_DistContentChange.tmpl │ ├── distdiff_DistReport.tmpl │ ├── jardiff_JarClassChange.tmpl │ ├── jardiff_JarContentChange.tmpl │ ├── jardiff_JarContentsReport.tmpl │ ├── jardiff_JarReport.tmpl │ ├── manifest_ManifestChange.tmpl │ ├── report.tmpl │ ├── setuptools.py │ └── subreport.tmpl ├── classdiff.py ├── classinfo.py ├── crypto.py ├── dirutils.py ├── distdiff.py ├── distinfo.py ├── jardiff.py ├── jarinfo.py ├── jarutil.py ├── manifest.py ├── opcodes.py ├── pack.py ├── report.py └── ziputils.py ├── python-javatools.spec ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── classdiff.py ├── classinfo.py ├── crypto.py ├── data ├── Makefile ├── README.md ├── Sample1.class ├── Sample1.java ├── Sample2.class ├── Sample2.java ├── Sample2A.class ├── Sample2A.java ├── Sample2I.class ├── Sample2I.java ├── Sample3.class ├── Sample3.java ├── SampleLambdas.class ├── SampleLambdas.java ├── test_classdiff │ ├── Sample1.class │ └── Sample2.class ├── test_classinfo │ └── Sample1.class ├── test_crypto │ ├── test_private_key_type__key-dsa.pem │ ├── test_private_key_type__key-ec.pem │ ├── test_private_key_type__key-invalid.pem │ ├── test_private_key_type__key-rsa-pkcs8.pem │ └── test_private_key_type__key-rsa.pem ├── test_distdiff │ ├── dist1 │ │ └── ec.jar │ ├── dist2 │ │ └── ec-tampered.jar │ ├── mf1 │ │ └── MANIFEST.MF │ ├── mf2 │ │ └── MANIFEST.MF │ ├── text1 │ │ └── file.txt │ └── text2 │ │ └── file.txt ├── test_distinfo │ └── dist1 │ │ └── Sample.jar ├── test_extensions │ ├── ca.pem │ ├── no-email-protection-cert.pem │ ├── no-email-protection.jar │ ├── no-ku-cert.pem │ ├── no-ku.jar │ ├── privkey.pem │ ├── wrong-ku-cert.pem │ └── wrong-ku.jar ├── test_jardiff │ ├── ec-copied.jar │ ├── ec-sig-block-removed.jar │ ├── ec-sig-mf-tampered.jar │ ├── ec-tampered.jar │ ├── ec.jar │ ├── generic1.jar │ └── generic2.jar ├── test_jarinfo │ └── Sample.jar ├── test_jarutil │ ├── ec-cert.pem │ ├── ec-must-fail.jar │ ├── ec-tampered.jar │ ├── ec.jar │ ├── jarutil-signed-by-jarsigner.jar │ ├── jarutil-signed.jar │ ├── javatools-cert-2.pem │ ├── javatools-cert.pem │ ├── multiple-sf-files-all-valid.jar │ ├── multiple-sf-files-some-junk.jar │ ├── several-manifest-attributes.jar │ ├── sig-related-junk-files-ok.jar │ ├── tampered-entry.jar │ ├── tampered-manifest.jar │ ├── test_cli_create_jar__test_cli_create │ │ ├── example_dir │ │ │ ├── empty_dir │ │ │ │ └── unused │ │ │ ├── example2_dir │ │ │ │ └── example3_file │ │ │ └── example2_file │ │ └── example_file │ ├── test_cli_sign_and_verify__cli-sign-and-verify.jar │ ├── test_cli_sign_and_verify__javatools-cert.pem │ ├── test_cli_sign_and_verify__javatools.pem │ ├── test_cli_sign_and_verify_ecdsa_pkcs8_sha512__cli-sign-and-verify.jar │ ├── test_cli_sign_and_verify_ecdsa_pkcs8_sha512__ec-cert.pem │ ├── test_cli_sign_and_verify_ecdsa_pkcs8_sha512__ec-key.pem │ ├── test_cli_sign_new_file_and_verify__cli-sign-and-verify.jar │ ├── test_cli_sign_new_file_and_verify__javatools-cert.pem │ ├── test_cli_sign_new_file_and_verify__javatools.pem │ ├── test_sign_with_certchain_and_verify__certchain-data.jar │ ├── test_sign_with_certchain_and_verify__certchain-intermediate.pem │ ├── test_sign_with_certchain_and_verify__certchain-root.pem │ ├── test_sign_with_certchain_and_verify__certchain-signing-key.pem │ ├── test_sign_with_certchain_and_verify__certchain-signing.pem │ └── wrong-digest-manifest.jar └── test_manifest │ ├── cli-verify-nok.jar │ ├── cli-verify-ok.jar │ ├── junk-entries.jar │ ├── manifest-sample1.jar │ ├── manifest.SHA-512.mf │ ├── manifest.SHA1.mf │ ├── manifest.dos-newlines.mf │ ├── manifest.ignores.mf │ ├── multi-digests.jar │ ├── no-entries.mf │ ├── one-valid-digest-of-several.mf │ ├── one-valid-digest-of-several.sf │ ├── sf-no-whole-digest.mf │ └── sf-no-whole-digest.sf ├── distdiff.py ├── distinfo.py ├── jardiff.py ├── jarinfo.py ├── jarutil.py ├── manifest.py └── pack.py /.gitattributes: -------------------------------------------------------------------------------- 1 | tests/data/* -text 2 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Github Action definition for publishing to PyPI when a release is 2 | # tagged. 3 | 4 | 5 | name: PyPI 6 | 7 | 8 | on: 9 | release: 10 | types: [published] 11 | 12 | 13 | jobs: 14 | 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | fail-fast: true 20 | matrix: 21 | python-version: 22 | - '2.7' 23 | - '3.9' 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Set up Python ${{ matrix.python-version }} 30 | if: ${{ matrix.python-version != '2.7' }} 31 | uses: actions/setup-python@v4 32 | with: 33 | python-version: ${{ matrix.python-version }} 34 | 35 | - name: Set up Python ${{ matrix.python-version }} 36 | if: ${{ matrix.python-version == '2.7' }} 37 | run: | 38 | sudo apt-get install -y python2 39 | 40 | - name: Install system packages 41 | run: | 42 | sudo apt-get install -y libssl-dev openssl swig 43 | 44 | - name: Install python dependencies 45 | run: | 46 | pip install wheel 47 | 48 | - name: Build source distribution 49 | if: ${{ matrix.python-version != '2.7' }} 50 | run: | 51 | python setup.py sdist --output dist 52 | 53 | - name: Build binary wheel distribution 54 | run: | 55 | python setup.py bdist_wheel --output dist 56 | 57 | - name: Save content 58 | uses: actions/upload-artifact@v3 59 | with: 60 | path: dist/ 61 | 62 | 63 | publish: 64 | name: Upload release to PyPI 65 | runs-on: ubuntu-latest 66 | 67 | needs: 68 | - build 69 | 70 | environment: 71 | name: pypi 72 | url: https://pypi.org/p/javatools 73 | 74 | steps: 75 | - name: Fetch content 76 | uses: actions/download-artifact@v4.1.7 77 | with: 78 | path: dist/ 79 | 80 | - name: Publish package distributions to PyPI 81 | uses: pypa/gh-action-pypi-publish@release/v1 82 | 83 | 84 | # The end. 85 | -------------------------------------------------------------------------------- /.github/workflows/tox.yml: -------------------------------------------------------------------------------- 1 | # Github Action definition for running tox across the supported python 2 | # versions. Intended to be triggered on push to master and on filing 3 | # of a pull_request, when those pushes hit something that impacts the 4 | # running of the tests. 5 | 6 | 7 | name: Tox 8 | 9 | 10 | on: 11 | push: 12 | branches: 13 | - master 14 | ignore-paths: 15 | - 'docs/**' 16 | paths: 17 | - 'setup.*' 18 | - '**/*.py' 19 | - '**/*.tmpl' 20 | - 'tests/**' 21 | 22 | pull_request: 23 | ignore-paths: 24 | - 'docs/**' 25 | paths: 26 | - 'setup.*' 27 | - '**/*.py' 28 | - '**/*.tmpl' 29 | - 'tests/**' 30 | 31 | 32 | jobs: 33 | build: 34 | runs-on: ubuntu-latest 35 | 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | python-version: 40 | - '2.7' 41 | - '3.7' 42 | - '3.8' 43 | - '3.9' 44 | - '3.10' 45 | 46 | steps: 47 | - name: Checkout 48 | uses: actions/checkout@v3 49 | 50 | - name: Set up Python ${{ matrix.python-version }} 51 | if: ${{ matrix.python-version != '2.7' }} 52 | uses: actions/setup-python@v4 53 | with: 54 | python-version: ${{ matrix.python-version }} 55 | 56 | - name: Set up Python ${{ matrix.python-version }} 57 | if: ${{ matrix.python-version == '2.7' }} 58 | run: | 59 | sudo apt-get install -y python2 60 | 61 | - name: Install system packages 62 | run: | 63 | sudo apt-get install -y libssl-dev openssl swig 64 | 65 | - name: Install python dependencies 66 | run: | 67 | pip install tox tox-gh-actions wheel 68 | 69 | - name: Running tox 70 | run: tox 71 | 72 | 73 | # The end. 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | *.bak 3 | *.egg-info 4 | *.gz 5 | *.pyc 6 | *.tar 7 | *~ 8 | .#* 9 | .coverage* 10 | .eggs 11 | .tox 12 | MANIFEST 13 | build 14 | dist 15 | htmlcov 16 | test 17 | tmp 18 | _build 19 | .DS_Store 20 | _deploy 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gh-pages"] 2 | path = gh-pages 3 | url = ./ 4 | branch = gh-pages 5 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Contributors, in order of appearance: 2 | 3 | Christopher O'Brien 4 | https://github.com/obriencj 5 | 6 | Jez NG 7 | https://github.com/int3 8 | 9 | Konstantin Shemyak 10 | https://github.com/KonstantinShemyak 11 | 12 | Adrian Herrera 13 | https://github.com/adrianherrera 14 | 15 | tehw0lf 16 | https://github.com/tehw0lf 17 | 18 | Hagen Fritsch 19 | https://github.com/rumpeltux 20 | 21 | Brian J Murray 22 | https://github.com/bmurray7/ 23 | 24 | Matus Jasnicky 25 | https://github.com/Matmaus 26 | 27 | Josh Gunzweig 28 | https://github.com/jgrunzweig 29 | 30 | Connor E. Basile 31 | https://github.com/CEBasile 32 | 33 | Daniel García Frías 34 | https://github.com/danielgf3 35 | 36 | Sergey Ilinykh 37 | https://github.com/Ri0n 38 | 39 | # The end. 40 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Sun Jul 02 2023 Christopher O'Brien - 1.6.0 2 | PR#113 Improves fail-proof ness (thanks Matus Jasnicky) 3 | 4 | PR#114 Raise an exception if an infinite loop occurs (thanks Matus 5 | Jasnicky) 6 | 7 | PR#116 Fixes unpack_wide function to accomodate changes in Python3 8 | (thanks Josh Grunzweig) 9 | 10 | PR#117 Improve detection of infinite loop from _typeseq_iter 11 | (thanks Matus Jasnicky) 12 | 13 | PR#124 Manifest.py has multiple bugs when using the cli function 14 | and is not usable (thanks Connor E. Basile) 15 | 16 | PR#125 Get the first element of tuple before interacting with it 17 | in the get_requires method (thanks Daniel García Frías) 18 | 19 | PR#126 Fixes invalid sentinel for file iteration (thanks Sergey 20 | Ilinykh)) 21 | 22 | PR#127 M2Crypto becomes an optional dependency. The crypto module 23 | adds a new `crypto_enabled` function to check this, and a 24 | `CryptoDisabled` exception for API calls which are invoked when 25 | M2Crypto isn't available. 26 | 27 | Change Cheetah3 pip dependency for CT3 28 | 29 | moves to tox for unittesting, flake8, and bandit integration 30 | 31 | Sun Jun 21 2020 Christopher O'Brien - 1.5.0 32 | UnknownConstantPoolTagException 33 | 34 | Updates to MethodHandle, MethodType, Dynamic, InvokeDynamic 35 | (thanks Matus Jasnicky) 36 | 37 | Sun Oct 05 2019 Christopher O'Brien - 1.4.0 38 | Python 3 support (thanks Konstantin Shemyak) 39 | 40 | Moved to Cheetah3 41 | 42 | check text file changes 43 | 44 | switch from optparse to argpase 45 | 46 | Python 2.7+ 47 | 48 | Support for signing and verifying JAR signatures (adds 49 | M2Crypto dependency) 50 | 51 | fixed issues with auto-exploding a dist and cleaning up 52 | afterwards 53 | 54 | InvokeDynamic, MethodType, and MethodHandle CONSTANT types 55 | 56 | RuntimeInvisibleAnnotations support 57 | 58 | added --ignore-manifest-key option 59 | 60 | more crypto hashes supported in manifests 61 | 62 | removed PyXML dependency 63 | 64 | Use entry_points for CLI invocation 65 | 66 | manifest enhancements 67 | 68 | bugfixes 69 | 70 | Thu May 23 2013 Christopher O'Brien - 1.3 71 | I think we've sat on these changes long enough, let's make a 72 | release 73 | 74 | expand on cheetah html reporting 75 | 76 | requires PyXML for xml.xpath 77 | 78 | renamed to python-javatools as there was already a javaclass 79 | 80 | significantly more testing before tagging a release 81 | 82 | distdiff and distpatchgen now use multiprocessing by default 83 | 84 | removed distpatchgen and javatools.patchgen 85 | 86 | added support for checking runtime annotations 87 | 88 | keep pylint happy 89 | 90 | Thu Jun 14 2012 Christopher O'Brien - 1.2 91 | require python 2.6 and later rather than trying to fight with 92 | library alternatives 93 | 94 | added classes to compartmentalize distinfo and jarinfo data 95 | 96 | reworked dependency information into a dep tree rather than a 97 | simple list 98 | 99 | rework options into groups 100 | 101 | fix for modified-utf8 in class constant pools 102 | 103 | added multiple output formats for reports (text, json, html) 104 | 105 | the html output is currently simplified, and will be expanded upon 106 | later 107 | 108 | Sun May 6 2012 Christopher O'Brien - 1.1 109 | dependency features, license files 110 | 111 | Fri Apr 27 2012 Christopher O'Brien - 1.0 112 | Initial build. 113 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | 2 | Conventions to follow while hacking: 3 | 4 | 5 | 1. API should return data, not text 6 | 7 | 2. functions or methods which print to stdout should be named with a 8 | prefix of cli_ and should only be used when invoked via the CLI. Pure 9 | API calls should not print to stdout. 10 | 11 | 3. Two blank lines after every function and method 12 | 13 | 4. Separate blocks of ideas within a function with a single blank line 14 | 15 | 5. flake8 (as configured in setup.cfg) otherwise 16 | 17 | 6. imports at the module level unless doing something tricky. Use 18 | relative imports as appropriate 19 | 20 | 7. don't over-nest function calls. don't be afraid to use a local 21 | variable to hold data between steps. It can be much clearer to read 22 | later 23 | 24 | 8. delete-trailing-whitespace or whatever it's called in your editor 25 | 26 | 9. Run `tox` and fix any unexpected issues before committing. 27 | 28 | 10. Add yourself to AUTHORS and your change to ChangeLog 29 | 30 | 31 | # The end. 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Sorry that this Makefile is a bit of a disaster. 2 | 3 | 4 | PYTHON ?= $(shell which python3 python 2>/dev/null | head -n1) 5 | PYTHON := $(PYTHON) 6 | 7 | 8 | PROJECT := $(shell $(PYTHON) ./setup.py --name) 9 | VERSION := $(shell $(PYTHON) ./setup.py --version) 10 | 11 | ARCHIVE := python-$(PROJECT)-$(VERSION).tar.gz 12 | 13 | 14 | # We use this later in setting up the gh-pages submodule for pushing, 15 | # so forks will push their docs to their own gh-pages branch. 16 | ORIGIN_PUSH = $(shell git remote get-url --push origin) 17 | 18 | 19 | ##@ Basic Targets 20 | default: quick-test ## Runs the quick-test target 21 | 22 | 23 | help: ## Display this help 24 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 25 | 26 | 27 | report-python: 28 | @echo "Using python" $(PYTHON) 29 | @$(PYTHON) -VV 30 | 31 | 32 | ##@ Local Build and Install 33 | build: clean-built report-python flake8 ## Produces a wheel using the default system python 34 | @$(PYTHON) setup.py bdist_wheel 35 | 36 | 37 | install: quick-test ## Installs using the default python for the current user 38 | @$(PYTHON) -B -m pip.__main__ \ 39 | install --no-deps --user -I \ 40 | dist/$(PROJECT)-$(VERSION)-py3-none-any.whl 41 | 42 | 43 | ##@ Cleanup 44 | tidy: ## Removes stray eggs and .pyc files 45 | @rm -rf *.egg-info 46 | @find -H . \ 47 | \( -iname '.tox' -o -iname '.eggs' -prune \) -o \ 48 | \( -type d -iname '__pycache__' -exec rm -rf {} + \) -o \ 49 | \( -type f -iname '*.pyc' -exec rm -f {} + \) 50 | 51 | 52 | clean-built: 53 | @rm -rf build/* dist/* 54 | @if [ -f ./"$(ARCHIVE)" ] ; then rm -f ./"$(ARCHIVE)" ; fi 55 | 56 | 57 | clean: clean-built tidy ## Removes built content, test logs, coverage reports 58 | @rm -rf .coverage* htmlcov/* logs/* 59 | 60 | 61 | ##@ Testing 62 | test: clean ## Launches tox 63 | @tox 64 | 65 | 66 | bandit: ## Launches bandit via tox 67 | @tox -e bandit 68 | 69 | 70 | flake8: ## Launches flake8 via tox 71 | @tox -e flake8 72 | 73 | 74 | mypy: ## Launches mypy via tox 75 | @tox -e mypy 76 | 77 | 78 | quick-test: build ## Launches nosetest using the default python 79 | @$(PYTHON) -B setup.py test $(NOSEARGS) 80 | 81 | 82 | ##@ RPMs 83 | srpm: $(ARCHIVE) ## Produce an SRPM from the archive 84 | @rpmbuild \ 85 | --define "_srcrpmdir dist" \ 86 | --define "dist %{nil}" \ 87 | -ts "$(ARCHIVE)" 88 | 89 | 90 | rpm: $(ARCHIVE) ## Produce an RPM from the archive 91 | @rpmbuild --define "_rpmdir dist" -tb "$(ARCHIVE)" 92 | 93 | 94 | archive: $(ARCHIVE) ## Extracts an archive from the current git commit 95 | 96 | 97 | # newer versions support the --format tar.gz but we're intending to work all 98 | # the way back to RHEL 6 which does not have that. 99 | $(ARCHIVE): 100 | @git archive HEAD \ 101 | --format tar --prefix "python-$(PROJECT)-$(VERSION)/" \ 102 | | gzip > "$(ARCHIVE)" 103 | 104 | 105 | ##@ Documentation 106 | docs: clean-docs docs/overview.rst ## Build sphinx docs 107 | @tox -e sphinx 108 | 109 | 110 | overview: docs/overview.rst ## rebuilds the overview from README.md 111 | 112 | 113 | docs/overview.rst: README.md 114 | @sed 's/^\[\!.*/ /g' $< > overview.md && \ 115 | pandoc --from=markdown --to=rst -o $@ "overview.md" && \ 116 | rm -f overview.md 117 | 118 | 119 | pull-docs: ## Refreshes the gh-pages submodule 120 | @git submodule init 121 | @git submodule update --remote gh-pages 122 | 123 | 124 | stage-docs: docs pull-docs ## Builds docs and stages them in gh-pages 125 | @pushd gh-pages >/dev/null && \ 126 | rm -rf * && \ 127 | touch .nojekyll ; \ 128 | popd >/dev/null ; \ 129 | cp -vr build/sphinx/dirhtml/* gh-pages/ 130 | 131 | 132 | deploy-docs: stage-docs ## Builds, stages, and deploys docs to gh-pages 133 | @pushd gh-pages >/dev/null && \ 134 | git remote set-url --push origin $(ORIGIN_PUSH) ; \ 135 | git add -A && git commit -m "deploying sphinx update" && git push ; \ 136 | popd >/dev/null ; \ 137 | if [ `git diff --name-only gh-pages` ] ; then \ 138 | git add gh-pages ; \ 139 | git commit -m "docs deploy [ci skip]" -o gh-pages ; \ 140 | fi 141 | 142 | 143 | clean-docs: ## Remove built docs 144 | @rm -rf build/sphinx/* 145 | 146 | 147 | .PHONY: archive build clean clean-built clean-docs default deploy-docs docs flake8 help mypy overview quick-test rpm srpm stage-docs test tidy 148 | 149 | 150 | # The end. 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Overview of python-javatools 3 | 4 | A [python] module for unpacking and inspecting [Java] Class files, 5 | JARs, and collections of either. Supporting features up to JDK 8. 6 | 7 | [python]: http://python.org 8 | [java]: http://www.oracle.com/technetwork/java/index.html 9 | 10 | It can do deep checking of classes to perform comparisons of 11 | functionality, and output reports in multiple formats. 12 | 13 | * [python-javatools on GitHub][github] 14 | * [python-javatools on PyPI][pypi] 15 | 16 | [github]: https://github.com/obriencj/python-javatools/ 17 | [pypi]: http://pypi.python.org/pypi/javatools 18 | 19 | If you have suggestions, please use the [issue tracker] on github. Or 20 | heck, just fork it! 21 | 22 | [issue tracker]: https://github.com/obriencj/python-javatools/issues 23 | 24 | 25 | ## Requirements 26 | 27 | * [Python] 2.7, 3.7, 3.8, 3.9, 3.10, 3.11 28 | * [Setuptools] 29 | * [Six] 30 | * [Cheetah3] is used in the generation of HTML reports 31 | * [M2Crypto] (optional) is used for cryptographic operations 32 | 33 | In addition, the following tools are used in building and testing the 34 | project. 35 | 36 | * [Tox] 37 | * [GNU Make] 38 | * [Flake8] 39 | 40 | All of these packages are available in most linux distributions 41 | (eg. Fedora), and for OSX via [MacPorts] and [HomeBrew], or available 42 | directly from pip. 43 | 44 | M2Crypto can be difficult on some platforms, and so is set as an 45 | optional dependency. If an execution path attempts to perform an 46 | action which requires M2Crypto (primarily Jar signing and Jar 47 | signature verification), then a `CryptoDisabled` exception will be 48 | raised, or a message will be printed to stdout explaining that the 49 | feature is unavailable. See the [M2Crypto Install Guide] for 50 | workarounds in your environment. 51 | 52 | [six]: https://pypi.org/project/six/ 53 | [cheetah3]: http://www.cheetahtemplate.org 54 | [pyxml]: http://www.python.org/community/sigs/current/xml-sig/ 55 | [M2Crypto]: https://gitlab.com/m2crypto/m2crypto/ 56 | 57 | [setuptools]: https://pypi.org/project/setuptools/ 58 | [gnu make]: http://www.gnu.org/software/make/ 59 | [flake8]: https://pypi.org/project/flake8/ 60 | [tox]: https://pypi.org/project/tox 61 | 62 | [fedora]: http://fedoraproject.org 63 | [macports]: http://www.macports.org 64 | [homebrew]: https://brew.sh/ 65 | 66 | [M2Crypto Install Guide]: https://gitlab.com/m2crypto/m2crypto/-/blob/master/INSTALL.rst 67 | 68 | 69 | ## Building 70 | 71 | This module uses [setuptools], so running the following will build the 72 | project: 73 | 74 | ```python setup.py build``` 75 | 76 | to install, run: 77 | 78 | ```python -m pip install . --user``` 79 | 80 | 81 | ### Testing 82 | 83 | Tests are written as `unittest` test cases. If you'd like to run the tests, 84 | simply invoke: 85 | 86 | ```python setup.py test``` 87 | 88 | or invoke tests across a wider range of platforms via ``tox`` 89 | 90 | 91 | ### RPM 92 | 93 | If you'd prefer to build an RPM, see the wiki entry for 94 | [Building as an RPM]. 95 | 96 | [building as an rpm]: https://github.com/obriencj/python-javatools/wiki/Building-as-an-RPM 97 | 98 | 99 | ## Javatools Scripts 100 | 101 | * classinfo - similar to the javap utility included with most 102 | JVMs. Also does provides/requires tracking. 103 | 104 | * classdiff - attempts to find differences between two Java class 105 | files 106 | 107 | * jarinfo - prints information about a JAR. Also does 108 | provides/requires tracking. 109 | 110 | * jardiff - prints the deltas between the contents of a JAR, and runs 111 | classdiff on differing Java class files contained in the JARs 112 | 113 | * jarutil - creates and signs JARs, verifies JAR signatures 114 | 115 | * manifest - creates and queries JAR manifests 116 | 117 | * distinfo - prints information about a mixed multi-jar/class 118 | distribution, such as provides/requires lists. 119 | 120 | * distdiff - attempts to find differences between two distributions, 121 | deep-checking any JARs or Java class files found in either 122 | directory. 123 | 124 | 125 | ## Additional References 126 | 127 | * Oracle's Java Virtual Machine Specification 128 | [Chapter 4 "The class File Format"][jvms-4] 129 | * [Java Archive (JAR) Files][jars] 130 | 131 | [jvms-4]: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 132 | [jars]: http://docs.oracle.com/javase/1.5.0/docs/guide/jar/index.html 133 | 134 | 135 | ## Contact 136 | 137 | Author: Christopher O'Brien 138 | 139 | If you're interested in my other projects, feel free to visit 140 | [my blog]. 141 | 142 | [my blog]: http://obriencj.preoccupied.net/ 143 | 144 | Original Git Repository: 145 | 146 | 147 | ## License 148 | 149 | This library is free software; you can redistribute it and/or modify 150 | it under the terms of the GNU Lesser General Public License as 151 | published by the Free Software Foundation; either version 3 of the 152 | License, or (at your option) any later version. 153 | 154 | This library is distributed in the hope that it will be useful, but 155 | WITHOUT ANY WARRANTY; without even the implied warranty of 156 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 157 | Lesser General Public License for more details. 158 | 159 | You should have received a copy of the GNU Lesser General Public 160 | License along with this library; if not, see 161 | . 162 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - standardize on use of pretty_* named functions and methods 2 | 3 | - perhaps diff-like opcode output for method code? That would be a bit 4 | of an undertaking; would it be at all worth it? 5 | 6 | - a class or class-member attribute discovery script 7 | 8 | - switch to using logging instead of print statements for CLI output 9 | (bad idea?) 10 | 11 | - fill in more docstrings with meaningful explanations 12 | 13 | - options to classinfo and jarinfo to attempt to fulfill dependencies 14 | (possibly recursively) from discoverable locations (JAVA_HOME, 15 | CLASSPATH, etc) and output missing deps 16 | 17 | - add signature information to jarinfo. 18 | 19 | - full classinfo --json support 20 | 21 | - move JarChange to use a JarInfo instance rather than path name 22 | 23 | - move DistChange to use a DistInfo instance rather than path name 24 | 25 | - flesh out the cheetah templates for classdiff reports 26 | 27 | - generics type signature handling 28 | 29 | - default annotation value attribute 30 | 31 | - pomdiff? maven-repo-diff? 32 | 33 | - [silly] output class files from classinfo data 34 | 35 | - given the way ACC_SUPER works, it's probably not at all useful to do 36 | symbol-level dependency tracking. Instead it should likely just be 37 | class-based. I'll need to change distinfo/jarinfo/classinfo 38 | accordingly. 39 | 40 | - the cheetah MethodCodeChange template needs to show the locals, stack, 41 | and exception table. 42 | 43 | - MethodCodeChange also needs to colorize the unified lines of code 44 | table 45 | 46 | - the cheetah ManifestChange template needs a lot of work. What should 47 | a manifest delta look like? 48 | 49 | - need some javascript magic to make cpool refs have a cute 50 | clicky-effect that shows their dereferenced value. 51 | 52 | - need some javascript magic that allows hiding unchanged/ignored, or 53 | collapsing individual sections with a twisty. 54 | 55 | - distreport needs a class-oriented page that allows quick jumping to 56 | the class reports, rather than requiring users to know which jar 57 | report to look in. 58 | 59 | - dist/jar/class html reports need to link to the json and text 60 | variants 61 | 62 | - for distributed text, I could use diff to generate a delta, how 63 | insane is that? Or perhaps the python diff module... 64 | 65 | - invokedynamic and all of its friends need support 66 | 67 | - investigate jinja2 as a replacement for Cheetah 68 | 69 | # 70 | -------------------------------------------------------------------------------- /docs/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {% block footer %} 4 | {{ super() }} 5 | 9 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /docs/change.rst: -------------------------------------------------------------------------------- 1 | Comparing Java Artifacts 2 | ======================== 3 | 4 | 5 | javatools.change 6 | ---------------- 7 | 8 | .. automodule:: javatools.change 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | javatools.classdiff 15 | ------------------- 16 | 17 | .. automodule:: javatools.classdiff 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | 23 | javatools.jardiff 24 | ----------------- 25 | 26 | .. automodule:: javatools.jardiff 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | 32 | javatools.distdiff 33 | ------------------ 34 | 35 | .. automodule:: javatools.distdiff 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | python-javatools 2 | ================ 3 | 4 | Contents: 5 | 6 | .. toctree:: 7 | :maxdepth: 4 8 | 9 | overview 10 | javatools 11 | change 12 | report 13 | utils 14 | -------------------------------------------------------------------------------- /docs/javatools.rst: -------------------------------------------------------------------------------- 1 | Javatools Core Modules 2 | ====================== 3 | 4 | 5 | javatools 6 | --------- 7 | 8 | .. automodule:: javatools 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | javatools.classinfo 15 | ------------------- 16 | 17 | .. automodule:: javatools.classinfo 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | 23 | javatools.jarinfo 24 | ----------------- 25 | 26 | .. automodule:: javatools.jarinfo 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | 32 | javatools.distinfo 33 | ------------------ 34 | 35 | .. automodule:: javatools.distinfo 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | -------------------------------------------------------------------------------- /docs/overview.rst: -------------------------------------------------------------------------------- 1 | Overview of python-javatools 2 | ============================ 3 | 4 | A `python `__ module for unpacking and inspecting 5 | `Java `__ Class 6 | files, JARs, and collections of either. Supporting features up to JDK 8. 7 | 8 | It can do deep checking of classes to perform comparisons of 9 | functionality, and output reports in multiple formats. 10 | 11 | - `python-javatools on 12 | GitHub `__ 13 | - `python-javatools on PyPI `__ 14 | 15 | If you have suggestions, please use the `issue 16 | tracker `__ on 17 | github. Or heck, just fork it! 18 | 19 | Requirements 20 | ------------ 21 | 22 | - `Python `__ 2.7, 3.7, 3.8, 3.9, 3.10, 3.11 23 | - `Setuptools `__ 24 | - `Six `__ 25 | - `Cheetah3 `__ is used in the 26 | generation of HTML reports 27 | - `M2Crypto `__ (optional) is 28 | used for cryptographic operations 29 | 30 | In addition, the following tools are used in building and testing the 31 | project. 32 | 33 | - `Tox `__ 34 | - `GNU Make `__ 35 | - `Flake8 `__ 36 | 37 | All of these packages are available in most linux distributions (eg. 38 | Fedora), and for OSX via `MacPorts `__ and 39 | `HomeBrew `__, or available directly from pip. 40 | 41 | M2Crypto can be difficult on some platforms, and so is set as an 42 | optional dependency. If an execution path attempts to perform an action 43 | which requires M2Crypto (primarily Jar signing and Jar signature 44 | verification), then a ``CryptoDisabled`` exception will be raised, or a 45 | message will be printed to stdout explaining that the feature is 46 | unavailable. See the `M2Crypto Install 47 | Guide `__ 48 | for workarounds in your environment. 49 | 50 | Building 51 | -------- 52 | 53 | This module uses `setuptools `__, 54 | so running the following will build the project: 55 | 56 | ``python setup.py build`` 57 | 58 | to install, run: 59 | 60 | ``python -m pip install . --user`` 61 | 62 | Testing 63 | ~~~~~~~ 64 | 65 | Tests are written as ``unittest`` test cases. If you’d like to run the 66 | tests, simply invoke: 67 | 68 | ``python setup.py test`` 69 | 70 | or invoke tests across a wider range of platforms via ``tox`` 71 | 72 | RPM 73 | ~~~ 74 | 75 | If you’d prefer to build an RPM, see the wiki entry for `Building as an 76 | RPM `__. 77 | 78 | Javatools Scripts 79 | ----------------- 80 | 81 | - classinfo - similar to the javap utility included with most JVMs. 82 | Also does provides/requires tracking. 83 | 84 | - classdiff - attempts to find differences between two Java class files 85 | 86 | - jarinfo - prints information about a JAR. Also does provides/requires 87 | tracking. 88 | 89 | - jardiff - prints the deltas between the contents of a JAR, and runs 90 | classdiff on differing Java class files contained in the JARs 91 | 92 | - jarutil - creates and signs JARs, verifies JAR signatures 93 | 94 | - manifest - creates and queries JAR manifests 95 | 96 | - distinfo - prints information about a mixed multi-jar/class 97 | distribution, such as provides/requires lists. 98 | 99 | - distdiff - attempts to find differences between two distributions, 100 | deep-checking any JARs or Java class files found in either directory. 101 | 102 | Additional References 103 | --------------------- 104 | 105 | - Oracle’s Java Virtual Machine Specification `Chapter 4 “The class 106 | File 107 | Format” `__ 108 | - `Java Archive (JAR) 109 | Files `__ 110 | 111 | Contact 112 | ------- 113 | 114 | Author: Christopher O’Brien obriencj@gmail.com 115 | 116 | If you’re interested in my other projects, feel free to visit `my 117 | blog `__. 118 | 119 | Original Git Repository: https://github.com/obriencj/python-javatools 120 | 121 | License 122 | ------- 123 | 124 | This library is free software; you can redistribute it and/or modify it 125 | under the terms of the GNU Lesser General Public License as published by 126 | the Free Software Foundation; either version 3 of the License, or (at 127 | your option) any later version. 128 | 129 | This library is distributed in the hope that it will be useful, but 130 | WITHOUT ANY WARRANTY; without even the implied warranty of 131 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 132 | General Public License for more details. 133 | 134 | You should have received a copy of the GNU Lesser General Public License 135 | along with this library; if not, see http://www.gnu.org/licenses/. 136 | -------------------------------------------------------------------------------- /docs/report.rst: -------------------------------------------------------------------------------- 1 | Reporting Changes 2 | ================= 3 | 4 | 5 | javatools.report 6 | ---------------- 7 | 8 | .. automodule:: javatools.report 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | javatools.cheetah 15 | ----------------- 16 | 17 | .. automodule:: javatools.cheetah 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/utils.rst: -------------------------------------------------------------------------------- 1 | Utility Modules 2 | =============== 3 | 4 | 5 | javatools.pack 6 | -------------- 7 | 8 | .. automodule:: javatools.pack 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | javatools.opcodes 15 | ----------------- 16 | 17 | .. automodule:: javatools.opcodes 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | 23 | javatools.manifest 24 | ------------------ 25 | 26 | .. automodule:: javatools.manifest 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | 32 | javatools.dirutils 33 | ------------------ 34 | 35 | .. automodule:: javatools.dirutils 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | 40 | 41 | javatools.ziputils 42 | ------------------ 43 | 44 | .. automodule:: javatools.ziputils 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | -------------------------------------------------------------------------------- /extras/cheetah-mode.el: -------------------------------------------------------------------------------- 1 | ;; cheetah-mode.el 2 | ;; 3 | ;; original from http://www.emacswiki.org/emacs/CheetahMode 4 | ;; 5 | ;; updated by obriencj@gmail.com to understand block, elif, implements. 6 | ;; 7 | ;; wishlist: make PSP <% %> sections look like python-mode 8 | 9 | (define-derived-mode cheetah-mode html-mode "Cheetah" 10 | (make-face 'cheetah-variable-face) 11 | (font-lock-add-keywords 12 | nil 13 | '(("\\(#\\(from\\|else\\|include\\|extends\\|implements\\|block\\|set\\|def\\|import\\|for\\|if\\|elif\\|end\\)+\\)\\>" 1 font-lock-type-face) 14 | ("\\(#\\(from\\|for\\|end\\)\\).*\\<\\(for\\|import\\|block\\|def\\|if\\|in\\)\\>" 3 font-lock-type-face) 15 | ("\\(##.*\\)\n" 1 font-lock-comment-face) 16 | ("\\(\\$\\(?:\\sw\\|}\\|{\\|\\s_\\)+\\)" 1 font-lock-variable-name-face))) 17 | (font-lock-mode 1)) 18 | 19 | (provide 'cheetah-mode) 20 | (add-to-list 'auto-mode-alist '("\\.tmpl$" . cheetah-mode)) 21 | -------------------------------------------------------------------------------- /extras/cheetah.cfg: -------------------------------------------------------------------------------- 1 | [globals] 2 | 3 | outputRowColComments = False 4 | includeBlockMarkers = True 5 | addTimestampsToCompilerOutput = False 6 | defDocStrMsg = " " 7 | 8 | # The end. 9 | -------------------------------------------------------------------------------- /extras/sample.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | 4 | # Grabs two copies of JBoss AS (6.0.0 and 6.1.0) and uses them to 5 | # produce a timed, multi-processing-enabled run of distdiff with all 6 | # reports enabled, and a profiled (via cProfile) single-process run of 7 | # distdiff with all reports enabled. 8 | 9 | 10 | # this is currently the closest that we come to having test-suite 11 | # coverage. I'm slowly fixing that problem. 12 | 13 | 14 | OUTPUT_DIR=build/sample 15 | DO_TIMED= 16 | DO_PROFILED= 17 | 18 | 19 | # the data for the left-side of the comparison 20 | SAMPLE_URL_LEFT="http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-6.0.0.Final/jboss-as-distribution-6.0.0.Final.zip?use_mirror=tcpdiag" 21 | SAMPLE_FILE_LEFT=$OUTPUT_DIR/jboss-as-distribution-6.0.0.Final.zip 22 | SAMPLE_DIR_LEFT=$OUTPUT_DIR/jboss-6.0.0.Final 23 | 24 | 25 | # the data for the right-side of the comparison 26 | SAMPLE_URL_RIGHT=http://download.jboss.org/jbossas/6.1/jboss-as-distribution-6.1.0.Final.zip 27 | SAMPLE_FILE_RIGHT=$OUTPUT_DIR/jboss-as-distribution-6.1.0.Final.zip 28 | SAMPLE_DIR_RIGHT=$OUTPUT_DIR/jboss-6.1.0.Final 29 | 30 | 31 | function run_help() { 32 | echo "Usage: $0 [OPTIONS]" 33 | echo "Fetches sample distributions and runs a full report" 34 | echo 35 | echo " Options:" 36 | echo " --help print this message" 37 | echo " --time run a timed report" 38 | echo " --profile run a profiled report" 39 | echo " --output=DIR directory to write work into" 40 | echo " default: $OUTPUT_DIR" 41 | echo 42 | } 43 | 44 | 45 | for arg in "$@" ; do 46 | case "$arg" in 47 | --help) 48 | run_help 49 | exit 1 50 | ;; 51 | 52 | --time) 53 | DO_TIMED=1 54 | ;; 55 | 56 | --profile) 57 | DO_PROFILED=1 58 | ;; 59 | 60 | --output=*) 61 | OUTPUT_DIR="${arg#--output=}" 62 | ;; 63 | esac 64 | done 65 | 66 | 67 | mkdir -p $OUTPUT_DIR 68 | 69 | 70 | echo "Fetching sample data if needed" 71 | if test ! -d "$SAMPLE_DIR_LEFT" ; then 72 | if test ! -f "$SAMPLE_FILE_LEFT" ; then 73 | wget -c "$SAMPLE_URL_LEFT" -O "$SAMPLE_FILE_LEFT" 74 | fi 75 | unzip -q "$SAMPLE_FILE_LEFT" -d "$OUTPUT_DIR/" 76 | fi 77 | 78 | if test ! -d "$SAMPLE_DIR_RIGHT" ; then 79 | if test ! -f "$SAMPLE_FILE_RIGHT" ; then 80 | wget -c "$SAMPLE_URL_RIGHT" -O "$SAMPLE_FILE_RIGHT" 81 | fi 82 | unzip -q "$SAMPLE_FILE_RIGHT" -d "$OUTPUT_DIR/" 83 | fi 84 | 85 | 86 | function just_run() { 87 | echo "Running normal report" 88 | 89 | PYTHONPATH=build/lib/ \ 90 | build/scripts-2.7/distdiff \ 91 | -q --show-ignored \ 92 | --ignore=version,platform,lines,pool \ 93 | --ignore=manifest_subsections,jar_signature \ 94 | --ignore=trailing_whitespace \ 95 | --report=html,txt,json \ 96 | --report=html,txt,json \ 97 | --report-dir=$OUTPUT_DIR/normal/reports \ 98 | --html-copy-data=$OUTPUT_DIR/normal/resources \ 99 | "$SAMPLE_DIR_LEFT" "$SAMPLE_DIR_RIGHT" 100 | 101 | echo "Report output written at $OUTPUT_DIR/normal/reports" 102 | } 103 | 104 | 105 | function run_timed() { 106 | echo "Running full-speed report for timing" 107 | 108 | PYTHONPATH=build/lib/ \ 109 | /usr/bin/time -v -o $OUTPUT_DIR/timed/distdiff.time \ 110 | build/scripts-2.7/distdiff \ 111 | -q --show-ignored \ 112 | --ignore=version,platform,lines,pool \ 113 | --ignore=manifest_subsections,jar_signature \ 114 | --ignore=trailing_whitespace \ 115 | --report=html,txt,json \ 116 | --report=html,txt,json \ 117 | --report-dir=$OUTPUT_DIR/timed/reports \ 118 | --html-copy-data=$OUTPUT_DIR/timed/resources \ 119 | "$SAMPLE_DIR_LEFT" "$SAMPLE_DIR_RIGHT" 120 | 121 | cat $OUTPUT_DIR/distdiff.time 122 | echo "Timing data saved at $OUTPUT_DIR/timed/distdiff.time" 123 | echo "Report output written at $OUTPUT_DIR/timed/reports" 124 | } 125 | 126 | 127 | function run_profiled() { 128 | echo "Running single-process report for profiling dump" 129 | 130 | PYTHONPATH=build/lib/ \ 131 | python -m cProfile -o $OUTPUT_DIR/profiled/distdiff.dump \ 132 | build/scripts-2.7/distdiff \ 133 | -q --show-ignored --processes=0 \ 134 | --ignore=version,platform,lines,pool \ 135 | --ignore=manifest_subsections,jar_signature \ 136 | --ignore=trailing_whitespace \ 137 | --report=html,txt,json \ 138 | --report-dir=$OUTPUT_DIR/profiled/reports \ 139 | --html-copy-data=$OUTPUT_DIR/profiled/resources \ 140 | "$SAMPLE_DIR_LEFT" "$SAMPLE_DIR_RIGHT" 141 | 142 | echo "Profiling data saved at $OUTPUT_DIR/profiled/distdiff.dump" 143 | echo "Report output written at $OUTPUT_DIR/profiled/reports" 144 | } 145 | 146 | 147 | echo "Building" 148 | ./setup.py clean build || exit 1 149 | 150 | 151 | if test "$DO_TIMED" ; then run_timed ; fi 152 | if test "$DO_PROFILED" ; then run_profiled ; fi 153 | 154 | if test ! "$DO_TIMED$DO_PROFILED" ; then just_run ; fi 155 | 156 | 157 | # 158 | # The end. 159 | -------------------------------------------------------------------------------- /javatools/cheetah/__init__.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | 17 | """ 18 | Collects available Cheetah templates for use with the HTML report 19 | 20 | author: Christopher O'Brien 21 | license: LGPL 22 | """ 23 | 24 | 25 | from pkgutil import iter_modules 26 | 27 | 28 | def _iter_templates(): 29 | """ 30 | uses reflection to yield the Cheetah templates under this module 31 | """ 32 | 33 | # pylint: disable=W0406 34 | # needed for introspection 35 | import javatools.cheetah 36 | from Cheetah.Template import Template 37 | 38 | for _, name, _ in iter_modules(__path__): 39 | if name == "setuptools": 40 | continue 41 | 42 | __import__("javatools.cheetah." + name) 43 | found = getattr(getattr(javatools.cheetah, name), name) 44 | if issubclass(found, Template): 45 | yield found 46 | 47 | 48 | def get_templates(): 49 | """ 50 | The Cheetah Template classes contained within this module 51 | """ 52 | 53 | return tuple(_iter_templates()) 54 | 55 | 56 | def xml_entity_escape(data): 57 | """ 58 | replace special characters with their XML entity versions 59 | """ 60 | 61 | data = data.replace("&", "&") 62 | data = data.replace(">", ">") 63 | data = data.replace("<", "<") 64 | return data 65 | 66 | 67 | # 68 | # The end. 69 | -------------------------------------------------------------------------------- /javatools/cheetah/change_Addition.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | 3 | 4 | ## 5 | ## The end. 6 | -------------------------------------------------------------------------------- /javatools/cheetah/change_Change.tmpl: -------------------------------------------------------------------------------- 1 | #from javatools.cheetah import xml_entity_escape as escape 2 | 3 | 4 | <% 5 | ch = getattr(self, "change") 6 | opts = getattr(self, "options") 7 | 8 | cl = ["Change"] 9 | cl.append(type(ch).__name__) 10 | 11 | if ch.is_change(): 12 | cl.append("is_changed") 13 | if ch.is_ignored(opts): 14 | cl.append("is_ignored") 15 | else: 16 | cl.append("is_unchanged") 17 | 18 | cl = " ".join(cl) 19 | %> 20 | 21 | 22 |
23 | 24 | #block description 25 |
26 | $escape($change.label) 27 |
28 | #end block 29 | 30 | 31 | #block details 32 | #end block 33 | 34 | 35 | #block collect 36 | #if $change.collect() 37 |
38 | #for child in $change.collect() 39 | $render_change(child) 40 | #end for 41 |
42 | #end if 43 | #end block 44 | 45 |
46 | 47 | 48 | ## 49 | ## The end. 50 | -------------------------------------------------------------------------------- /javatools/cheetah/change_Removal.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | 3 | 4 | ## 5 | ## The end. 6 | -------------------------------------------------------------------------------- /javatools/cheetah/change_SquashedChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | #implements respond 4 | 5 | 6 | <% 7 | ch = getattr(self, "change") 8 | opts = getattr(self, "options") 9 | 10 | cl = ["Change"] 11 | cl.append(type(ch).__name__) 12 | cl.append(ch.origclass.__name__) 13 | 14 | if ch.is_change(): 15 | cl.append("is_changed") 16 | if ch.is_ignored(opts): 17 | cl.append("is_ignored") 18 | else: 19 | cl.append("is_unchanged") 20 | 21 | cl = " ".join(cl) 22 | %> 23 | 24 | 25 |
26 | #block description 27 | <% 28 | change = getattr(self, "change") 29 | oc = change.origclass 30 | uri = "%s/%s.html" % (change.entry, oc.report_name) 31 | %> 32 | $escape($change.entry) 33 | [details] 34 | #end block 35 |
36 | 37 | 38 | ## 39 | ## The end. 40 | -------------------------------------------------------------------------------- /javatools/cheetah/change_SuperChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | 3 | ## 4 | ## The end. 5 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_AnnotationsChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.subreport 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | #from six.moves import zip_longest 4 | 5 | 6 | #block details 7 |
8 |
9 | #if $change.is_change() 10 | $render_dual_annotations($change.get_ldata(), $change.get_rdata()) 11 | #else 12 | $render_annotations($change.get_ldata()) 13 | #end if 14 |
15 |
16 | #end block 17 | 18 | 19 | #block description 20 |
$change.label
21 | #end block 22 | 23 | 24 | #def render_annotations(annos) 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | #for index in range(0, len(annos)) 33 | 34 | 35 | 36 | 37 | #end for 38 |
IndexAnnotation
<%= index %><%= annos[index].pretty_annotation() %>
39 | #end def 40 | 41 | 42 | #def render_dual_annotations(left, right) 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | <% index = 0 %> 55 | #for la, ra in zip_longest(left, right) 56 | 57 | 58 | 60 | 61 | #if (la == ra) 62 | 64 | #else 65 | 67 | #end if 68 | 69 | <% index += 1 %> 70 | #end for 71 |
IndexAnnotation
OriginalChanged
<%= index %> 59 | <%= (la and la.pretty_annotation()) or "" %> 63 | <%= (ra and ra.pretty_annotation()) or "" %> 66 | <%= (ra and ra.pretty_annotation()) or "" %>
72 | #end def 73 | 74 | 75 | ## 76 | ## The end. 77 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_ClassConstantPoolChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.subreport 2 | #from javatools.classdiff import pretty_merge_constants 3 | #from javatools.cheetah import xml_entity_escape as escape 4 | 5 | 6 | 7 | #block details 8 |
9 |
10 | #if $change.is_change() 11 | $render_dual_constant_pool($change.get_ldata(), $change.get_rdata()) 12 | #else 13 | $render_constant_pool($change.pretty_ldata()) 14 | #end if 15 |
16 |
17 | #end block 18 | 19 | 20 | 21 | #def render_constant_pool(consts) 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | #for i, t, v in consts 32 | 33 | 34 | 35 | 36 | 37 | #end for 38 | 39 |
IndexTypeValue
<%= i %><%= t %><%= escape(str(v)) %>
40 | #end def 41 | 42 | 43 | 44 | #def render_dual_constant_pool(left, right) 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | #for index, lt, lv, rt, rv in pretty_merge_constants(left, right) 57 | <% 58 | row_class = (" is_changed")[(lt, lv) == (rt, rv)] 59 | %> 60 | 61 | 62 | 63 | 64 | #if (lt, lv) == (rt, rv) 65 | 66 | 67 | #else 68 | 69 | 70 | 71 | #end if 72 | #end for 73 | 74 |
IndexOriginal TypeOriginal ValueModified TypeModified Value
<%= index %><%= lt or "" %><%= escape(str(lv or "")) %><%= rt or "" %><%= escape(str(rv or "")) %>
75 | #end def 76 | 77 | 78 | 79 | ## 80 | ## The end. 81 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_ClassFieldsChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.subreport 2 | 3 | 4 | 5 | ## 6 | ## The end. 7 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_ClassInfoChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.subreport 2 | #from javatools.change import collect_by_typename 3 | #from javatools.cheetah import xml_entity_escape as escape 4 | 5 | 6 | 7 | #block details 8 | <% 9 | change = getattr(self, "change") 10 | data = collect_by_typename(change.collect()) 11 | %> 12 |
13 |
14 | 15 | 16 | $sub_classname(data["ClassNameChange"][0]) 17 | $sub_flags(data["ClassAccessflagsChange"][0]) 18 | $sub_super(data["ClassSuperclassChange"][0]) 19 | $sub_inter(data["ClassInterfacesChange"][0]) 20 | $sub_version(data["ClassVersionChange"][0]) 21 | $sub_platform(data["ClassPlatformChange"][0]) 22 | $sub_signature(data["ClassSignatureChange"][0]) 23 | $sub_deprecation(data["ClassDeprecationChange"][0]) 24 |
25 | 26 |
27 |
28 | #end block 29 | 30 | 31 | 32 | #block collect 33 | #end block 34 | 35 | 36 | 37 | #def sub_classname(subch) 38 | #set label = "Class Name" 39 | #if subch.is_change() 40 | 41 | $label 42 | <%= subch.pretty_ldata() %> 43 | 44 | 45 | <%= subch.pretty_rdata() %> 46 | 47 | #else 48 | 49 | $label 50 | <%= subch.pretty_ldata() %> 51 | 52 | #end if 53 | #end def 54 | 55 | 56 | 57 | #def sub_flags(subch) 58 | #set label = "Class Flags" 59 | #if subch.is_change() 60 | 61 | $label 62 | <%= "0x%04x" % subch.get_ldata() %>: 63 | <%= " ".join(subch.pretty_ldata()) %> 64 | 65 | 66 | 67 | <%= "0x%04x" % subch.get_rdata() %>: 68 | <%= " ".join(subch.pretty_rdata()) %> 69 | 70 | #else 71 | 72 | $label 73 | <%= "0x%04x" % subch.get_ldata() %>: 74 | <%= " ".join(subch.pretty_ldata()) %> 75 | 76 | #end if 77 | #end def 78 | 79 | 80 | 81 | #def sub_super(subch) 82 | #set label = "Extends" 83 | #if subch.is_change() 84 | 85 | $label 86 | <%= subch.pretty_ldata() %> 87 | 88 | 89 | <%= subch.pretty_rdata() %> 90 | 91 | #else 92 | 93 | $label 94 | <%= subch.pretty_ldata() %> 95 | 96 | #end if 97 | #end def 98 | 99 | 100 | 101 | #def sub_inter(subch) 102 | #set label = "Implements" 103 | #if subch.is_change() 104 | 105 | $label 106 | <%= ", ".join(subch.pretty_ldata()) or "(None)" %> 107 | 108 | 109 | 110 | <%= ", ".join(subch.pretty_rdata()) or "(None)" %> 111 | 112 | #elif subch.get_ldata() 113 | 114 | $label 115 | <%= ", ".join(subch.pretty_ldata()) %> 116 | 117 | #end if 118 | #end def 119 | 120 | 121 | 122 | #def sub_version(subch) 123 | #set label = "Java Version" 124 | #set templ = "Major: %i, Minor: %i" 125 | #if subch.is_change() 126 | 127 | $label 128 | <%= templ % subch.get_ldata() %> 129 | 130 | 131 | <%= templ % subch.get_rdata() %> 132 | 133 | #else 134 | 135 | $label 136 | <%= templ % subch.get_ldata() %> 137 | 138 | #end if 139 | #end def 140 | 141 | 142 | 143 | #def sub_platform(subch) 144 | #set label = "Java Platform" 145 | #if subch.is_change() 146 | 147 | $label 148 | <%= subch.pretty_ldata() %> 149 | 150 | 151 | <%= subch.pretty_rdata() %> 152 | 153 | #else 154 | 155 | $label 156 | <%= subch.pretty_ldata() %> 157 | 158 | #end if 159 | #end def 160 | 161 | 162 | 163 | #def sub_signature(subch) 164 | #set label = "Generics Signature" 165 | #if subch.is_change() 166 | 167 | $label 168 | <%= escape(subch.pretty_ldata() or "(None)") %> 169 | 170 | 171 | 172 | <%= escape(subch.pretty_rdata() or "(None)") %> 173 | 174 | #elif subch.get_ldata() 175 | 176 | $label 177 | <%= escape(subch.pretty_ldata()) %> 178 | 179 | #end if 180 | #end def 181 | 182 | 183 | 184 | #def sub_deprecation(subch) 185 | #set label = "Deprecated" 186 | #if subch.is_change() 187 | 188 | $label 189 | <%= subch.pretty_ldata() %> 190 | 191 | 192 | <%= subch.pretty_rdata() %> 193 | 194 | #elif subch.get_ldata() 195 | 196 | $label 197 | <%= subch.pretty_ldata() %> 198 | 199 | #end if 200 | #end def 201 | 202 | 203 | 204 | ## 205 | ## The end. 206 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_ClassMethodsChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.subreport 2 | 3 | 4 | 5 | ## 6 | ## The end. 7 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_FieldChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | #from javatools.change import collect_by_typename 3 | #from javatools.cheetah import xml_entity_escape as escape 4 | 5 | 6 | 7 | #block description 8 | <% 9 | change = getattr(self, "change") 10 | ldata = change.get_ldata() 11 | nom = ldata.get_name() 12 | %> 13 |

<%= escape(nom) %>

14 | #end block 15 | 16 | 17 | 18 | #block details 19 | <% 20 | change = getattr(self, "change") 21 | data = collect_by_typename(change.collect()) 22 | %> 23 | 24 |
25 |
26 | 27 | 28 | $sub_name(data.pop("FieldNameChange")[0]) 29 | $sub_type(data.pop("FieldTypeChange")[0]) 30 | $sub_flags(data.pop("FieldAccessflagsChange")[0]) 31 | $sub_signature(data.pop("FieldSignatureChange")[0]) 32 | $sub_const(data.pop("FieldConstvalueChange")[0]) 33 | $sub_deprecation(data.pop("FieldDeprecationChange")[0]) 34 |
35 | 36 |
37 |
38 | #end block 39 | 40 | 41 | 42 | #block collect 43 | <% 44 | change = getattr(self, "change") 45 | data = collect_by_typename(change.collect()) 46 | %> 47 |
48 | $render_change(data.pop("FieldAnnotationsChange")[0]) 49 | $render_change(data.pop("FieldInvisibleAnnotationsChange")[0]) 50 |
51 | #end block 52 | 53 | 54 | 55 | #def sub_name(subch) 56 | #set label = "Field Name" 57 | #if subch.is_change() 58 | 59 | $label 60 | <%= escape(subch.pretty_ldata()) %> 61 | 62 | 63 | <%= escape(subch.pretty_rdata()) %> 64 | 65 | #else 66 | 67 | $label 68 | <%= escape(subch.pretty_ldata()) %> 69 | 70 | #end if 71 | #end def 72 | 73 | 74 | 75 | #def sub_type(subch) 76 | #set label = "Field Type" 77 | #if subch.is_change() 78 | 79 | $label 80 | <%= subch.pretty_ldata() %> 81 | 82 | 83 | <%= subch.pretty_rdata() %> 84 | 85 | #else 86 | 87 | $label 88 | <%= subch.pretty_ldata() %> 89 | 90 | #end if 91 | #end def 92 | 93 | 94 | 95 | #def sub_flags(subch) 96 | #set label = "Field Flags" 97 | #if subch.is_change() 98 | 99 | $label 100 | <%= "0x%04x" % subch.get_ldata() %>: 101 | <%= " ".join(subch.pretty_ldata()) %> 102 | 103 | 104 | 105 | <%= "0x%04x" % subch.get_rdata() %>: 106 | <%= " ".join(subch.pretty_rdata()) %> 107 | 108 | #else 109 | 110 | $label 111 | <%= "0x%04x" % subch.get_ldata() %>: 112 | <%= " ".join(subch.pretty_ldata()) %> 113 | 114 | #end if 115 | #end def 116 | 117 | 118 | 119 | #def sub_signature(subch) 120 | #set label = "Generics Signature" 121 | #if subch.is_change() 122 | 123 | $label 124 | <%= escape(subch.pretty_ldata() or "(None)") %> 125 | 126 | 127 | 128 | <%= escape(subch.pretty_rdata() or "(None)") %> 129 | 130 | #elif subch.get_ldata() 131 | 132 | $label 133 | <%= escape(subch.pretty_ldata()) %> 134 | 135 | #end if 136 | #end def 137 | 138 | 139 | 140 | #def sub_const(subch) 141 | #set label = "Const Value" 142 | #if subch.is_change() 143 | 144 | $label 145 | <%= escape(subch.pretty_ldata() or "(None)") %> 146 | 147 | 148 | 149 | <%= escape(subch.pretty_rdata() or "(None)") %> 150 | 151 | #elif subch.get_ldata() 152 | 153 | $label 154 | <%= escape(subch.pretty_ldata()) %> 155 | 156 | #end if 157 | #end def 158 | 159 | 160 | 161 | #def sub_deprecation(subch) 162 | #set label = "Deprecated" 163 | #if subch.is_change() 164 | 165 | $label 166 | <%= subch.pretty_ldata() %> 167 | 168 | 169 | <%= subch.pretty_rdata() %> 170 | 171 | #elif subch.get_ldata() 172 | 173 | $label 174 | <%= subch.pretty_ldata() %> 175 | 176 | #end if 177 | #end def 178 | 179 | 180 | 181 | ## 182 | ## The end. 183 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_JavaClassReport.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.report 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | 4 | 5 | 6 | #def title 7 | <% 8 | change = getattr(self, "change") 9 | nom = change.get_ldata().pretty_this() 10 | %> 11 | <%= escape("%s %s" % (change.__class__.__name__ , nom.split(".")[-1])) %> 12 | #end def 13 | 14 | 15 | 16 | ## 17 | ## The end. 18 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_MethodAdded.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | 4 | 5 | 6 | #block description 7 | <% 8 | change = getattr(self, "change") 9 | info = change.get_rdata() 10 | a = info.get_name() 11 | b = ", ".join(info.pretty_arg_types()) 12 | c = info.pretty_type() 13 | %> 14 |

<%= escape("%s(%s):%s" % (a, b, c)) %>

15 |
Method Added
22 |
23 | $method_table($change.get_rdata()) 24 |
25 | 26 | #end block 27 | 28 | 29 | 30 | #def method_table(info) 31 | 32 | $row("Method Name", info.get_name()) 33 | $row("Return Type", info.pretty_type()) 34 | $row("Argument Types", "(%s)" % ", ".join(info.pretty_arg_types())) 35 | $row("Method Flags", "0x%04x: %s" % 36 | (info.access_flags, " ".join(info.pretty_access_flags()))) 37 | 38 | #if info.get_signature() 39 | $row("Generics Signature", info.get_signature()) 40 | #end if 41 | 42 | #if info.get_exceptions() 43 | $row("Exceptions", ", ".join(info.pretty_exceptions())) 44 | #end if 45 | 46 | #if not info.get_code() 47 | $row("Abstract", "True") 48 | #end if 49 | 50 | #if info.is_deprecated() 51 | $row("Deprecated", "True") 52 | #end if 53 | 54 |
55 | #end def 56 | 57 | 58 | 59 | #def row(label, data) 60 | 61 | $label 62 | <%= escape(data) %> 63 | 64 | #end def 65 | 66 | 67 | 68 | ## 69 | ## The end. 70 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_MethodChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | #from javatools.change import collect_by_typename 3 | #from javatools.cheetah import xml_entity_escape as escape 4 | 5 | 6 | 7 | #block description 8 | <% 9 | change = getattr(self, "change") 10 | ldata = change.get_ldata() 11 | a = ldata.get_name() 12 | b = ", ".join(ldata.pretty_arg_types()) 13 | c = ldata.pretty_type() 14 | %> 15 |

<%= escape("%s(%s):%s" % (a, b, c)) %>

16 | #end block 17 | 18 | 19 | 20 | #block details 21 | <% 22 | change = getattr(self, "change") 23 | data = collect_by_typename(change.collect()) 24 | %> 25 | 26 |
27 |
28 | 29 | 30 | $sub_name(data.pop("MethodNameChange")[0]) 31 | $sub_type(data.pop("MethodTypeChange")[0]) 32 | $sub_args(data.pop("MethodParametersChange")[0]) 33 | $sub_flags(data.pop("MethodAccessflagsChange")[0]) 34 | $sub_signature(data.pop("MethodSignatureChange")[0]) 35 | $sub_throws(data.pop("MethodExceptionsChange")[0]) 36 | $sub_abstract(data.pop("MethodAbstractChange")[0]) 37 | $sub_deprecation(data.pop("MethodDeprecationChange")[0]) 38 |
39 | 40 |
41 |
42 | #end block 43 | 44 | 45 | 46 | #block collect 47 | <% 48 | change = getattr(self, "change") 49 | data = collect_by_typename(change.collect()) 50 | %> 51 |
52 | $render_change(data.pop("MethodAnnotationsChange")[0]) 53 | $render_change(data.pop("MethodInvisibleAnnotationsChange")[0]) 54 | $render_change(data.pop("MethodCodeChange")[0]) 55 |
56 | #end block 57 | 58 | 59 | 60 | #def sub_name(subch) 61 | #set label = "Method Name" 62 | #if subch.is_change() 63 | 64 | $label 65 | <%= escape(subch.pretty_ldata()) %> 66 | 67 | 68 | <%= escape(subch.pretty_rdata()) %> 69 | 70 | #else 71 | 72 | $label 73 | <%= escape(subch.pretty_ldata()) %> 74 | 75 | #end if 76 | #end def 77 | 78 | 79 | 80 | #def sub_type(subch) 81 | #set label = "Return Type" 82 | #if subch.is_change() 83 | 84 | $label 85 | <%= subch.pretty_ldata() %> 86 | 87 | 88 | <%= subch.pretty_rdata() %> 89 | 90 | #else 91 | 92 | $label 93 | <%= subch.pretty_ldata() %> 94 | 95 | #end if 96 | #end def 97 | 98 | 99 | 100 | #def sub_args(subch) 101 | #set label = "Argument Types" 102 | #if subch.is_change() 103 | 104 | $label 105 | (<%= ", ".join(subch.pretty_ldata()) %>) 106 | 107 | 108 | (<%= ", ".join(subch.pretty_rdata()) %>) 109 | 110 | #else 111 | 112 | $label 113 | (<%= ", ".join(subch.pretty_ldata()) %>) 114 | 115 | #end if 116 | #end def 117 | 118 | 119 | 120 | #def sub_flags(subch) 121 | #set label = "Method Flags" 122 | #if subch.is_change() 123 | 124 | $label 125 | <%= "0x%04x" % subch.get_ldata() %>: 126 | <%= " ".join(subch.pretty_ldata()) %> 127 | 128 | 129 | 130 | <%= "0x%04x" % subch.get_rdata() %>: 131 | <%= " ".join(subch.pretty_rdata()) %> 132 | 133 | #else 134 | 135 | $label 136 | <%= "0x%04x" % subch.get_ldata() %>: 137 | <%= " ".join(subch.pretty_ldata()) %> 138 | 139 | #end if 140 | #end def 141 | 142 | 143 | 144 | #def sub_signature(subch) 145 | #set label = "Generics Signature" 146 | #if subch.is_change() 147 | 148 | $label 149 | <%= escape(subch.pretty_ldata() or "(None)") %> 150 | 151 | 152 | 153 | <%= escape(subch.pretty_rdata() or "(None)") %> 154 | 155 | #elif subch.get_ldata() 156 | 157 | $label 158 | <%= escape(subch.pretty_ldata()) %> 159 | 160 | #end if 161 | #end def 162 | 163 | 164 | 165 | #def sub_throws(subch) 166 | #set label = "Exceptions" 167 | #if subch.is_change() 168 | 169 | $label 170 | (<%= ", ".join(subch.pretty_ldata()) %>) 171 | 172 | 173 | (<%= ", ".join(subch.pretty_rdata()) %>) 174 | 175 | #elif subch.get_ldata() 176 | 177 | $label 178 | (<%= ", ".join(subch.pretty_ldata()) %>) 179 | 180 | #end if 181 | #end def 182 | 183 | 184 | 185 | #def sub_abstract(subch) 186 | #set label = "Abstract" 187 | #if subch.is_change() 188 | 189 | $label 190 | <%= subch.pretty_ldata() %> 191 | 192 | 193 | <%= subch.pretty_rdata() %> 194 | 195 | #elif subch.get_ldata() 196 | 197 | $label 198 | <%= subch.pretty_ldata() %> 199 | 200 | #end if 201 | #end def 202 | 203 | 204 | 205 | #def sub_deprecation(subch) 206 | #set label = "Deprecated" 207 | #if subch.is_change() 208 | 209 | $label 210 | <%= subch.pretty_ldata() %> 211 | 212 | 213 | <%= subch.pretty_rdata() %> 214 | 215 | #elif subch.get_ldata() 216 | 217 | $label 218 | <%= subch.pretty_ldata() %> 219 | 220 | #end if 221 | #end def 222 | 223 | 224 | 225 | ## 226 | ## The end. 227 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_MethodCodeChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_SuperChange 2 | #from javatools.classdiff import merge_code 3 | #from javatools.opcodes import has_const_arg, get_opname_by_code 4 | #from javatools.cheetah import xml_entity_escape as escape 5 | #from six.moves import zip_longest 6 | 7 | 8 | #block details_changed 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <% 30 | change = getattr(self, "change") 31 | ldata = change.get_ldata() 32 | rdata = change.get_rdata() 33 | merged = merge_code(ldata, rdata) 34 | %> 35 | #for rel_line, (left, right) in sorted(merged.items()) 36 | <% 37 | first = True 38 | last = False 39 | 40 | left_line = None 41 | left_dis = tuple() 42 | if left is not None: 43 | left_line, left_dis = left 44 | 45 | right_line = None 46 | right_dis = tuple() 47 | if right is not None: 48 | right_line, right_dis = right 49 | 50 | rowspan = max(len(left_dis), len(right_dis)) 51 | lastrow = (rowspan - min(len(left_dis), len(right_dis))) 52 | %> 53 | #for l_instruction, r_instruction in zip_longest(left_dis, right_dis) 54 | 55 | 56 | #if first 57 | 58 | #end if 59 | 60 | #if l_instruction is not None 61 | #if first 62 | 63 | #end if 64 | <% l_offset, l_code, l_args = l_instruction %> 65 | 66 | 67 | 69 | #else 70 | #if not last 71 | #if first 72 | 73 | #else 74 | 75 | #end if 76 | <% last = True %> 77 | #end if 78 | #end if 79 | 80 | #if r_instruction is not None 81 | #if first 82 | 83 | #end if 84 | <% r_offset, r_code, r_args = r_instruction %> 85 | 86 | 87 | 89 | #else 90 | #if not last 91 | #if first 92 | 93 | #else 94 | 95 | #end if 96 | <% last = True %> 97 | #end if 98 | #end if 99 | 100 | <% first = False %> 101 | #end for 102 | #end for 103 |
RelativeOriginalModified
linelineoffsetopcodeargslineoffsetopcodeargs
<%= rel_line %><%= left[0] %><%= l_offset %><%= get_opname_by_code(l_code) %><%= ((has_const_arg(l_code) and ("#%s" % l_args[0])) 68 | or ", ".join(map(str, l_args))) %><%= right[0] %><%= r_offset %><%= get_opname_by_code(r_code) %><%= ((has_const_arg(r_code) and ("#%s" % r_args[0])) 88 | or ", ".join(map(str, r_args))) %>
104 | #end block 105 | 106 | 107 | 108 | #block details_unchanged 109 | <% 110 | change = getattr(self, "change") 111 | ldata = change.get_ldata() 112 | %> 113 | #if ldata is None 114 | 115 | #else 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | #for abs_line, rel_line, dis in ldata.iter_code_by_lines() 131 | <% 132 | rowspan = len(dis) 133 | first = True 134 | %> 135 | #for offset, code, args in dis 136 | 137 | #if first 138 | 139 | 140 | #end if 141 | 142 | 143 | 145 | 146 | <% 147 | first = False 148 | %> 149 | #end for 150 | #end for 151 |
RelativeMethod Code
linelineoffsetopcodeargs
<%= rel_line %><%= abs_line %><%= offset %><%= get_opname_by_code(code) %><%= ((has_const_arg(code) and ("#%s" % args[0])) 144 | or ", ".join(map(str, args))) %>
152 | #end if 153 | #end block 154 | 155 | 156 | 157 | #block details 158 |
159 |
160 | <% 161 | change = getattr(self, "change") 162 | lcode = (change.ldata and change.ldata.code) or tuple() 163 | rcode = (change.rdata and change.rdata.code) or tuple() 164 | %> 165 | #if change.is_change() or (lcode != rcode) 166 | $details_changed 167 | #else 168 | $details_unchanged 169 | #end if 170 |
171 |
172 | #end block 173 | 174 | 175 | 176 | #block collect 177 | #end block 178 | 179 | 180 | 181 | ## 182 | ## The end. 183 | -------------------------------------------------------------------------------- /javatools/cheetah/classdiff_MethodRemoved.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | 4 | 5 | 6 | #block description 7 | <% 8 | change = getattr(self, "change") 9 | info = change.get_ldata() 10 | a = info.get_name() 11 | b = ", ".join(info.pretty_arg_types()) 12 | c = info.pretty_type() 13 | %> 14 |

<%= escape("%s(%s):%s" % (a, b, c)) %>

15 |
Method Removed
16 | #end block 17 | 18 | 19 | 20 | #block details 21 |
22 |
23 | $method_table($change.get_ldata()) 24 |
25 |
26 | #end block 27 | 28 | 29 | 30 | #def method_table(info) 31 | 32 | $row("Method Name", info.get_name()) 33 | $row("Return Type", info.pretty_type()) 34 | $row("Argument Types", "(%s)" % ", ".join(info.pretty_arg_types())) 35 | $row("Method Flags", "0x%04x: %s" % 36 | (info.access_flags, " ".join(info.pretty_access_flags()))) 37 | 38 | #if info.get_signature() 39 | $row("Generics Signature", info.get_signature()) 40 | #end if 41 | 42 | #if info.get_exceptions() 43 | $row("Exceptions", ", ".join(info.pretty_exceptions())) 44 | #end if 45 | 46 | #if not info.get_code() 47 | $row("Abstract", "True") 48 | #end if 49 | 50 | #if info.is_deprecated() 51 | $row("Deprecated", "True") 52 | #end if 53 | 54 |
55 | #end def 56 | 57 | 58 | 59 | #def row(label, data) 60 | 61 | $label 62 | <%= escape(data) %> 63 | 64 | #end def 65 | 66 | 67 | 68 | ## 69 | ## The end. 70 | -------------------------------------------------------------------------------- /javatools/cheetah/data/report.css: -------------------------------------------------------------------------------- 1 | 2 | div { 3 | clear: both; 4 | margin: 0 0 0 1em; 5 | padding: 0.2em 0; 6 | font: 10pt sans; 7 | } 8 | 9 | 10 | .Change .description { 11 | margin: 0; 12 | font: 12pt sans; 13 | } 14 | 15 | 16 | .is_unchanged { 17 | color: green; 18 | } 19 | 20 | 21 | .is_changed { 22 | color: red; 23 | } 24 | 25 | 26 | .is_ignored { 27 | color: orange; 28 | } 29 | 30 | 31 | .vertical { 32 | clear: none; 33 | float: left; 34 | } 35 | 36 | 37 | .vertical.ldata, .vertical.rdata { 38 | width: auto; 39 | min-width: 20em; 40 | max-width: 47%; 41 | padding: 0 2em 1em 0; 42 | margin: 0; 43 | } 44 | 45 | 46 | .lrdata { 47 | min-width: 20em; 48 | padding: 0 2em 1em 0; 49 | margin: 0 2em; 50 | } 51 | 52 | 53 | table { 54 | border-collapse: collapse; 55 | color: black; 56 | } 57 | 58 | 59 | td { 60 | vertical-align: top; 61 | border: thin solid grey; 62 | padding: 0.2em 1em; 63 | } 64 | 65 | 66 | td.const-value { 67 | /* max-width: 24em; */ 68 | word-wrap: break-word; 69 | font-family: "Verdana", "monospace"; 70 | } 71 | 72 | 73 | th { 74 | color: black; 75 | vertical-align: top; 76 | padding: 0 1em; 77 | } 78 | 79 | 80 | table.left-headers th { 81 | text-align: right; 82 | } 83 | 84 | 85 | ul.breadcrumbs li { 86 | border: thin solid grey; 87 | display: inline; 88 | list-style-type: none; 89 | padding: 0 0.5em; 90 | margin: 0; 91 | } 92 | 93 | 94 | ul.breadcrumbs a { 95 | text-decoration: none; 96 | } 97 | 98 | 99 | /* The end. */ 100 | -------------------------------------------------------------------------------- /javatools/cheetah/data/report.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | */ 5 | 6 | 7 | // details sections expand/collapse 8 | 9 | // keybindings for pages 10 | 11 | // 12 | 13 | 14 | /* The end. */ 15 | -------------------------------------------------------------------------------- /javatools/cheetah/distdiff_DistClassChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.distdiff_DistContentChange 2 | 3 | 4 | ## 5 | ## The end. 6 | -------------------------------------------------------------------------------- /javatools/cheetah/distdiff_DistContentChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | 3 | #block description 4 | #from javatools.cheetah import xml_entity_escape as escape 5 | $escape($change.entry) 6 | #end block 7 | 8 | ## 9 | ## The end. 10 | -------------------------------------------------------------------------------- /javatools/cheetah/distdiff_DistReport.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.report 2 | 3 | 4 | ## render a collection of changes that are all of the same type 5 | #def render_by_class(changes, label) 6 | #if changes 7 | 8 |
9 |

$label

10 | 11 | <% 12 | chm = dict((ch.entry,ch) for ch in changes) 13 | %> 14 | 15 | #for entry in sorted(chm.keys()) 16 | $render_change(chm[entry]) 17 | #end for 18 | 19 |
20 | #end if 21 | #end def 22 | 23 | 24 | ## the overridden details block 25 | #block details 26 | 27 | #import javatools.distdiff 28 | #import javatools.change 29 | 30 | ## collect the changes into buckets by type 31 | <% 32 | change = getattr(self, "change") 33 | changemap = javatools.change.collect_by_type(change.collect()) 34 | changeorder = ( 35 | javatools.distdiff.DistClassAdded, 36 | javatools.distdiff.DistClassRemoved, 37 | javatools.distdiff.DistClassChange, 38 | javatools.distdiff.DistJarAdded, 39 | javatools.distdiff.DistJarRemoved, 40 | javatools.distdiff.DistJarChange, 41 | javatools.distdiff.DistJarChange, 42 | javatools.distdiff.DistTextChange, 43 | javatools.distdiff.DistManifestChange, 44 | javatools.distdiff.DistContentAdded, 45 | javatools.distdiff.DistContentRemoved, 46 | javatools.distdiff.DistContentChange, 47 | ) 48 | 49 | ## gather SquashedChange instances under a more appropriate heading 50 | for sq in changemap.pop(javatools.change.SquashedChange, ()): 51 | oc = sq.origclass 52 | if oc is javatools.distdiff.DistJarReport: 53 | oc = javatools.distdiff.DistJarChange 54 | elif oc is javatools.distdiff.DistClassReport: 55 | oc = javatools.distdiff.DistClassChange 56 | sqm = changemap.setdefault(oc, []) 57 | sqm.append(sq) 58 | %> 59 | 60 | ## print the above types gathered in order 61 | #for ct in changeorder 62 | $render_by_class(changemap.pop(ct, tuple()), ct.label) 63 | #end for 64 | 65 | ## print the remaining types 66 | #for ct, changes in changemap.items() 67 | $render_by_class(changes, ct.label) 68 | #end for 69 | 70 | #end block 71 | 72 | 73 | ## 74 | ## The end. 75 | -------------------------------------------------------------------------------- /javatools/cheetah/jardiff_JarClassChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.jardiff_JarContentChange 2 | 3 | 4 | ## 5 | ## The end. 6 | -------------------------------------------------------------------------------- /javatools/cheetah/jardiff_JarContentChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | 4 | 5 | #block description 6 | $escape($change.entry) 7 | #end block 8 | 9 | 10 | ## 11 | ## The end. 12 | -------------------------------------------------------------------------------- /javatools/cheetah/jardiff_JarContentsReport.tmpl: -------------------------------------------------------------------------------- 1 | ## render a collection of changes that are all of the same type 2 | #def render_by_class(changes, label) 3 | #if changes 4 | 5 |
6 |

$label

7 | 8 | <% 9 | chm = dict((ch.entry,ch) for ch in changes) 10 | %> 11 | 12 | #for entry in sorted(chm.keys()) 13 | $render_change(chm[entry]) 14 | #end for 15 | 16 |
17 | #end if 18 | #end def 19 | 20 | 21 | ## the overridden details block 22 | #block details 23 | 24 |
25 | 26 | <% 27 | import javatools.jardiff 28 | import javatools.change 29 | 30 | ## collect the changes into buckets by type 31 | change = getattr(self, "change") 32 | changemap = javatools.change.collect_by_type(change.collect()) 33 | changeorder = ( 34 | javatools.jardiff.JarManifestChange, 35 | javatools.jardiff.JarSignatureFileAdded, 36 | javatools.jardiff.JarSignatureFileRemoved, 37 | javatools.jardiff.JarSignatureFileChange, 38 | javatools.jardiff.JarSignatureBlockFileAdded, 39 | javatools.jardiff.JarSignatureBlockFileRemoved, 40 | javatools.jardiff.JarSignatureBlockFileChange, 41 | javatools.jardiff.JarContentAdded, 42 | javatools.jardiff.JarContentRemoved, 43 | javatools.jardiff.JarContentChange, 44 | javatools.jardiff.JarClassAdded, 45 | javatools.jardiff.JarClassRemoved, 46 | javatools.jardiff.JarClassChange, 47 | ) 48 | 49 | ## gather SquashedChange instances under a more appropriate heading 50 | for sq in changemap.pop(javatools.change.SquashedChange, ()): 51 | oc = sq.origclass 52 | if oc is javatools.jardiff.JarClassReport: 53 | oc = javatools.jardiff.JarClassChange 54 | sqm = changemap.setdefault(oc, []) 55 | sqm.append(sq) 56 | %> 57 | 58 | ## print the above types gathered in order 59 | #for ct in changeorder 60 | $render_by_class(changemap.pop(ct, ()), ct.label) 61 | #end for 62 | 63 | ## print the remaining types 64 | #for ct,changes in changemap.items() 65 | $render_by_class(changes, ct.label) 66 | #end for 67 | 68 |
69 | 70 | #end block 71 | 72 | 73 | ## 74 | ## The end. 75 | -------------------------------------------------------------------------------- /javatools/cheetah/jardiff_JarReport.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.report 2 | 3 | 4 | ## 5 | ## The end. 6 | -------------------------------------------------------------------------------- /javatools/cheetah/manifest_ManifestChange.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_Change 2 | 3 | 4 | #block description 5 |
The manifest has changed between Jars
6 | #end block 7 | 8 | 9 | ## 10 | ## The end. 11 | -------------------------------------------------------------------------------- /javatools/cheetah/report.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | #def title 10 | $change.__class__.__name__ 11 | #end def 12 | 13 | 14 | 15 | 16 | 17 | #block head_title 18 | $title 19 | #end block 20 | 21 | 22 | #block head_meta 23 | #end block 24 | 25 | 26 | #block head_stylesheets 27 | #for ss in $stylesheets 28 | 29 | #end for 30 | #end block 31 | 32 | 33 | #block head_javascripts 34 | #if not getattr($options, "html_no_jquery", False) 35 | 36 | #end if 37 | #for js in $javascripts 38 | 39 | #end for 40 | #end block 41 | 42 | 43 | #block head_extra 44 | #end block 45 | 46 | 47 | 48 | 49 | 50 | #block body 51 | 52 | 53 | 54 | #block body_heading 55 |
56 | 57 | 58 | #block body_breadcrumb 59 | #from os.path import join 60 | 66 | #end block 67 | 68 | 69 |

$title

70 |
71 | #end block 72 | 73 | 74 | #block into 75 |
76 |
77 | #end block 78 | 79 | 80 | #block details 81 |
82 | #for $child in $change.collect() 83 | $render_change($child) 84 | #end for 85 |
86 | #end block 87 | 88 | 89 | #block outro 90 |
91 |
92 | #end block 93 | 94 | 95 | 96 | #end block 97 | 98 | 99 | 100 | 101 | 102 | ## 103 | ## The end. 104 | -------------------------------------------------------------------------------- /javatools/cheetah/setuptools.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | Replacement setuptools/distutils build_py command which also 18 | compiles Cheetah templates to Python 19 | 20 | author: Christopher O'Brien 21 | license: LGPL v.3 22 | """ 23 | 24 | 25 | from distutils.core import Command 26 | from distutils.util import newer 27 | from distutils.command.build_py import build_py 28 | from glob import glob 29 | from os import makedirs 30 | from os.path import basename, exists, join, splitext 31 | 32 | 33 | DEFAULT_CONFIG = "extras/cheetah.cfg" 34 | 35 | 36 | class cheetah_cmd(Command): 37 | """ 38 | command that compiles Cheetah template files into Python 39 | """ 40 | 41 | # TODO: move the act of actually compiling .tmpl -> .py into this 42 | # command, and simply make the build_py command depend on this one 43 | 44 | pass 45 | 46 | 47 | class cheetah_build_py_cmd(build_py): 48 | """ 49 | build_py command with some special handling for Cheetah template 50 | files. Takes tmpl from package source directories and compiles 51 | them for distribution. This allows me to write tmpl files in the 52 | src dir of my project, and have them get compiled to py/pyc/pyo 53 | files during the build process. 54 | """ 55 | 56 | # Note: it's important to override build_py rather than to add a 57 | # sub-command to build. The build command doesn't collate the 58 | # get_outputs of its sub-commands, and install specifically looks 59 | # for build_py and build_ext for the list of files to install. 60 | 61 | # Update: now that I've switched from distutils to setuptools, it 62 | # may be possible to put this into a subcommand instead. Have to 63 | # investigate. 64 | 65 | def find_package_templates(self, package, package_dir): 66 | # template files will be located under src, and will end in .tmpl 67 | 68 | self.check_package(package, package_dir) 69 | template_files = glob(join(package_dir, "*.tmpl")) 70 | templates = [] 71 | 72 | for f in template_files: 73 | template = splitext(basename(f))[0] 74 | templates.append((package, template, f)) 75 | return templates 76 | 77 | 78 | def build_package_templates(self): 79 | for package in self.packages: 80 | package_dir = self.get_package_dir(package) 81 | templates = self.find_package_templates(package, package_dir) 82 | 83 | for package_, template, template_file in templates: 84 | assert package == package_ 85 | self.build_template(template, template_file, package) 86 | 87 | 88 | def build_template(self, template, template_file, package): 89 | """ 90 | Compile the cheetah template in src into a python file in build 91 | """ 92 | 93 | try: 94 | from Cheetah.Compiler import Compiler 95 | except ImportError: 96 | self.announce("unable to import Cheetah.Compiler, build failed") 97 | raise 98 | else: 99 | comp = Compiler(file=template_file, moduleName=template) 100 | 101 | # load configuration if it exists 102 | conf_fn = DEFAULT_CONFIG 103 | if exists(conf_fn): 104 | with open(conf_fn, "rt") as config: 105 | comp.updateSettingsFromConfigFileObj(config) 106 | 107 | # and just why can't I configure these? 108 | comp.setShBang("") 109 | comp.addModuleHeader("pylint: disable=C,W,R,F") 110 | 111 | outfd = join(self.build_lib, *package.split(".")) 112 | outfn = join(outfd, template + ".py") 113 | 114 | if not exists(outfd): 115 | makedirs(outfd) 116 | 117 | if newer(template_file, outfn): 118 | self.announce("compiling %s -> %s" % (template_file, outfd), 2) 119 | with open(outfn, "w") as output: 120 | output.write(str(comp)) 121 | 122 | 123 | def get_template_outputs(self, include_bytecode=1): 124 | built = list() 125 | 126 | for package in self.packages: 127 | package_dir = self.get_package_dir(package) 128 | templates = self.find_package_templates(package, package_dir) 129 | for _, template, _ in templates: 130 | outfd = join(self.build_lib, *package.split(".")) 131 | outfn = join(outfd, template + ".py") 132 | 133 | built.append(outfn) 134 | 135 | if include_bytecode: 136 | if self.compile: 137 | built.append(outfn + "c") 138 | if self.optimize > 0: 139 | built.append(outfn + "o") 140 | 141 | return built 142 | 143 | 144 | def get_outputs(self, include_bytecode=1): 145 | # Overridden to append our compiled templates in addition to 146 | # the normal build outputs. 147 | 148 | outputs = build_py.get_outputs(self, include_bytecode) 149 | outputs.extend(self.get_template_outputs(include_bytecode)) 150 | 151 | return outputs 152 | 153 | 154 | def run(self): 155 | if self.packages: 156 | self.build_package_templates() 157 | 158 | # old-style class, can't use super 159 | build_py.run(self) 160 | 161 | 162 | # 163 | # The end. 164 | -------------------------------------------------------------------------------- /javatools/cheetah/subreport.tmpl: -------------------------------------------------------------------------------- 1 | #extends javatools.cheetah.change_SuperChange 2 | #from javatools.cheetah import xml_entity_escape as escape 3 | 4 | #block description 5 |

$change.label

6 | 7 |
8 | $escape($change.get_description()) 9 |
10 | #end block 11 | 12 | 13 | ## 14 | ## The end. 15 | -------------------------------------------------------------------------------- /javatools/crypto.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | Cryptography-related functions for handling JAR signature block files. 18 | 19 | :author: Konstantin Shemyak 20 | :license: LGPL v.3 21 | """ 22 | 23 | 24 | from functools import wraps 25 | 26 | 27 | try: 28 | from M2Crypto import SMIME, X509, BIO, RSA, DSA, EC, m2 29 | except ImportError: 30 | __ENABLED = False 31 | else: 32 | __ENABLED = True 33 | 34 | 35 | class CryptoDisabled(Exception): 36 | """ 37 | cryptography is disabled due to lack of M2Crypto 38 | """ 39 | 40 | pass 41 | 42 | 43 | class CannotFindKeyTypeError(Exception): 44 | """ 45 | Failed to determine the type of the private key. 46 | """ 47 | 48 | pass 49 | 50 | 51 | class SignatureBlockVerificationError(Exception): 52 | """ 53 | The Signature Block File verification failed. 54 | """ 55 | 56 | pass 57 | 58 | 59 | def crypto_enabled(): 60 | return __ENABLED 61 | 62 | 63 | def requires_crypto(fn): 64 | @wraps(fn) 65 | def wrapper(*args, **kwds): 66 | if not crypto_enabled(): 67 | raise CryptoDisabled("javatools API %s requires M2Crypto" % 68 | fn.__name__) 69 | return fn(*args, **kwds) 70 | return wrapper 71 | 72 | 73 | @requires_crypto 74 | def private_key_type(key_file): 75 | """ 76 | Determines type of the private key: RSA, DSA, EC. 77 | 78 | :param key_file: file path 79 | :type key_file: str 80 | :return: one of "RSA", "DSA" or "EC" 81 | :except CannotFindKeyTypeError 82 | """ 83 | 84 | keytypes = (("RSA", RSA), ("DSA", DSA), ("EC", EC)) 85 | 86 | for key, ktype in keytypes: 87 | try: 88 | ktype.load_key(key_file) 89 | except (RSA.RSAError, DSA.DSAError, ValueError): 90 | continue 91 | else: 92 | return key 93 | else: 94 | raise CannotFindKeyTypeError() 95 | 96 | 97 | @requires_crypto 98 | def create_signature_block(openssl_digest, certificate, private_key, 99 | extra_certs, data): 100 | 101 | """ 102 | Produces a signature block for the data. 103 | 104 | Reference 105 | --------- 106 | http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures 107 | 108 | Note: Oracle does not specify the content of the "signature 109 | file block", friendly saying that "These are binary files 110 | not intended to be interpreted by humans". 111 | 112 | :param openssl_digest: alrogithm known to OpenSSL used to digest the data 113 | :type openssl_digest: str 114 | :param certificate: filename of the certificate file (PEM format) 115 | :type certificate: str 116 | :param private_key:filename of private key used to sign (PEM format) 117 | :type private_key: str 118 | :param extra_certs: additional certificates to embed into the signature (PEM format) 119 | :type extra_certs: array of filenames 120 | :param data: the content to be signed 121 | :type data: bytes 122 | :returns: content of the signature block file as produced by jarsigner 123 | :rtype: bytes 124 | """ # noqa 125 | 126 | smime = SMIME.SMIME() 127 | with BIO.openfile(private_key) as k, BIO.openfile(certificate) as c: 128 | smime.load_key_bio(k, c) 129 | 130 | if extra_certs is not None: 131 | # Could we use just X509.new_stack_from_der() instead? 132 | stack = X509.X509_Stack() 133 | for cert in extra_certs: 134 | stack.push(X509.load_cert(cert)) 135 | smime.set_x509_stack(stack) 136 | 137 | pkcs7 = smime.sign(BIO.MemoryBuffer(data), 138 | algo=openssl_digest, 139 | flags=(SMIME.PKCS7_BINARY | 140 | SMIME.PKCS7_DETACHED | 141 | SMIME.PKCS7_NOATTR)) 142 | tmp = BIO.MemoryBuffer() 143 | pkcs7.write_der(tmp) 144 | return tmp.read() 145 | 146 | 147 | @requires_crypto 148 | def ignore_missing_email_protection_eku_cb(ok, ctx): 149 | """ 150 | For verifying PKCS7 signature, m2Crypto uses OpenSSL's PKCS7_verify(). 151 | The latter requires that ExtendedKeyUsage extension, if present, 152 | contains 'emailProtection' OID. (Is it because S/MIME is/was the 153 | primary use case for PKCS7?) 154 | We do not want to fail the verification in this case. At present, 155 | M2Crypto lacks possibility of removing or modifying an existing 156 | extension. Let's assign a custom verification callback. 157 | """ 158 | # The error we want to ignore is indicated by X509_V_ERR_INVALID_PURPOSE. 159 | err = ctx.get_error() 160 | if err != m2.X509_V_ERR_INVALID_PURPOSE: 161 | return ok 162 | 163 | # PKCS7_verify() has this requriement only for the signing certificate. 164 | # Do not modify the behavior for certificates upper in the chain. 165 | if ctx.get_error_depth() > 0: 166 | return ok 167 | 168 | # There is another cause of ERR_INVALID_PURPOSE: incompatible keyUsage. 169 | # Do not modify the default behavior in this case. 170 | cert = ctx.get_current_cert() 171 | try: 172 | key_usage = cert.get_ext('keyUsage').get_value() 173 | if 'digitalSignature' not in key_usage \ 174 | and 'nonRepudiation' not in key_usage: 175 | return ok 176 | except LookupError: 177 | pass 178 | 179 | # Here, keyUsage is either absent, or contains the needed bit(s). 180 | # So ERR_INVALID_PURPOSE is caused by EKU not containing 'emailProtection'. 181 | # Ignore this error. 182 | return 1 183 | 184 | 185 | @requires_crypto 186 | def verify_signature_block(certificate_file, content, signature): 187 | """ 188 | Verifies the 'signature' over the 'content', trusting the 189 | 'certificate'. 190 | 191 | :param certificate_file: the trusted certificate (PEM format) 192 | :type certificate_file: str 193 | :param content: The signature should match this content 194 | :type content: str 195 | :param signature: data (DER format) subject to check 196 | :type signature: str 197 | :return None if the signature validates. 198 | :exception SignatureBlockVerificationError 199 | """ 200 | 201 | sig_bio = BIO.MemoryBuffer(signature) 202 | pkcs7 = SMIME.PKCS7(m2.pkcs7_read_bio_der(sig_bio._ptr()), 1) 203 | signers_cert_stack = pkcs7.get0_signers(X509.X509_Stack()) 204 | trusted_cert_store = X509.X509_Store() 205 | trusted_cert_store.set_verify_cb(ignore_missing_email_protection_eku_cb) 206 | trusted_cert_store.load_info(certificate_file) 207 | smime = SMIME.SMIME() 208 | smime.set_x509_stack(signers_cert_stack) 209 | smime.set_x509_store(trusted_cert_store) 210 | data_bio = BIO.MemoryBuffer(content) 211 | 212 | try: 213 | smime.verify(pkcs7, data_bio) 214 | except SMIME.PKCS7_Error as message: 215 | raise SignatureBlockVerificationError(message) 216 | else: 217 | return None 218 | 219 | 220 | # 221 | # The end. 222 | -------------------------------------------------------------------------------- /javatools/dirutils.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | Utility module for discovering the differences between two directory 18 | trees 19 | 20 | :author: Christopher O'Brien 21 | :license: LGPL 22 | """ 23 | 24 | 25 | from filecmp import dircmp 26 | from fnmatch import fnmatch 27 | from os import makedirs, walk 28 | from os.path import exists, isdir, join, relpath 29 | from shutil import copy 30 | 31 | 32 | LEFT = "left only" 33 | RIGHT = "right only" 34 | DIFF = "changed" 35 | SAME = "same" 36 | BOTH = SAME # meh, synonyms 37 | 38 | 39 | def fnmatches(entry, *pattern_list): 40 | """ 41 | returns true if entry matches any of the glob patterns, false 42 | otherwise 43 | """ 44 | 45 | for pattern in pattern_list: 46 | if pattern and fnmatch(entry, pattern): 47 | return True 48 | return False 49 | 50 | 51 | def makedirsp(dirname): 52 | """ 53 | create dirname if it doesn't exist 54 | """ 55 | 56 | if dirname and not exists(dirname): 57 | makedirs(dirname) 58 | 59 | 60 | def copydir(orig, dest): 61 | """ 62 | copies directory orig to dest. Returns a list of tuples of 63 | relative filenames which were copied from orig to dest 64 | """ 65 | 66 | copied = list() 67 | 68 | makedirsp(dest) 69 | 70 | for root, dirs, files in walk(orig): 71 | for d in dirs: 72 | # ensure directories exist 73 | makedirsp(join(dest, d)) 74 | 75 | for f in files: 76 | root_f = join(root, f) 77 | dest_f = join(dest, relpath(root_f, orig)) 78 | copy(root_f, dest_f) 79 | copied.append((root_f, dest_f)) 80 | 81 | return copied 82 | 83 | 84 | def compare(left, right): 85 | """ 86 | generator emiting pairs indicating the contents of the left and 87 | right directories. The pairs are in the form of (difference, 88 | filename) where difference is one of the LEFT, RIGHT, DIFF, or 89 | BOTH constants. This generator recursively walks both trees. 90 | """ 91 | 92 | dc = dircmp(left, right, ignore=[]) 93 | return _gen_from_dircmp(dc, left, right) 94 | 95 | 96 | def _gen_from_dircmp(dc, lpath, rpath): 97 | """ 98 | do the work of comparing the dircmp 99 | """ 100 | 101 | left_only = dc.left_only 102 | left_only.sort() 103 | 104 | for f in left_only: 105 | fp = join(dc.left, f) 106 | if isdir(fp): 107 | for r, _ds, fs in walk(fp): 108 | r = relpath(r, lpath) 109 | for f in fs: 110 | yield (LEFT, join(r, f)) 111 | else: 112 | yield (LEFT, relpath(fp, lpath)) 113 | 114 | right_only = dc.right_only 115 | right_only.sort() 116 | 117 | for f in right_only: 118 | fp = join(dc.right, f) 119 | if isdir(fp): 120 | for r, _ds, fs in walk(fp): 121 | r = relpath(r, rpath) 122 | for f in fs: 123 | yield (RIGHT, join(r, f)) 124 | else: 125 | yield (RIGHT, relpath(fp, rpath)) 126 | 127 | diff_files = dc.diff_files 128 | diff_files.sort() 129 | 130 | for f in diff_files: 131 | yield (DIFF, join(relpath(dc.right, rpath), f)) 132 | 133 | same_files = dc.same_files 134 | same_files.sort() 135 | 136 | for f in same_files: 137 | yield (BOTH, join(relpath(dc.left, lpath), f)) 138 | 139 | subdirs = dc.subdirs.values() 140 | subdirs = sorted(subdirs) 141 | for sub in subdirs: 142 | for event in _gen_from_dircmp(sub, lpath, rpath): 143 | yield event 144 | 145 | 146 | def collect_compare(left, right): 147 | """ 148 | returns a tuple of four lists describing the file paths that have 149 | been (in order) added, removed, altered, or left the same 150 | """ 151 | 152 | return collect_compare_into(left, right, [], [], [], []) 153 | 154 | 155 | def collect_compare_into(left, right, added, removed, altered, same): 156 | """ 157 | collect the results of compare into the given lists (or None if 158 | you do not wish to collect results of that type. Returns a tuple 159 | of (added, removed, altered, same) 160 | """ 161 | 162 | for event, filename in compare(left, right): 163 | if event == LEFT: 164 | group = removed 165 | 166 | elif event == RIGHT: 167 | group = added 168 | 169 | elif event == DIFF: 170 | group = altered 171 | 172 | elif event == BOTH: 173 | group = same 174 | 175 | else: 176 | assert False 177 | 178 | if group is not None: 179 | group.append(filename) 180 | 181 | return added, removed, altered, same 182 | 183 | 184 | class ClosingContext(object): 185 | # pylint: disable=R0903 186 | # too few public methods (none) 187 | 188 | """ 189 | A simple context manager which is created with an object instance, 190 | and will return that instance from __enter__ and call the close 191 | method on the instance in __exit__ 192 | """ 193 | 194 | 195 | def __init__(self, managed): 196 | self.managed = managed 197 | 198 | 199 | def __enter__(self): 200 | return self.managed 201 | 202 | 203 | def __exit__(self, exc_type, _exc_val, _exc_tb): 204 | managed = self.managed 205 | self.managed = None 206 | 207 | if managed is not None and hasattr(managed, "close"): 208 | managed.close() 209 | 210 | return exc_type is None 211 | 212 | 213 | def closing(managed): 214 | """ 215 | If the managed object already provides its own context management 216 | via the __enter__ and __exit__ methods, it is returned 217 | unchanged. However, if the instance does not, a ClosingContext 218 | will be created to wrap it. When the ClosingContext exits, it will 219 | call managed.close() 220 | """ 221 | 222 | if managed is None or hasattr(managed, "__enter__"): 223 | return managed 224 | else: 225 | return ClosingContext(managed) 226 | 227 | 228 | # 229 | # The end. 230 | -------------------------------------------------------------------------------- /javatools/distinfo.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | 17 | """ 18 | Utility script and module for discovering information about a 19 | distribution of mixed class files and JARs. 20 | 21 | :author: Christopher O'Brien 22 | :license: LGPL 23 | """ 24 | 25 | 26 | from __future__ import print_function 27 | 28 | 29 | import sys 30 | 31 | from json import dump 32 | from argparse import ArgumentParser 33 | from os.path import isdir, join 34 | from shutil import rmtree 35 | from tempfile import mkdtemp 36 | 37 | from . import unpack_classfile 38 | from .jarinfo import JarInfo, JAR_PATTERNS, REQ_BY_CLASS, PROV_BY_CLASS 39 | from .dirutils import fnmatches 40 | from .ziputils import open_zip 41 | 42 | 43 | DIST_JAR = "jar" 44 | DIST_CLASS = "class" 45 | 46 | REQ_BY_JAR = "jar.requires" 47 | PROV_BY_JAR = "jar.provides" 48 | 49 | 50 | class DistInfo(object): 51 | 52 | 53 | def __init__(self, base_path): 54 | self.base_path = base_path 55 | 56 | # a pair of strings useful for later reporting. Non-mandatory 57 | self.product = None 58 | self.version = None 59 | 60 | # if the dist is a zip, we'll explode it into tmpdir 61 | self.tmpdir = None 62 | 63 | self._contents = None 64 | self._requires = None 65 | self._provides = None 66 | 67 | 68 | def __del__(self): 69 | self.close() 70 | 71 | 72 | def _working_path(self): 73 | if self.tmpdir: 74 | return self.tmpdir 75 | 76 | elif isdir(self.base_path): 77 | return self.base_path 78 | 79 | else: 80 | self.tmpdir = mkdtemp() 81 | with open_zip(self.base_path, "r") as zf: 82 | zf.extractall(path=self.tmpdir) 83 | return self.tmpdir 84 | 85 | 86 | def _collect_requires_provides(self): 87 | req = {} 88 | prov = {} 89 | 90 | p = set() 91 | 92 | for entry in self.get_jars(): 93 | ji = self.get_jarinfo(entry) 94 | for sym, data in ji.get_requires().items(): 95 | req.setdefault(sym, []).append((REQ_BY_JAR, entry, data)) 96 | for sym, data in ji.get_provides().items(): 97 | prov.setdefault(sym, []).append((PROV_BY_JAR, entry, data)) 98 | p.add(sym) 99 | ji.close() 100 | 101 | for entry in self.get_classes(): 102 | ci = self.get_classinfo(entry) 103 | for sym in ci.get_requires(): 104 | req.setdefault(sym, []).append((REQ_BY_CLASS, entry)) 105 | for sym in ci.get_provides(private=False): 106 | prov.setdefault(sym, []).append((PROV_BY_CLASS, entry)) 107 | for sym in ci.get_provides(private=True): 108 | p.add(sym) 109 | 110 | req = dict((k, v) for k, v in req.items() if k not in p) 111 | 112 | self._requires = req 113 | self._provides = prov 114 | 115 | 116 | def get_requires(self, ignored=tuple()): 117 | """ a map of requirements to what requires it. ignored is an 118 | optional list of globbed patterns indicating packages, 119 | classes, etc that shouldn't be included in the provides map""" 120 | 121 | if self._requires is None: 122 | self._collect_requires_provides() 123 | 124 | d = self._requires 125 | if ignored: 126 | d = dict((k, v) for k, v in d.items() 127 | if not fnmatches(k, *ignored)) 128 | return d 129 | 130 | 131 | def get_provides(self, ignored=tuple()): 132 | """ a map of provided classes and class members, and what 133 | provides them. ignored is an optional list of globbed patterns 134 | indicating packages, classes, etc that shouldn't be included 135 | in the provides map""" 136 | 137 | if self._provides is None: 138 | self._collect_requires_provides() 139 | 140 | d = self._provides 141 | if ignored: 142 | d = dict((k, v) for k, v in d.items() 143 | if not fnmatches(k, *ignored)) 144 | return d 145 | 146 | 147 | def get_jars(self): 148 | """ sequence of entry names found in this distribution """ 149 | 150 | for entry in self.get_contents(): 151 | if fnmatches(entry, *JAR_PATTERNS): 152 | yield entry 153 | 154 | 155 | def get_jarinfo(self, entry): 156 | return JarInfo(join(self.base_path, entry)) 157 | 158 | 159 | def get_classes(self): 160 | """ sequence of entry names found in the distribution. This 161 | is only the collection of class files directly in the dist, it 162 | does not include classes within JARs that are inthe dist.""" 163 | 164 | for entry in self.get_contents(): 165 | if fnmatches(entry, "*.class"): 166 | yield entry 167 | 168 | 169 | def get_classinfo(self, entry): 170 | return unpack_classfile(join(self.base_path, entry)) 171 | 172 | 173 | def get_contents(self): 174 | if self._contents is None: 175 | self._contents = tuple(_collect_dist(self._working_path())) 176 | return self._contents 177 | 178 | 179 | def close(self): 180 | """ if this was a zip'd distribution, any introspection 181 | may have resulted in opening or creating temporary files. 182 | Call close in order to clean up. """ 183 | 184 | if self.tmpdir: 185 | rmtree(self.tmpdir) 186 | self.tmpdir = None 187 | 188 | self._contents = None 189 | 190 | 191 | def _collect_dist(pathn): 192 | from os.path import join, relpath 193 | from os import walk 194 | for r, _ds, fs in walk(pathn): 195 | for f in fs: 196 | yield relpath(join(r, f), pathn) 197 | 198 | 199 | # --- CLI --- 200 | # 201 | 202 | 203 | def cli_dist_provides(options, info): 204 | print("distribution provides:") 205 | 206 | for provided in sorted(info.get_provides(options.api_ignore)): 207 | print(" ", provided) 208 | print() 209 | 210 | 211 | def cli_dist_requires(options, info): 212 | print("distribution requires:") 213 | 214 | for required in sorted(info.get_requires(options.api_ignore)): 215 | print(" ", required) 216 | print() 217 | 218 | 219 | def cli_distinfo(options, info): 220 | 221 | if options.dist_provides: 222 | cli_dist_provides(options, info) 223 | 224 | if options.dist_requires: 225 | cli_dist_requires(options, info) 226 | 227 | # TODO: simple things like listing JARs and non-JAR files 228 | 229 | 230 | def cli_distinfo_json(options, info): 231 | data = {} 232 | 233 | if options.dist_provides: 234 | data["dist.provides"] = info.get_provides(options.api_ignore) 235 | 236 | if options.dist_requires: 237 | data["dist.requires"] = info.get_requires(options.api_ignore) 238 | 239 | dump(data, sys.stdout, sort_keys=True, indent=2) 240 | 241 | 242 | def cli(options): 243 | # pylint: disable=W0613 244 | # parser unused 245 | 246 | pathn = options.dist 247 | info = DistInfo(pathn) 248 | 249 | if options.json: 250 | cli_distinfo_json(options, info) 251 | else: 252 | cli_distinfo(options, info) 253 | 254 | info.close() 255 | return 0 256 | 257 | 258 | def add_distinfo_optgroup(parser): 259 | g = parser.add_argument_group("Distribution Info Options") 260 | 261 | g.add_argument("--dist-provides", dest="dist_provides", 262 | action="store_true", default=False, 263 | help="API provides information at the distribution level") 264 | 265 | g.add_argument("--dist-requires", dest="dist_requires", 266 | action="store_true", default=False, 267 | help="API requires information at the distribution level") 268 | 269 | 270 | def create_optparser(progname): 271 | from .jarinfo import add_jarinfo_optgroup 272 | from .classinfo import add_classinfo_optgroup 273 | 274 | parser = ArgumentParser(prog=progname) 275 | parser.add_argument("dist", help="distribution to inspect") 276 | parser.add_argument("--json", dest="json", action="store_true", 277 | help="output in JSON mode") 278 | 279 | add_distinfo_optgroup(parser) 280 | add_jarinfo_optgroup(parser) 281 | add_classinfo_optgroup(parser) 282 | 283 | return parser 284 | 285 | 286 | def main(args=sys.argv): 287 | parser = create_optparser(args[0]) 288 | return cli(parser.parse_args(args[1:])) 289 | 290 | 291 | # 292 | # The end. 293 | -------------------------------------------------------------------------------- /python-javatools.spec: -------------------------------------------------------------------------------- 1 | %global srcproj javatools 2 | %global srcname python-%{srcproj} 3 | %global srcver 1.6.0 4 | %global srcrel 1 5 | 6 | 7 | # There's two distinct eras of RPM packaging for python, with 8 | # different macros and different expectations. Generally speaking the 9 | # new features are available in RHEL 8+ and Fedora 22+ 10 | 11 | %define old_rhel ( 0%{?rhel} && 0%{?rhel} < 8 ) 12 | %define old_fedora ( 0%{?fedora} && 0%{?fedora} < 22 ) 13 | 14 | %if %{old_rhel} || %{old_fedora} 15 | # old python 2.6 support 16 | %define with_old_python 1 17 | %undefine with_python2 18 | %undefine with_python3 19 | %else 20 | # newer pythons, with cooler macros 21 | %undefine with_old_python 22 | %bcond_with python2 23 | %bcond_without python3 24 | %endif 25 | 26 | 27 | # we don't generate binaries, let's turn the debuginfo part off 28 | %global debug_package %{nil} 29 | 30 | 31 | Summary: Tools for inspecting and comparing binary Java class files 32 | Name: %{srcname} 33 | Version: %{srcver} 34 | Release: %{srcrel}%{?dist} 35 | License: LGPLv3 36 | Group: Application/System 37 | URL: https://github.com/obriencj/python-javatools/ 38 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root 39 | BuildArch: noarch 40 | 41 | Source0: %{srcname}-%{srcver}.tar.gz 42 | 43 | 44 | %description 45 | Tools for inspecting and comparing binary Java class files, JARs, and 46 | JAR-based distributions 47 | 48 | 49 | %prep 50 | %setup -q 51 | 52 | 53 | %build 54 | 55 | %if %{with old_python} 56 | %{__python} setup.py build 57 | %endif 58 | 59 | %if %{with python2} 60 | %py2_build_wheel 61 | %endif 62 | 63 | %if %{with python3} 64 | %py3_build_wheel 65 | %endif 66 | 67 | 68 | %install 69 | %__rm -rf $RPM_BUILD_ROOT 70 | 71 | %if %{with old_python} 72 | %{__python} setup.py install --skip-build --root %{buildroot} 73 | %endif 74 | 75 | %if %{with python2} 76 | %py2_install_wheel %{srcproj}-%{version}-py2-none-any.whl 77 | %endif 78 | 79 | %if %{with python3} 80 | %py3_install_wheel %{srcproj}-%{version}-py3-none-any.whl 81 | %endif 82 | 83 | 84 | %clean 85 | rm -rf %{buildroot} 86 | 87 | 88 | %if %{with old_python} 89 | # package support for older python systems (centos 6, fedora 90 | # 19) with only python 2.6 available. 91 | 92 | %package -n python2-%{srcproj} 93 | Summary: %{summary} 94 | BuildRequires: python-devel python-setuptools 95 | BuildRequires: python-cheetah python-six 96 | Requires: python python-argparse python-setuptools 97 | Requires: python-cheetah python-six 98 | %{?python_provide:%python_provide python2-%{srcproj}} 99 | 100 | %description -n python2-%{srcproj} 101 | Python Java Tools 102 | 103 | %files -n python2-%{srcproj} 104 | %defattr(-,root,root,-) 105 | %{python2_sitelib}/javatools/ 106 | %{python2_sitelib}/javatools-%{version}.dist-info 107 | %{_bindir}/* 108 | 109 | %doc AUTHORS ChangeLog README.md 110 | %license LICENSE 111 | 112 | %endif 113 | 114 | 115 | %if %{with python2} 116 | 117 | %package -n python2-%{srcproj} 118 | Summary: %{summary} 119 | BuildRequires: python2-devel 120 | BuildRequires: python2-pip python2-setuptools python2-wheel 121 | BuildRequires: python2-cheetah python2-six 122 | Requires: python2 python2-setuptools 123 | Requires: python2-cheetah python2-six 124 | %{?python_provide:%python_provide python2-%{srcproj}} 125 | %{?py_provides:%py_provides python2-%{srcproj}} 126 | 127 | %description -n python2-%{srcproj} 128 | Python Java Tools 129 | 130 | %files -n python2-%{srcproj} 131 | %defattr(-,root,root,-) 132 | %{python2_sitelib}/javatools/ 133 | %{python2_sitelib}/javatools-%{version}.dist-info 134 | %{_bindir}/* 135 | 136 | %doc AUTHORS ChangeLog README.md 137 | %license LICENSE 138 | 139 | %endif 140 | 141 | 142 | %if %{with python3} 143 | 144 | %package -n python3-%{srcproj} 145 | Summary: %{summary} 146 | BuildRequires: python3-devel 147 | BuildRequires: python3-pip python3-setuptools python3-wheel 148 | BuildRequires: python3-cheetah python3-six 149 | Requires: python3 python3-setuptools 150 | Requires: python3-cheetah python3-six 151 | %{?python_provide:%python_provide python3-%{srcproj}} 152 | %{?py_provides:%py_provides python3-%{srcproj}} 153 | 154 | %description -n python3-%{srcproj} 155 | Python Java Tools 156 | 157 | %files -n python3-%{srcproj} 158 | %defattr(-,root,root,-) 159 | %{python3_sitelib}/javatools/ 160 | %{python3_sitelib}/javatools-%{version}.dist-info 161 | %{_bindir}/* 162 | 163 | %doc AUTHORS ChangeLog README.md 164 | %license LICENSE 165 | 166 | %endif 167 | 168 | 169 | %changelog 170 | 171 | * Thu Jul 27 2023 Christopher O'Brien - 1.6.0-1 172 | - version 1.6.0 173 | - m2crypto is runtime optional 174 | - python2 and python3 support 175 | 176 | * Sun Jun 21 2020 Christopher O'Brien - 1.5.0-1 177 | - version 1.5.0 178 | 179 | * Sun Oct 05 2019 Christopher O'Brien - 1.4.0-1 180 | - version 1.4.0 181 | - added ChangeLog as its own file 182 | - move to setuptools 183 | 184 | * Thu May 23 2013 Christopher O'Brien - 1.3-1 185 | - bump to 1.3 186 | 187 | * Thu Jun 14 2012 Christopher O'Brien - 1.2-1 188 | - require python 2.6 and later 189 | 190 | * Sun May 06 2012 Christopher O'Brien - 1.1-1 191 | - dependency features, license files 192 | 193 | * Fri Apr 27 2012 Christopher O'Brien - 1.0-1 194 | - Initial build. 195 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # This file defines the general configuration for the javatools 2 | # wheel, and the tools tox, nose, flake8, coverage, and sphinx 3 | 4 | 5 | [metadata] 6 | name = javatools 7 | version = 1.6.0 8 | description = Tools for working with Java class files and JARs 9 | 10 | author = Christopher O'Brien 11 | author_email = obriencj@gmail.com 12 | 13 | license = GNU Lesser General Public License v3 (LGPLv3) 14 | license_files = 15 | LICENSE 16 | 17 | long_description = file: README.md 18 | long_description_content_type = text/markdown 19 | 20 | home_page = https://github.com/obriencj/python-javatools 21 | 22 | platform = any 23 | 24 | project_urls = 25 | Source = https://github.com/obriencj/python-javatools 26 | Bug Reports = https://github.com/obriencj/python-javatools/issues 27 | 28 | classifiers = 29 | Development Status :: 5 - Production/Stable 30 | Environment :: Console 31 | Intended Audience :: Developers 32 | Intended Audience :: Information Technology 33 | License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) 34 | Programming Language :: Python :: 2 35 | Programming Language :: Python :: 2.7 36 | Programming Language :: Python :: 3 37 | Programming Language :: Python :: 3.7 38 | Programming Language :: Python :: 3.8 39 | Programming Language :: Python :: 3.9 40 | Programming Language :: Python :: 3.10 41 | Programming Language :: Python :: 3.11 42 | Topic :: Software Development :: Disassemblers 43 | 44 | 45 | [options] 46 | packages = 47 | javatools 48 | javatools.cheetah 49 | 50 | zip_safe = False 51 | 52 | setup_requires = 53 | CT3 # Cheetah3 54 | six 55 | 56 | install_requires = 57 | CT3 # Cheetah3 58 | six 59 | 60 | tests_require = 61 | CT3 # Cheetah3 62 | M2Crypto >= 0.26.0 63 | coverage 64 | six 65 | 66 | 67 | [options.extras_require] 68 | crypto = 69 | M2Crypto >= 0.26.0 70 | 71 | 72 | [options.package_data] 73 | javatools.cheetah = 74 | *.tmpl 75 | data/*.css 76 | data/*.js 77 | data/*.png 78 | 79 | 80 | [options.entry_points] 81 | console_scripts = 82 | classdiff=javatools.classdiff:main 83 | classinfo=javatools.classinfo:main 84 | distdiff=javatools.distdiff:main 85 | distinfo=javatools.distinfo:main 86 | jardiff=javatools.jardiff:main 87 | jarinfo=javatools.jarinfo:main 88 | jarutil=javatools.jarutil:main 89 | manifest=javatools.manifest:main 90 | 91 | 92 | [aliases] 93 | # nose acts enough like the original test command, but without the 94 | # extremely obnoxious deprecation warning. And why are they 95 | # deprecating the test command? So someone can remove approximately 40 96 | # lines of code from setuptools, despite the test command being the 97 | # most convenient and available way to get started with unit testing. 98 | 99 | test = nosetests 100 | 101 | 102 | [tox:tox] 103 | envlist = flake8,py{27,37,38,39,310,311},coverage,bandit,twine 104 | skip_missing_interpreters = true 105 | 106 | 107 | [testenv] 108 | setenv = 109 | COVERAGE_FILE = .coverage.{envname} 110 | 111 | commands = 112 | python -B -m coverage run -m nose 113 | 114 | sitepackages = true 115 | 116 | download = true 117 | 118 | deps = 119 | CT3 # Cheetah3 120 | M2Crypto>=0.26.0 121 | coverage 122 | nose-py3 123 | six 124 | 125 | 126 | [testenv:py27] 127 | 128 | deps = 129 | CT3 # Cheetah3 130 | M2Crypto>=0.26.0 131 | coverage 132 | nose 133 | six 134 | 135 | 136 | [testenv:bandit] 137 | 138 | basepython = python3.9 139 | 140 | commands = 141 | python -B -m bandit --ini setup.cfg -qr javatools 142 | 143 | deps = 144 | bandit 145 | 146 | 147 | [testenv:twine] 148 | 149 | basepython = python3.9 150 | 151 | commands = 152 | python -B setup.py bdist_wheel 153 | python -B -m twine check --strict dist/*.whl 154 | 155 | deps = 156 | twine 157 | 158 | 159 | [testenv:flake8] 160 | 161 | basepython = python3.9 162 | 163 | commands = 164 | python -B -m flake8 javatools 165 | 166 | deps = 167 | flake8 168 | 169 | 170 | [testenv:coverage] 171 | # this is just here to combine the coverage output 172 | 173 | setenv = 174 | COVERAGE_FILE = .coverage 175 | 176 | basepython = python 177 | 178 | commands = 179 | python -B -m coverage combine 180 | python -B -m coverage report 181 | python -B -m coverage html 182 | 183 | 184 | [nosetests] 185 | 186 | all-modules = 1 187 | no-byte-compile = 1 188 | verbosity = 2 189 | 190 | 191 | [coverage:run] 192 | 193 | source = 194 | javatools 195 | 196 | 197 | [coverage:report] 198 | 199 | exclude_lines = 200 | \.\.\. 201 | pass 202 | pragma: no cover 203 | @abstract 204 | 205 | 206 | [bandit] 207 | # B101 complains about asserts 208 | 209 | skips = B101 210 | 211 | 212 | [flake8] 213 | # E303 complains about more than one blank lines between methods in a class 214 | # E731 assigning a lambda to a variable 215 | # E741 ambiguous variable name 216 | # F401 ambiguous variable name 217 | # F812 list comprehension redefines variable (I reuse tmp names) 218 | # W504 line break after binary operator 219 | 220 | ignore = E303,E731,E741,F401,F812,W504 221 | 222 | filename = 223 | *.py 224 | *.pyi 225 | 226 | exclude = 227 | __pycache__ 228 | .* 229 | build 230 | dist 231 | docs 232 | gh-pages 233 | htmlcov 234 | setup.py 235 | tests 236 | todo 237 | tools 238 | 239 | 240 | [testenv:sphinx] 241 | 242 | basepython = python3.9 243 | 244 | commands = 245 | python -B setup.py build_sphinx 246 | 247 | # sphinx 7 not only doesn't have a build_sphinx command, but it also 248 | # completely ignores the settings in setup.cfg 249 | deps = 250 | sphinx<7 251 | numpydoc 252 | 253 | 254 | [build_sphinx] 255 | # some of the configuration for sphinx. The rest of it lives over in 256 | # docs/conf.py 257 | 258 | version = 1.6 259 | release = 1.6.0 260 | 261 | project = python-javatools 262 | copyright = 2014-2023, Christopher O'Brien 263 | 264 | build-dir = build/sphinx 265 | builder = dirhtml html 266 | source-dir = docs 267 | 268 | 269 | [gh-actions] 270 | python = 271 | 2.7: py27 272 | 3.7: py37 273 | 3.8: py38 274 | 3.9: py39, flake8, bandit 275 | 3.10: py310 276 | 277 | 278 | # 279 | # The end. 280 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # This library is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU Lesser General Public License as 5 | # published by the Free Software Foundation; either version 3 of the 6 | # License, or (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, but 9 | # WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | # Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public 14 | # License along with this library; if not, see 15 | # . 16 | 17 | 18 | """ 19 | Python Javatools 20 | 21 | author: Christopher O'Brien 22 | license: LGPL v.3 23 | """ 24 | 25 | 26 | from setuptools import setup as _setup 27 | 28 | 29 | PYTHON_SUPPORTED_VERSIONS = ( 30 | ">=2.7", 31 | "!=3.0.*", "!=3.1.*", "!=3.2.*", "!=3.3.*", "!=3.4.*", 32 | "<4", 33 | ) 34 | 35 | 36 | def delayed_cheetah_build_py_cmd(*args, **kwds): 37 | # only import cheetah_build_py_cmd immediately before 38 | # instantiating it. 39 | from javatools.cheetah.setuptools import cheetah_build_py_cmd 40 | return cheetah_build_py_cmd(*args, **kwds) 41 | 42 | 43 | def setup(): 44 | return _setup(cmdclass={'build_py': delayed_cheetah_build_py_cmd, }) 45 | 46 | 47 | if __name__ == '__main__': 48 | setup() 49 | 50 | 51 | # 52 | # The end. 53 | -------------------------------------------------------------------------------- /tests/classdiff.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for javatools/classdiff.py 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | import os 24 | from unittest import TestCase 25 | from . import get_data_fn 26 | from javatools.classdiff import main 27 | 28 | 29 | class ClassdiffTest(TestCase): 30 | 31 | # Options from relevant option groups are accepted: 32 | def test_options_accepted(self): 33 | left = get_data_fn(os.path.join("test_classdiff", "Sample1.class")) 34 | right = get_data_fn(os.path.join("test_classdiff", "Sample2.class")) 35 | # General options: 36 | self.assertEqual(1, main(["argv0", "-q", left, right])) 37 | # Class checking options: 38 | self.assertEqual(1, main(["argv0", "--ignore-platform", left, right])) 39 | # Reporting options: 40 | self.assertEqual(1, main(["argv0", "--report-dir=foo", left, right])) 41 | # JSON reporting options: 42 | self.assertEqual(1, main(["argv0", "--json-indent=4", left, right])) 43 | # HTML reporting options: 44 | self.assertEqual(1, main(["argv0", "--html-copy-data=foo", left, right])) -------------------------------------------------------------------------------- /tests/classinfo.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for javatools/classinfo.py 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | import os 24 | from unittest import TestCase 25 | from . import get_data_fn 26 | from javatools.classinfo import main 27 | 28 | 29 | class ClassinfoTest(TestCase): 30 | 31 | # Test that (some random) classinfo-specific options are accepted. 32 | def test_classinfo_options(self): 33 | class_fn = get_data_fn(os.path.join("test_classinfo", "Sample1.class")) 34 | self.assertEqual(0, main(["argv0", "-p", class_fn])) 35 | -------------------------------------------------------------------------------- /tests/crypto.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for cryptography-related functions of python-javatools. 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | from unittest import TestCase 24 | from javatools.crypto import private_key_type, CannotFindKeyTypeError 25 | from . import get_data_fn 26 | 27 | class CryptoTest(TestCase): 28 | 29 | def test_private_key_type(self): 30 | rsa_key = get_data_fn("test_crypto/test_private_key_type__key-rsa.pem") 31 | self.assertEqual(private_key_type(rsa_key), "RSA") 32 | 33 | rsa_key_pkcs8 = get_data_fn("test_crypto/test_private_key_type__key-rsa-pkcs8.pem") 34 | self.assertEqual(private_key_type(rsa_key_pkcs8), "RSA") 35 | 36 | dsa_key = get_data_fn("test_crypto/test_private_key_type__key-dsa.pem") 37 | self.assertEqual(private_key_type(dsa_key), "DSA") 38 | 39 | ec_key = get_data_fn("test_crypto/test_private_key_type__key-ec.pem") 40 | self.assertEqual(private_key_type(ec_key), "EC") 41 | 42 | invalid_key = get_data_fn("test_crypto/test_private_key_type__key-invalid.pem") 43 | with self.assertRaises(CannotFindKeyTypeError): 44 | private_key_type(invalid_key) 45 | 46 | # 47 | # The end. 48 | -------------------------------------------------------------------------------- /tests/data/Makefile: -------------------------------------------------------------------------------- 1 | SOURCES = $(wildcard *.java) 2 | JAVAC = javac 3 | 4 | .SUFFIXES: .java .class 5 | .java.class: 6 | $(JAVAC) $< 7 | default: all 8 | all: $(SOURCES:.java=.class) 9 | clean: 10 | $(RM) *.class 11 | -------------------------------------------------------------------------------- /tests/data/README.md: -------------------------------------------------------------------------------- 1 | # python-javatools test data 2 | 3 | This directory contains sample Java class files for the 4 | python-javatools unit tests to run against. 5 | 6 | 7 | ## Rebuilding 8 | 9 | Both the source files and the binaries are included in git. You may 10 | opt to rebuild the sources, but be warned that doing so may change the 11 | validity of some of the tests. For example, the ordering of the 12 | constants pool may vary depending on the version of the javac used to 13 | compile the binaries, and this will most certainly result in some of 14 | the tests failing. 15 | 16 | Suitably warned, to rebuild the samples simply run: 17 | 18 | ```make clean all``` 19 | 20 | 21 | ## Sample 1 22 | 23 | - Source: Sample1.java 24 | - Binary: Sample1.class 25 | 26 | This sample tests the simplest set of features. fields, methods, 27 | constant pool, method code, line number tables. 28 | 29 | 30 | ## Sample 2 31 | 32 | - Sources: Sample2I.java, Sample2A.java, Sample2.java 33 | - Binaries: Sample2I.class, Sample2A.class, Sample2.class 34 | 35 | This sample tests interfaces and abstract classes, and bridge 36 | methods. It also tests large-sized constants (double and float) 37 | 38 | 39 | ## Sample 3 40 | 41 | - Source: Sample3.java 42 | - Binary: Sample3.class 43 | 44 | Synchronized method, synchronized static method. Methods that throw, 45 | methods with try/catch. 46 | 47 | 48 | ## Sample 4 49 | 50 | TODO -- annotations 51 | 52 | -------------------------------------------------------------------------------- /tests/data/Sample1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/Sample1.class -------------------------------------------------------------------------------- /tests/data/Sample1.java: -------------------------------------------------------------------------------- 1 | public class Sample1 extends Object { 2 | 3 | public static final String DEFAULT_NAME = "Daphne"; 4 | 5 | private String name = null; 6 | protected static String recent_name = null; 7 | 8 | public Sample1() { 9 | this(DEFAULT_NAME); 10 | } 11 | 12 | public Sample1(String name) { 13 | this.name = name; 14 | this.recent_name = name; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public static String getRecentName() { 22 | return recent_name; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /tests/data/Sample2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/Sample2.class -------------------------------------------------------------------------------- /tests/data/Sample2.java: -------------------------------------------------------------------------------- 1 | public final class Sample2 extends Sample2A { 2 | public boolean getBoolean(boolean b) { 3 | return b; 4 | } 5 | public byte getByte(byte b) { 6 | return b; 7 | } 8 | public char getChar(char c) { 9 | return c; 10 | } 11 | public int getInt(int i) { 12 | return i; 13 | } 14 | public long getLong(long l) { 15 | return l; 16 | } 17 | public double getDouble(double d) { 18 | return d; 19 | } 20 | public float getFloat(float f) { 21 | return f; 22 | } 23 | public Sample2 getSample() { 24 | return this; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/data/Sample2A.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/Sample2A.class -------------------------------------------------------------------------------- /tests/data/Sample2A.java: -------------------------------------------------------------------------------- 1 | public abstract class Sample2A implements Sample2I { 2 | public Sample2A getSample() { 3 | return this; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/data/Sample2I.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/Sample2I.class -------------------------------------------------------------------------------- /tests/data/Sample2I.java: -------------------------------------------------------------------------------- 1 | public interface Sample2I { 2 | public boolean getBoolean(boolean b); 3 | public byte getByte(byte b); 4 | public char getChar(char c); 5 | public int getInt(int i); 6 | public long getLong(long l); 7 | public Sample2I getSample(); 8 | } 9 | -------------------------------------------------------------------------------- /tests/data/Sample3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/Sample3.class -------------------------------------------------------------------------------- /tests/data/Sample3.java: -------------------------------------------------------------------------------- 1 | public class Sample3 extends Object { 2 | 3 | private Object data = null; 4 | private static Object lastData = null; 5 | 6 | public int[][] twoDimIntArray; 7 | 8 | private static synchronized void setLastData(Object data) { 9 | lastData = data; 10 | } 11 | 12 | private static synchronized Object getLastData() throws Exception { 13 | if (lastData == null) { 14 | throw new Exception("no data"); 15 | } else { 16 | return lastData; 17 | } 18 | } 19 | 20 | public synchronized void setData(Object d) { 21 | data = d; 22 | setLastData(d); 23 | } 24 | 25 | public synchronized Object getData() throws Exception { 26 | if (data == null) { 27 | data = getLastData(); 28 | } 29 | return data; 30 | } 31 | 32 | public Object getData(Object defaultValue) { 33 | try { 34 | return getData(); 35 | } catch(Exception exc) { 36 | return defaultValue; 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /tests/data/SampleLambdas.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/SampleLambdas.class -------------------------------------------------------------------------------- /tests/data/SampleLambdas.java: -------------------------------------------------------------------------------- 1 | import java.util.Comparator; 2 | 3 | public class SampleLambdas extends Object { 4 | 5 | public static final Comparator by_hash = (Comparator) 6 | (Object a, Object b) -> { 7 | int ahash = a.hashCode(); 8 | int bhash = b.hashCode(); 9 | if (ahash == bhash) { 10 | return 0; 11 | } else if (ahash < bhash) { 12 | return -1; 13 | } else { 14 | return 1; 15 | } 16 | }; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /tests/data/test_classdiff/Sample1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_classdiff/Sample1.class -------------------------------------------------------------------------------- /tests/data/test_classdiff/Sample2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_classdiff/Sample2.class -------------------------------------------------------------------------------- /tests/data/test_classinfo/Sample1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_classinfo/Sample1.class -------------------------------------------------------------------------------- /tests/data/test_crypto/test_private_key_type__key-dsa.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIDVQIBAAKCAQEA1n49MjqCbwOzEsQ0x4E6/ZCaZmAVw0NzbsbA0+Ie51ycWzIb 3 | Ntw+4CSqokulUCXLsoASJ1uDUEsK9zk0E3DgKjmhY9SJHKoeUy7m3L7Q0YC5Wygg 4 | pGsx8rdiI+vUxUGGoBsz1RSoTH1+dKOySw2IBcDTRktSpaOtAgXE1/gW0LolBk2y 5 | Ra+k8h83VN1Zd0asrPp2cICewfnXi3MslnJa+3NShI5WQf6vYLqDIH30GIM8PfZ7 6 | FeOYNZr7bJfPBE3r97TTHS7NKEDuBc1kfKPBM1kYaPvTsb2hdN2p170JncJ1RF6i 7 | uvNuoTr1vAr5kgbAU2IR6k5pvXblR/6IA6TxwwIhAMTxctBM65R2QoE35Lg33D43 8 | rhY+CMW+9hagmSnReELlAoIBADODnLLqbMtzf11zltJhOpJ6v7aQq+YWixX9fQqf 9 | c56ubCyvlJSSB1Wszl1eFz1ZzxjTVIYKf4fz/CTkMFWGqxU6J+9/hSXfSEILybPr 10 | oz0FfnFf1LM7Xq42k4HvVsSj/TYaK4O/i309VODQq+MJWhKnBizH8tun1Wg8+WX1 11 | yN1v4wv799FKtJbQt2EV+7flfNlmeslFvb/PK1i22IDHVCwXxAKaiFwiGwEZDrft 12 | RV1g/UswWzsHpVCxo0xUH/cELCSzUZjX0W71MyoOvO8AX1rPvdy9nvRlTv6Pr72Z 13 | vMsl1znB7eha66hS9brYb1DdngtfLa/79XPB9jfggGjnm3ACggEAc7WcUOayr3bk 14 | KrH/S3IK/gpUWKtVmsFDl2tEpR26KnwjXjFGrXTswlfMfje0B/iBkn4qyENABUWf 15 | ZXYLEy2Qvu2b1iu4jX0u8toQiSM8jgBYElUsAORbUbvn4aUq8PFeP1Hk3OMadqfS 16 | F+7R4BEd+k/6pDRFmoAWVCKUPsc1KtC5sATde1PmzCQ2BgJqVe3hjqZp5V3hfmPc 17 | Jb6EMgn/QkPy1I7m97UKwTQAL8cozmVMjXkNqURhp25zmruN98i8v9bOqA2pWeku 18 | 8vHhyJRq4HbR0CzN0RUKAYK0Y1eL8nL8tN2fi5BYJFvy9i/5rH+MvMREKJgptf8r 19 | r/iqiKoC3QIgVHsygWEyMf2isxwFH8k7PWMQDGw+bHvJv5oz17rQnlI= 20 | -----END DSA PRIVATE KEY----- 21 | -------------------------------------------------------------------------------- /tests/data/test_crypto/test_private_key_type__key-ec.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BgUrgQQAIw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MIHcAgEBBEIBhj5p/lGkhjwPxJUXvvl+a2krM4m7Jdj2yD9sOz8YxE44tXn9sJv+ 6 | 3Bu5QRR7cLimx9Be+pN4INvUnmy32Zg5a72gBwYFK4EEACOhgYkDgYYABAFiR+MS 7 | s/3av/x78sf71GJP3ErfKb0jwI+h5pPFXfpwjFE9u6c7AhxhVMRpKABS6YpFl5oE 8 | WzaqoaRMQjvCt1DGfwEji2waUkTWt08+oQnNgjY6HfmSdHJWaGghYe+nGy37el0r 9 | DScF8tJO5kuEAKLIzPYziVGihl1kcHGs7rz9LrjSQQ== 10 | -----END EC PRIVATE KEY----- 11 | -------------------------------------------------------------------------------- /tests/data/test_crypto/test_private_key_type__key-invalid.pem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_crypto/test_private_key_type__key-invalid.pem -------------------------------------------------------------------------------- /tests/data/test_crypto/test_private_key_type__key-rsa-pkcs8.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/tmXRx2b4vREy 3 | T9NaY7cMQp8Vdf9osIAeWmCI8bcmxKBPe+ukSE/QK9iaPXkeIglAdZCf/uBPmXw3 4 | ga5O8lN3tI5bDuniAbCKRmjQa7dhVia4l8+T8T2CXyz4vO6pu63jkkfqw7IgJG/p 5 | hQbEKtQ2X82Sw4/VuGV7qGK5PfhpPe9KC1g0j0ymBK3rlbHZCjYVmqtltNBZUSsr 6 | 3hvL49nD72R19If2OHfxs+bp0V3lRIETyXQNbYCPk22f6DUVGp2lU7lj+KXc+wTL 7 | kNDa1fsH2ucyOeAEyA2qgmXeRBTsVk2Ysx4+417Zf7aeIMO9YMUu7mVZ1bnGzrD4 8 | 9QYN4uSbAgMBAAECggEANk9vzNwWecTmCEDA+UxiYODGvIevEXNe+DpWOrVvU1ZE 9 | q//JI8MwiSLCu/9KPpUZ1d74V7sWxLYQkJD2Vnsj1jeaVIWHEHW2E5Yav2CklLiZ 10 | Q5YOQjUHXdWkodq0KfV3L48TPJiv75ci9R6wagZQFA9T543rQ3p3lW6AeUXrB7T7 11 | WIDL0Ng5x8LQaYhVZmeQkGg2BVcxJmKrm9qd5CNSQ4EYHdoTxzonGTHJnOi3uuk2 12 | ij25X/sQ2cQVDCugZYKhjgQ5MpeVhUXHHjR9STCWW8/GEeJwe3YL+ugMD/VnDrOz 13 | AScyhnF5G9nyg36pQZMqh617ZCEs2wEupQz4nJwKYQKBgQD9kPR1+KLnbO0PqYZZ 14 | L398cffKTiL6ugkvPSwpw98uVAJTQPy8TiLOMiM4QUZ0cvMgLkokNBjcINH4pXRH 15 | 05u8r3a31oiyWVt9NnJQEBgB/BkuNruVYfjSItLB1KyfYVliNCIPVkHmqD7B3sX0 16 | hP+jlSxqH4u2JCyWqQIM2hr0AwKBgQDBjXXM5OqfMM+Ve9L3f07JTbHZC7HYTZJ4 17 | b8gCwqUGrdiOEFe25oVDjkzGnQnQVCmzzSSWgYvJEkay/wV4zxAyRuNxQcEjINnZ 18 | pxresnK/irF0IGmMYbE1ZQxz3B/Ce2yHYsV1o5rUXXIQ8G0VNUjxzCs6qStq2sey 19 | ChLUcpDFiQKBgBVBr5ysKUvpT74+YercFn3iN/mXr0sBiX+SSz99EhqaJE/CZO2M 20 | R1Kt1VID9toQQN1zw/dg/qyFe9SyWhsjXCznMLacn30EDK1kgRTBJKIV9i5vnC4b 21 | tnY3QR/KqmX6DTo0UJ6khoXFmO07tbCX7a5S9RQ4bMfqJGrE5E0bg6LtAoGADKw5 22 | cU/vuLqWbOAtoPzZ6L5IjcCBRXtWwsH2449hBL3vNuYFCDmxsgmoJzzy/ov0Kwyc 23 | f6o9v82NiXy/G/jaw5/2llzKy4UEHocdcEVY1Ae9tK/GmWVwF+Hk3dUk0zQHmBm0 24 | eg5bPdpcdJV5XvEdNI+8qNuYtydZ+eNE9loF9pkCgYEA4i00Z2Sw1zjkXLquAB7D 25 | eFabq43RrNiE33Pbk50OcmsJEWYMFKiBRGYim/FG0YbSsuSt66YXXRwQxaA3JPV3 26 | 0xUD+xxnedZdE9T3ra0vB61aprniWSnwzQVGKKhSTJ/lBuen67xpOWWYJEgap+bh 27 | E/nsFu0UtJGz/vZcJvFuavI= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/data/test_crypto/test_private_key_type__key-rsa.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/tmXRx2b4vREy 3 | T9NaY7cMQp8Vdf9osIAeWmCI8bcmxKBPe+ukSE/QK9iaPXkeIglAdZCf/uBPmXw3 4 | ga5O8lN3tI5bDuniAbCKRmjQa7dhVia4l8+T8T2CXyz4vO6pu63jkkfqw7IgJG/p 5 | hQbEKtQ2X82Sw4/VuGV7qGK5PfhpPe9KC1g0j0ymBK3rlbHZCjYVmqtltNBZUSsr 6 | 3hvL49nD72R19If2OHfxs+bp0V3lRIETyXQNbYCPk22f6DUVGp2lU7lj+KXc+wTL 7 | kNDa1fsH2ucyOeAEyA2qgmXeRBTsVk2Ysx4+417Zf7aeIMO9YMUu7mVZ1bnGzrD4 8 | 9QYN4uSbAgMBAAECggEANk9vzNwWecTmCEDA+UxiYODGvIevEXNe+DpWOrVvU1ZE 9 | q//JI8MwiSLCu/9KPpUZ1d74V7sWxLYQkJD2Vnsj1jeaVIWHEHW2E5Yav2CklLiZ 10 | Q5YOQjUHXdWkodq0KfV3L48TPJiv75ci9R6wagZQFA9T543rQ3p3lW6AeUXrB7T7 11 | WIDL0Ng5x8LQaYhVZmeQkGg2BVcxJmKrm9qd5CNSQ4EYHdoTxzonGTHJnOi3uuk2 12 | ij25X/sQ2cQVDCugZYKhjgQ5MpeVhUXHHjR9STCWW8/GEeJwe3YL+ugMD/VnDrOz 13 | AScyhnF5G9nyg36pQZMqh617ZCEs2wEupQz4nJwKYQKBgQD9kPR1+KLnbO0PqYZZ 14 | L398cffKTiL6ugkvPSwpw98uVAJTQPy8TiLOMiM4QUZ0cvMgLkokNBjcINH4pXRH 15 | 05u8r3a31oiyWVt9NnJQEBgB/BkuNruVYfjSItLB1KyfYVliNCIPVkHmqD7B3sX0 16 | hP+jlSxqH4u2JCyWqQIM2hr0AwKBgQDBjXXM5OqfMM+Ve9L3f07JTbHZC7HYTZJ4 17 | b8gCwqUGrdiOEFe25oVDjkzGnQnQVCmzzSSWgYvJEkay/wV4zxAyRuNxQcEjINnZ 18 | pxresnK/irF0IGmMYbE1ZQxz3B/Ce2yHYsV1o5rUXXIQ8G0VNUjxzCs6qStq2sey 19 | ChLUcpDFiQKBgBVBr5ysKUvpT74+YercFn3iN/mXr0sBiX+SSz99EhqaJE/CZO2M 20 | R1Kt1VID9toQQN1zw/dg/qyFe9SyWhsjXCznMLacn30EDK1kgRTBJKIV9i5vnC4b 21 | tnY3QR/KqmX6DTo0UJ6khoXFmO07tbCX7a5S9RQ4bMfqJGrE5E0bg6LtAoGADKw5 22 | cU/vuLqWbOAtoPzZ6L5IjcCBRXtWwsH2449hBL3vNuYFCDmxsgmoJzzy/ov0Kwyc 23 | f6o9v82NiXy/G/jaw5/2llzKy4UEHocdcEVY1Ae9tK/GmWVwF+Hk3dUk0zQHmBm0 24 | eg5bPdpcdJV5XvEdNI+8qNuYtydZ+eNE9loF9pkCgYEA4i00Z2Sw1zjkXLquAB7D 25 | eFabq43RrNiE33Pbk50OcmsJEWYMFKiBRGYim/FG0YbSsuSt66YXXRwQxaA3JPV3 26 | 0xUD+xxnedZdE9T3ra0vB61aprniWSnwzQVGKKhSTJ/lBuen67xpOWWYJEgap+bh 27 | E/nsFu0UtJGz/vZcJvFuavI= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/data/test_distdiff/dist1/ec.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_distdiff/dist1/ec.jar -------------------------------------------------------------------------------- /tests/data/test_distdiff/dist2/ec-tampered.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_distdiff/dist2/ec-tampered.jar -------------------------------------------------------------------------------- /tests/data/test_distdiff/mf1/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: 1.7.0_51 (Oracle Corporation) 3 | 4 | -------------------------------------------------------------------------------- /tests/data/test_distdiff/mf2/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | Name: filename-which-is-longer-than-80-characters-and-does-not-fit-in- 4 | java-manifest-line.txt 5 | MD5-Digest: JqsNuQ1y4orQuh4i7lEFEA== 6 | SHA-512-Digest: Y+Iuwvvuur8AXlj7+w7uYHxKpBcEWmigzGN2ewSONVkmjTXnLzZ9Oy 7 | 29Xb3fEvxDl3YroUkmCzeVoDkXE73c1w== 8 | 9 | -------------------------------------------------------------------------------- /tests/data/test_distdiff/text1/file.txt: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /tests/data/test_distdiff/text2/file.txt: -------------------------------------------------------------------------------- 1 | b 2 | -------------------------------------------------------------------------------- /tests/data/test_distinfo/dist1/Sample.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_distinfo/dist1/Sample.jar -------------------------------------------------------------------------------- /tests/data/test_extensions/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC7DCCAdSgAwIBAgIJALx5vnebWfutMA0GCSqGSIb3DQEBCwUAMBkxFzAVBgNV 3 | BAMMDk15IENvbW1vbiBOYW1lMCAXDTE4MDQyODIxMTc0M1oYDzIxMTgwNDA0MjEx 4 | NzQzWjAZMRcwFQYDVQQDDA5NeSBDb21tb24gTmFtZTCCASIwDQYJKoZIhvcNAQEB 5 | BQADggEPADCCAQoCggEBAJzuDqZEljiKVZ0SlEjVNd0FzqDR6V84Hzje46EstMCR 6 | U5GqZ4h3oJbMNS01SWtaOBl4PPzDXhqI8BjDG/3gqzRMlyg4VHxxHqVGN7I3sBTS 7 | AI4LBbmsaDz9YrBi2/rr4/W/fFjG7HzJvTl1WZXgWCQqhj4Whe1MXThMtXd37VaX 8 | AUQSmPYeZCdxR42TnVEzDGsNyipmvEyoULAbnRtBpVlw2s2KssBM+M8pLIKFvsqE 9 | LOCNn/ToLMY7Qk0gCQygSndlZNKyaSW2Mv+ZX9vxJJ+R/X+t53fAZfXRvl4qmW9f 10 | ku1E3ir4GZxTjiPatLuOcmCS/NRyw/Er+2XE7zo3MD8CAwEAAaM1MDMwDwYDVR0T 11 | AQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDQYJ 12 | KoZIhvcNAQELBQADggEBAElGoE6HyjQnKGmDLpwaGG2YH2hHxE4Ge3Kj9EKYrZ/i 13 | sOscfUrssuDeJ66E9i52ucc2Z2npdlY7HtfcaaSIESTkVTDNsI44P63MWLme5nms 14 | UhND1/0VUdPhtVRo204yc8I1PXl/W4tQLwETRQGcHMfIm6PQ1Rm388ym+HIsTuRn 15 | kqmFp4V8rlabgCTfyON7D2UlbGcuMk6xH5OVSWM9rfpGZpinSOQI0yD3a2MFLz8j 16 | 1yVorssf3lWCUwUSI9Pm1rOqnCz4Sd203OPpPis4+Hyi0I087GZc7alS1ypBCKay 17 | tpszWYFXcMU/NOe5vZWGPNiiofdGvBO80fyU3HtWJfU= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/data/test_extensions/no-email-protection-cert.pem: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 1 (0x1) 5 | Signature Algorithm: sha256WithRSAEncryption 6 | Issuer: CN=My Common Name 7 | Validity 8 | Not Before: Apr 29 07:34:33 2018 GMT 9 | Not After : Apr 5 07:34:33 2118 GMT 10 | Subject: CN=No email protection KU 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:9c:ee:0e:a6:44:96:38:8a:55:9d:12:94:48:d5: 16 | 35:dd:05:ce:a0:d1:e9:5f:38:1f:38:de:e3:a1:2c: 17 | b4:c0:91:53:91:aa:67:88:77:a0:96:cc:35:2d:35: 18 | 49:6b:5a:38:19:78:3c:fc:c3:5e:1a:88:f0:18:c3: 19 | 1b:fd:e0:ab:34:4c:97:28:38:54:7c:71:1e:a5:46: 20 | 37:b2:37:b0:14:d2:00:8e:0b:05:b9:ac:68:3c:fd: 21 | 62:b0:62:db:fa:eb:e3:f5:bf:7c:58:c6:ec:7c:c9: 22 | bd:39:75:59:95:e0:58:24:2a:86:3e:16:85:ed:4c: 23 | 5d:38:4c:b5:77:77:ed:56:97:01:44:12:98:f6:1e: 24 | 64:27:71:47:8d:93:9d:51:33:0c:6b:0d:ca:2a:66: 25 | bc:4c:a8:50:b0:1b:9d:1b:41:a5:59:70:da:cd:8a: 26 | b2:c0:4c:f8:cf:29:2c:82:85:be:ca:84:2c:e0:8d: 27 | 9f:f4:e8:2c:c6:3b:42:4d:20:09:0c:a0:4a:77:65: 28 | 64:d2:b2:69:25:b6:32:ff:99:5f:db:f1:24:9f:91: 29 | fd:7f:ad:e7:77:c0:65:f5:d1:be:5e:2a:99:6f:5f: 30 | 92:ed:44:de:2a:f8:19:9c:53:8e:23:da:b4:bb:8e: 31 | 72:60:92:fc:d4:72:c3:f1:2b:fb:65:c4:ef:3a:37: 32 | 30:3f 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Basic Constraints: 36 | CA:FALSE 37 | X509v3 Extended Key Usage: 38 | Time Stamping 39 | Signature Algorithm: sha256WithRSAEncryption 40 | 98:bc:6a:76:86:97:1d:9f:11:1b:60:b8:6e:2c:0d:fc:2f:56: 41 | e6:ac:5a:07:f7:51:09:12:2a:60:5c:39:1d:4a:3f:48:58:d9: 42 | 3d:f0:a4:e7:50:56:a1:01:71:dd:74:2f:6e:42:31:30:18:a1: 43 | 62:b1:20:bc:43:1a:e1:c2:96:2a:16:5c:e1:f0:fb:c7:86:28: 44 | e0:23:6c:b8:ef:3c:af:d8:41:95:70:8e:e4:34:52:58:12:c6: 45 | 3f:80:d6:68:23:1d:e3:fd:cb:34:25:f8:fa:37:5b:69:2c:54: 46 | 3d:0d:21:d1:5e:dd:32:3a:15:e4:3d:99:5b:75:13:66:d4:50: 47 | 08:7c:9b:b8:29:a8:55:c0:5e:88:82:82:e3:d0:08:6e:ed:ca: 48 | d2:8a:98:f4:78:98:bd:ce:2a:34:20:0f:b7:9f:06:82:69:fd: 49 | a4:cd:af:21:74:5e:73:58:d3:1c:3a:04:5f:05:57:e9:d2:b2: 50 | 33:c9:fb:f3:3c:45:32:63:f3:28:b3:db:b7:db:81:1a:dc:6d: 51 | 2a:56:1f:30:5d:ca:fd:4c:2c:04:d3:2f:7c:92:0f:89:68:08: 52 | 18:69:36:59:db:03:95:e7:36:8e:72:a1:a9:0c:b1:2e:1c:7a: 53 | 00:a6:49:df:82:48:11:05:a8:1f:cd:af:ea:f9:cf:4f:69:39: 54 | 4a:35:03:74 55 | -----BEGIN CERTIFICATE----- 56 | MIIC2TCCAcGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDDA5NeSBD 57 | b21tb24gTmFtZTAgFw0xODA0MjkwNzM0MzNaGA8yMTE4MDQwNTA3MzQzM1owITEf 58 | MB0GA1UEAwwWTm8gZW1haWwgcHJvdGVjdGlvbiBLVTCCASIwDQYJKoZIhvcNAQEB 59 | BQADggEPADCCAQoCggEBAJzuDqZEljiKVZ0SlEjVNd0FzqDR6V84Hzje46EstMCR 60 | U5GqZ4h3oJbMNS01SWtaOBl4PPzDXhqI8BjDG/3gqzRMlyg4VHxxHqVGN7I3sBTS 61 | AI4LBbmsaDz9YrBi2/rr4/W/fFjG7HzJvTl1WZXgWCQqhj4Whe1MXThMtXd37VaX 62 | AUQSmPYeZCdxR42TnVEzDGsNyipmvEyoULAbnRtBpVlw2s2KssBM+M8pLIKFvsqE 63 | LOCNn/ToLMY7Qk0gCQygSndlZNKyaSW2Mv+ZX9vxJJ+R/X+t53fAZfXRvl4qmW9f 64 | ku1E3ir4GZxTjiPatLuOcmCS/NRyw/Er+2XE7zo3MD8CAwEAAaMiMCAwCQYDVR0T 65 | BAIwADATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQsFAAOCAQEAmLxq 66 | doaXHZ8RG2C4biwN/C9W5qxaB/dRCRIqYFw5HUo/SFjZPfCk51BWoQFx3XQvbkIx 67 | MBihYrEgvEMa4cKWKhZc4fD7x4Yo4CNsuO88r9hBlXCO5DRSWBLGP4DWaCMd4/3L 68 | NCX4+jdbaSxUPQ0h0V7dMjoV5D2ZW3UTZtRQCHybuCmoVcBeiIKC49AIbu3K0oqY 69 | 9HiYvc4qNCAPt58Ggmn9pM2vIXRec1jTHDoEXwVX6dKyM8n78zxFMmPzKLPbt9uB 70 | GtxtKlYfMF3K/UwsBNMvfJIPiWgIGGk2WdsDlec2jnKhqQyxLhx6AKZJ34JIEQWo 71 | H82v6vnPT2k5SjUDdA== 72 | -----END CERTIFICATE----- 73 | -------------------------------------------------------------------------------- /tests/data/test_extensions/no-email-protection.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_extensions/no-email-protection.jar -------------------------------------------------------------------------------- /tests/data/test_extensions/no-ku-cert.pem: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 3 (0x3) 5 | Signature Algorithm: sha256WithRSAEncryption 6 | Issuer: CN=My Common Name 7 | Validity 8 | Not Before: Apr 29 07:58:32 2018 GMT 9 | Not After : Apr 5 07:58:32 2118 GMT 10 | Subject: CN=No any KU field 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:9c:ee:0e:a6:44:96:38:8a:55:9d:12:94:48:d5: 16 | 35:dd:05:ce:a0:d1:e9:5f:38:1f:38:de:e3:a1:2c: 17 | b4:c0:91:53:91:aa:67:88:77:a0:96:cc:35:2d:35: 18 | 49:6b:5a:38:19:78:3c:fc:c3:5e:1a:88:f0:18:c3: 19 | 1b:fd:e0:ab:34:4c:97:28:38:54:7c:71:1e:a5:46: 20 | 37:b2:37:b0:14:d2:00:8e:0b:05:b9:ac:68:3c:fd: 21 | 62:b0:62:db:fa:eb:e3:f5:bf:7c:58:c6:ec:7c:c9: 22 | bd:39:75:59:95:e0:58:24:2a:86:3e:16:85:ed:4c: 23 | 5d:38:4c:b5:77:77:ed:56:97:01:44:12:98:f6:1e: 24 | 64:27:71:47:8d:93:9d:51:33:0c:6b:0d:ca:2a:66: 25 | bc:4c:a8:50:b0:1b:9d:1b:41:a5:59:70:da:cd:8a: 26 | b2:c0:4c:f8:cf:29:2c:82:85:be:ca:84:2c:e0:8d: 27 | 9f:f4:e8:2c:c6:3b:42:4d:20:09:0c:a0:4a:77:65: 28 | 64:d2:b2:69:25:b6:32:ff:99:5f:db:f1:24:9f:91: 29 | fd:7f:ad:e7:77:c0:65:f5:d1:be:5e:2a:99:6f:5f: 30 | 92:ed:44:de:2a:f8:19:9c:53:8e:23:da:b4:bb:8e: 31 | 72:60:92:fc:d4:72:c3:f1:2b:fb:65:c4:ef:3a:37: 32 | 30:3f 33 | Exponent: 65537 (0x10001) 34 | Signature Algorithm: sha256WithRSAEncryption 35 | 22:2d:41:6d:d3:e1:e7:aa:a8:7d:e5:af:58:51:a6:44:8b:a5: 36 | 45:cc:a2:d6:14:83:c8:20:5f:e5:5b:d3:70:d5:99:0c:69:02: 37 | 09:6e:ae:58:12:b7:b7:0b:cb:31:f6:3b:4f:c4:cb:82:de:14: 38 | 14:4d:c1:b1:81:91:ca:1a:38:9f:7d:6c:88:da:31:98:72:11: 39 | 56:88:90:47:76:ac:5d:b8:3f:0b:78:6a:e6:04:a8:0c:82:79: 40 | 1e:52:7b:37:ed:d4:f8:3b:70:7f:6f:0b:0f:f8:b5:86:36:91: 41 | b6:91:99:7e:08:65:62:e7:ec:a8:f7:e3:d4:4b:04:08:c5:e8: 42 | 4c:7f:4d:7b:4e:bf:7f:3f:e2:5a:95:61:9f:36:73:68:c9:a4: 43 | 13:cd:a2:51:fd:f1:46:d9:29:5c:12:8c:a2:1a:78:92:a0:ad: 44 | 6b:02:39:32:1d:d4:e6:7f:53:95:99:52:fc:23:9a:81:24:3f: 45 | b0:15:8e:9f:66:45:df:6d:b6:64:e9:3f:ea:e6:1b:05:02:70: 46 | e1:21:02:aa:66:a2:46:84:34:22:82:df:34:c5:36:b2:e7:10: 47 | 7f:d2:1a:df:64:18:aa:cc:9e:47:af:1e:66:1f:6e:dd:be:5c: 48 | 0b:ca:d0:07:40:98:20:d5:af:78:f3:e2:b0:5f:c9:d7:c4:40: 49 | c6:05:4b:33 50 | -----BEGIN CERTIFICATE----- 51 | MIICrjCCAZagAwIBAgIBAzANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDDA5NeSBD 52 | b21tb24gTmFtZTAgFw0xODA0MjkwNzU4MzJaGA8yMTE4MDQwNTA3NTgzMlowGjEY 53 | MBYGA1UEAwwPTm8gYW55IEtVIGZpZWxkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 54 | MIIBCgKCAQEAnO4OpkSWOIpVnRKUSNU13QXOoNHpXzgfON7joSy0wJFTkapniHeg 55 | lsw1LTVJa1o4GXg8/MNeGojwGMMb/eCrNEyXKDhUfHEepUY3sjewFNIAjgsFuaxo 56 | PP1isGLb+uvj9b98WMbsfMm9OXVZleBYJCqGPhaF7UxdOEy1d3ftVpcBRBKY9h5k 57 | J3FHjZOdUTMMaw3KKma8TKhQsBudG0GlWXDazYqywEz4zyksgoW+yoQs4I2f9Ogs 58 | xjtCTSAJDKBKd2Vk0rJpJbYy/5lf2/Ekn5H9f63nd8Bl9dG+XiqZb1+S7UTeKvgZ 59 | nFOOI9q0u45yYJL81HLD8Sv7ZcTvOjcwPwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB 60 | AQAiLUFt0+Hnqqh95a9YUaZEi6VFzKLWFIPIIF/lW9Nw1ZkMaQIJbq5YEre3C8sx 61 | 9jtPxMuC3hQUTcGxgZHKGjiffWyI2jGYchFWiJBHdqxduD8LeGrmBKgMgnkeUns3 62 | 7dT4O3B/bwsP+LWGNpG2kZl+CGVi5+yo9+PUSwQIxehMf017Tr9/P+JalWGfNnNo 63 | yaQTzaJR/fFG2SlcEoyiGniSoK1rAjkyHdTmf1OVmVL8I5qBJD+wFY6fZkXfbbZk 64 | 6T/q5hsFAnDhIQKqZqJGhDQigt80xTay5xB/0hrfZBiqzJ5Hrx5mH27dvlwLytAH 65 | QJgg1a948+KwX8nXxEDGBUsz 66 | -----END CERTIFICATE----- 67 | -------------------------------------------------------------------------------- /tests/data/test_extensions/no-ku.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_extensions/no-ku.jar -------------------------------------------------------------------------------- /tests/data/test_extensions/privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCc7g6mRJY4ilWd 3 | EpRI1TXdBc6g0elfOB843uOhLLTAkVORqmeId6CWzDUtNUlrWjgZeDz8w14aiPAY 4 | wxv94Ks0TJcoOFR8cR6lRjeyN7AU0gCOCwW5rGg8/WKwYtv66+P1v3xYxux8yb05 5 | dVmV4FgkKoY+FoXtTF04TLV3d+1WlwFEEpj2HmQncUeNk51RMwxrDcoqZrxMqFCw 6 | G50bQaVZcNrNirLATPjPKSyChb7KhCzgjZ/06CzGO0JNIAkMoEp3ZWTSsmkltjL/ 7 | mV/b8SSfkf1/red3wGX10b5eKplvX5LtRN4q+BmcU44j2rS7jnJgkvzUcsPxK/tl 8 | xO86NzA/AgMBAAECggEAL/KslzCtlWju76cVl4tNgdKcZ5a7b1R+dankcwJt18iP 9 | eBpQt+mVL34FYWK+pAZUzbNnLvOidQkSEv7KNq/Gn5wnMyrC5aLKckUaD2HkcvgX 10 | I09K2IhM8RWaabpK7EfWxudS3u0opJgfMMciMCDzzVkQ2zeWhAKpGOKXL4F9Cs9u 11 | GRE0DNkdDUBm+ZHUXpNQOSB53U7Y+uNiKck76zUR8vu9YNP01Ch8x6Xb0yYNcoPK 12 | QC/8E1GLBtjSkuTH65CNq+BuFhtyje6G+gxZLtjzGjnvgqAyjxnZvq73kA0z4Z8m 13 | AT5Iv7PeWSDrZ/UUSqpv4mxd9UzLDWIyPOQv23HDwQKBgQDMuLw1xMk5zpxqsSeC 14 | 1KIbC1EkLKlVALzUDf/otrSP4SBieor/d3AW624csbkjjGFiQDfJ4gMYujzM/8gN 15 | hqrjj/g0HniOPEAB+SPeuF6UVdyAbBzDkyrA0sJNEACr6sUmbzKtAtyDUZhpgTZa 16 | AHm90aQkV0JYpNbCy3TkdTl9cwKBgQDEPMwlPNLxMeV62qxcJLbNAj8drxRcbtfI 17 | 9+AbOhfpFLnPnFCHgiwioR1OS02sNqdiWtxGvbpzKOOkthV3YGqyvLLrEmdcLDwj 18 | Nd+GUHHpiQ5ylfllkFqeyfe8mAygUE0BMtep+MvwITc/7qC4a4aB3nNKMzUej/kt 19 | KM4W18oPBQKBgQDGXWIQ/4Kzfp1VTB6qyHnilo6i7JuO/8338zC6Pv6qQ0tr4K16 20 | aDK2Ip1pNFPePBHIb80e0t6JQTvUrysa4BgJs+CeL8BEoeCriMrW7fLG7INh9F/S 21 | qXDNseoPXago7KznVuvVdGZS3+c8o7UUdE2CPfY8OEjTN7XYveefzm5MPQKBgFmE 22 | gnvaKz/rywsoBchi1yDeDXy1CUzBI56BtLG25oFk+v5CCFpIf2mspXm50EznAaRU 23 | XnfGxO8TkATrKw+x4/p1Kgkh9BSP+T72rGjQ+aXW58hNsd8q4qvc5i4aDmhzOS16 24 | y/a1kBKSlGmNqbN3GXzUxTLr+Sdf9gMrwheZiIshAoGAC6ggL2A467q5xrMFI081 25 | 3qJX4+/0YOK25ThQJh/ep9MokbBlM7keWFaZ9svAvABIl8O/BtP/jwwUd/SRBMmG 26 | wHI4RKldAcEWohIsFUNdOy1ommPwwdl7wIGlKUS6HXodzm6VDl0aQDrixn1Q74Or 27 | C+kXxGUf/+xS4dU8lfW2940= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/data/test_extensions/wrong-ku-cert.pem: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 2 (0x2) 5 | Signature Algorithm: sha256WithRSAEncryption 6 | Issuer: CN=My Common Name 7 | Validity 8 | Not Before: Apr 29 07:46:38 2018 GMT 9 | Not After : Apr 5 07:46:38 2118 GMT 10 | Subject: CN=keyEncipherment in KeyUsage 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:9c:ee:0e:a6:44:96:38:8a:55:9d:12:94:48:d5: 16 | 35:dd:05:ce:a0:d1:e9:5f:38:1f:38:de:e3:a1:2c: 17 | b4:c0:91:53:91:aa:67:88:77:a0:96:cc:35:2d:35: 18 | 49:6b:5a:38:19:78:3c:fc:c3:5e:1a:88:f0:18:c3: 19 | 1b:fd:e0:ab:34:4c:97:28:38:54:7c:71:1e:a5:46: 20 | 37:b2:37:b0:14:d2:00:8e:0b:05:b9:ac:68:3c:fd: 21 | 62:b0:62:db:fa:eb:e3:f5:bf:7c:58:c6:ec:7c:c9: 22 | bd:39:75:59:95:e0:58:24:2a:86:3e:16:85:ed:4c: 23 | 5d:38:4c:b5:77:77:ed:56:97:01:44:12:98:f6:1e: 24 | 64:27:71:47:8d:93:9d:51:33:0c:6b:0d:ca:2a:66: 25 | bc:4c:a8:50:b0:1b:9d:1b:41:a5:59:70:da:cd:8a: 26 | b2:c0:4c:f8:cf:29:2c:82:85:be:ca:84:2c:e0:8d: 27 | 9f:f4:e8:2c:c6:3b:42:4d:20:09:0c:a0:4a:77:65: 28 | 64:d2:b2:69:25:b6:32:ff:99:5f:db:f1:24:9f:91: 29 | fd:7f:ad:e7:77:c0:65:f5:d1:be:5e:2a:99:6f:5f: 30 | 92:ed:44:de:2a:f8:19:9c:53:8e:23:da:b4:bb:8e: 31 | 72:60:92:fc:d4:72:c3:f1:2b:fb:65:c4:ef:3a:37: 32 | 30:3f 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Basic Constraints: 36 | CA:FALSE 37 | X509v3 Key Usage: 38 | Key Encipherment 39 | Signature Algorithm: sha256WithRSAEncryption 40 | 46:be:e7:07:28:7a:71:a1:91:4d:3e:5a:b5:01:be:25:d4:72: 41 | 22:7a:12:aa:62:f7:ee:5a:af:c0:f7:2e:2d:f9:b6:38:0d:dd: 42 | 87:78:c0:5b:c8:5f:76:0f:cb:1b:8b:be:13:9a:86:dc:73:93: 43 | 00:bd:46:46:da:b0:dd:67:c5:ea:85:66:be:48:8e:4b:0b:35: 44 | d1:c4:bd:11:f9:a1:1b:4e:58:69:b6:42:16:6c:94:a7:4a:ea: 45 | 42:0a:d7:54:93:4c:74:17:a1:2e:a7:d7:40:c0:ea:40:2e:37: 46 | 5d:a3:5e:10:b4:41:7b:68:96:5d:da:a9:72:fc:81:5e:6c:c8: 47 | 5c:0f:5f:e3:4b:6b:3e:46:fc:b8:96:98:8d:16:d9:c8:dc:6e: 48 | da:69:d3:7a:b4:b9:f2:1b:bd:a5:3b:40:27:e0:a3:64:81:ca: 49 | 0d:b4:59:76:9b:68:93:23:6a:7c:51:10:65:2e:45:b8:92:0d: 50 | 77:93:32:5b:48:4d:2f:fa:1b:bb:4c:eb:3d:d3:e6:de:63:96: 51 | 37:76:45:bd:13:df:5e:59:5c:77:59:5e:9e:b3:b7:91:48:c8: 52 | 7d:2b:b4:e5:10:8b:76:23:06:95:f8:4b:41:94:ee:c6:d7:34: 53 | a0:b3:8e:e7:31:7d:a1:53:ad:95:48:b3:0c:ad:82:a7:ae:3b: 54 | 6a:eb:7a:9a 55 | -----BEGIN CERTIFICATE----- 56 | MIIC1jCCAb6gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDDA5NeSBD 57 | b21tb24gTmFtZTAgFw0xODA0MjkwNzQ2MzhaGA8yMTE4MDQwNTA3NDYzOFowJjEk 58 | MCIGA1UEAwwba2V5RW5jaXBoZXJtZW50IGluIEtleVVzYWdlMIIBIjANBgkqhkiG 59 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnO4OpkSWOIpVnRKUSNU13QXOoNHpXzgfON7j 60 | oSy0wJFTkapniHeglsw1LTVJa1o4GXg8/MNeGojwGMMb/eCrNEyXKDhUfHEepUY3 61 | sjewFNIAjgsFuaxoPP1isGLb+uvj9b98WMbsfMm9OXVZleBYJCqGPhaF7UxdOEy1 62 | d3ftVpcBRBKY9h5kJ3FHjZOdUTMMaw3KKma8TKhQsBudG0GlWXDazYqywEz4zyks 63 | goW+yoQs4I2f9OgsxjtCTSAJDKBKd2Vk0rJpJbYy/5lf2/Ekn5H9f63nd8Bl9dG+ 64 | XiqZb1+S7UTeKvgZnFOOI9q0u45yYJL81HLD8Sv7ZcTvOjcwPwIDAQABoxowGDAJ 65 | BgNVHRMEAjAAMAsGA1UdDwQEAwIFIDANBgkqhkiG9w0BAQsFAAOCAQEARr7nByh6 66 | caGRTT5atQG+JdRyInoSqmL37lqvwPcuLfm2OA3dh3jAW8hfdg/LG4u+E5qG3HOT 67 | AL1GRtqw3WfF6oVmvkiOSws10cS9EfmhG05YabZCFmyUp0rqQgrXVJNMdBehLqfX 68 | QMDqQC43XaNeELRBe2iWXdqpcvyBXmzIXA9f40trPkb8uJaYjRbZyNxu2mnTerS5 69 | 8hu9pTtAJ+CjZIHKDbRZdptokyNqfFEQZS5FuJINd5MyW0hNL/obu0zrPdPm3mOW 70 | N3ZFvRPfXllcd1lenrO3kUjIfSu05RCLdiMGlfhLQZTuxtc0oLOO5zF9oVOtlUiz 71 | DK2Cp647aut6mg== 72 | -----END CERTIFICATE----- 73 | -------------------------------------------------------------------------------- /tests/data/test_extensions/wrong-ku.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_extensions/wrong-ku.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/ec-copied.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/ec-copied.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/ec-sig-block-removed.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/ec-sig-block-removed.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/ec-sig-mf-tampered.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/ec-sig-mf-tampered.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/ec-tampered.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/ec-tampered.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/ec.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/ec.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/generic1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/generic1.jar -------------------------------------------------------------------------------- /tests/data/test_jardiff/generic2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jardiff/generic2.jar -------------------------------------------------------------------------------- /tests/data/test_jarinfo/Sample.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarinfo/Sample.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/ec-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB4TCCAUKgAwIBAgIBATAKBggqhkjOPQQDBDANMQswCQYDVQQGEwJVUzAeFw0x 3 | NDEyMDExNTM5NThaFw0yNDExMjgxNTM5NThaMA0xCzAJBgNVBAYTAlVTMIGbMBAG 4 | ByqGSM49AgEGBSuBBAAjA4GGAAQAEdZUdeHPX0akwMaUwPSJ9v+NjKRodLjrTXdy 5 | lKq9wT1AADJlh5sNvxq9isbEGg/vYHfDaEJJNiT+OMR8Af9QORoAG3whPzFdQSPj 6 | b2zAK40AZbo1ikoBeMKIGhIUqEMgmVlsjG8Bop3LJiDFAy4T/rW6855wPyReD1Eo 7 | 5gJED2JuJeqjUDBOMB0GA1UdDgQWBBQrdf7dWoB9rvUKM8pZjcbR7q0HUjAfBgNV 8 | HSMEGDAWgBQrdf7dWoB9rvUKM8pZjcbR7q0HUjAMBgNVHRMEBTADAQH/MAoGCCqG 9 | SM49BAMEA4GMADCBiAJCAdgJ28pvdPK3eJ4pbOvb3ScEWdVDF6nmhyaW2nUtEiDk 10 | 0y0fPALrE0PrJVLnY1G/40ld4mB0AmUqMBPIJiRip0AIAkIBiHSKPtS31B45uPbf 11 | n43GDd5HOPesac7KXjqLz2L1KmdkDmn83sMkOK/532+69S29MUNrV8pOIie7fENP 12 | xAMTNVQ= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/ec-must-fail.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/ec-must-fail.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/ec-tampered.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/ec-tampered.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/ec.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/ec.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/jarutil-signed-by-jarsigner.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/jarutil-signed-by-jarsigner.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/jarutil-signed.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/jarutil-signed.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/javatools-cert-2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIELzCCAxegAwIBAgIJALYxaX0mZjcTMA0GCSqGSIb3DQEBCwUAMIGsMQswCQYD 3 | VQQGEwJVUzEWMBQGA1UECAwNTW91bnRhaW4gVmlldzETMBEGA1UEBwwKQ2FsaWZv 4 | cm5pYTEZMBcGA1UECgwQcHl0aG9uLWphdmF0b29sczESMBAGA1UECwwJamF2YXRv 5 | b2xzMRswGQYDVQQDDBJweXRob24tamF2YXRvb2xzLTIxJDAiBgkqhkiG9w0BCQEW 6 | FWJtdXJyYXk3amh1QGdtYWlsLmNvbTAgFw0xNzA2MTUyMDI3NDVaGA8yMjg4MDYx 7 | NTIwMjc0NVowgawxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1Nb3VudGFpbiBWaWV3 8 | MRMwEQYDVQQHDApDYWxpZm9ybmlhMRkwFwYDVQQKDBBweXRob24tamF2YXRvb2xz 9 | MRIwEAYDVQQLDAlqYXZhdG9vbHMxGzAZBgNVBAMMEnB5dGhvbi1qYXZhdG9vbHMt 10 | MjEkMCIGCSqGSIb3DQEJARYVYm11cnJheTdqaHVAZ21haWwuY29tMIIBIjANBgkq 11 | hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4uEkNOPZbuCClN86ErI67q5Go31qyU2r 12 | cCzYiO7zikcxdKfjBZ1+7GKah/6qK3on4Tlaexxhl3+AjC+8KuaFo1674aeb3xul 13 | dA7n8vmAaJAesyeGPK4tSbDggs0tIo1YoN/WSNArrDLtZ4gRexXYXxYanKqAjL2O 14 | TG0RJxJV3jbkcoRvc86/SqEJswzDtIVY4baepmAt7GFk2yLj2bLRXdNIca6YghuZ 15 | Dkq17JZopHXPedHNevMMF3WFL3oAZRfUHLB168Uw4vZfVKU+2W6PeHAIGEZjIEU1 16 | UN9CSNG3AhnhRMD40Cxre4tIJT2d9fTaXd+zujIVnpAXkQrmTchhxQIDAQABo1Aw 17 | TjAdBgNVHQ4EFgQUdSY1U4kKhQRPowAum8CGHHEsXLcwHwYDVR0jBBgwFoAUdSY1 18 | U4kKhQRPowAum8CGHHEsXLcwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC 19 | AQEAkhuBVODJ7uebS1uIB1Mo2Ad1Tt9X6RUKHyo5GkJYrfEtGu+Gkc+K63kUW+X9 20 | I5kDi7+zINLSkHlg0RaRcKeBKBCNw4h7huOfbVtVXCnBbY04S6ZaPtrpZ1Shq169 21 | +p4zxNJ4povKeGKg1g6lSKlTTfgf+p+B2zAdHMpCKIf7v6ebkZgmiwt1sPajq4Y2 22 | RrG2dv6KlLbM/Y4KG9yn7443FzUejFNJgwTy6RfvIl7tw04I4SBiBiEwgiWe6pFz 23 | P5b0hi5BtSH2ypK13PhET7uxUyRcOHVBipXhlkl4cmYSPsauVnx7ZdydVOVCE/EV 24 | LL81Ex0LWT3NmfVyvdl9ce9pNg== 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/javatools-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDHDCCAoWgAwIBAgIJAIDa20BvHLGsMA0GCSqGSIb3DQEBBQUAMIGlMQswCQYD 3 | VQQGEwJVUzEXMBUGA1UECAwOTm9ydGgtQ2Fyb2xpbmExEDAOBgNVBAcMB1JhbGVp 4 | Z2gxGTAXBgNVBAoMEHB5dGhvbi1qYXZhdG9vbHMxEjAQBgNVBAsMCWphdmF0b29s 5 | czEZMBcGA1UEAwwQcHl0aG9uLWphdmF0b29sczEhMB8GCSqGSIb3DQEJARYSb2Jy 6 | aWVuY2pAZ21haWwuY29tMCAXDTE0MDkwNzIwMjc0NVoYDzIyODgwNjIxMjAyNzQ1 7 | WjCBpTELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoLUNhcm9saW5hMRAwDgYD 8 | VQQHDAdSYWxlaWdoMRkwFwYDVQQKDBBweXRob24tamF2YXRvb2xzMRIwEAYDVQQL 9 | DAlqYXZhdG9vbHMxGTAXBgNVBAMMEHB5dGhvbi1qYXZhdG9vbHMxITAfBgkqhkiG 10 | 9w0BCQEWEm9icmllbmNqQGdtYWlsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw 11 | gYkCgYEAx2e1usZF3B/mya1MnRtPmr6Z+QMTho70GfzJDgiSflhUpGHZGm2vXVca 12 | 0IhFEl2ApmVwpLm0Z0m67776xBxsMflQoZQRACjiXWgalaLttYkhAWFCBK6iMfH8 13 | ejagP0TpTFO8+ide29x//gwx9fps7chwToRAqqRRybLtWzolN6cCAwEAAaNQME4w 14 | HQYDVR0OBBYEFLSwxhAmPDBFMniZEFyTiJkkkKiuMB8GA1UdIwQYMBaAFLSwxhAm 15 | PDBFMniZEFyTiJkkkKiuMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA 16 | knR0ngS8tlF7WDz3xYm0yibAia3CvHpOpm17nFl+04kWlOpP5vK8FM/ZZsnGHpTt 17 | aoN9e7GM1b1x3dmiLAdd7j5jwNQCzccWJFYXAW+NFzOsmFZHQ7n00SP12S6LKfXo 18 | PH8pLFd9V6ZqgSMxijUkbFY3GRjrKz0EOjzMnSJAsD8= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/multiple-sf-files-all-valid.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/multiple-sf-files-all-valid.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/multiple-sf-files-some-junk.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/multiple-sf-files-some-junk.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/several-manifest-attributes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/several-manifest-attributes.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/sig-related-junk-files-ok.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/sig-related-junk-files-ok.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/tampered-entry.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/tampered-entry.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/tampered-manifest.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/tampered-manifest.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_dir/empty_dir/unused: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_dir/empty_dir/unused -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_dir/example2_dir/example3_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_dir/example2_dir/example3_file -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_dir/example2_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_dir/example2_file -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_create_jar__test_cli_create/example_file: -------------------------------------------------------------------------------- 1 | Unused data 2 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_and_verify__cli-sign-and-verify.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_cli_sign_and_verify__cli-sign-and-verify.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_and_verify__javatools-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDHDCCAoWgAwIBAgIJAIDa20BvHLGsMA0GCSqGSIb3DQEBBQUAMIGlMQswCQYD 3 | VQQGEwJVUzEXMBUGA1UECAwOTm9ydGgtQ2Fyb2xpbmExEDAOBgNVBAcMB1JhbGVp 4 | Z2gxGTAXBgNVBAoMEHB5dGhvbi1qYXZhdG9vbHMxEjAQBgNVBAsMCWphdmF0b29s 5 | czEZMBcGA1UEAwwQcHl0aG9uLWphdmF0b29sczEhMB8GCSqGSIb3DQEJARYSb2Jy 6 | aWVuY2pAZ21haWwuY29tMCAXDTE0MDkwNzIwMjc0NVoYDzIyODgwNjIxMjAyNzQ1 7 | WjCBpTELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoLUNhcm9saW5hMRAwDgYD 8 | VQQHDAdSYWxlaWdoMRkwFwYDVQQKDBBweXRob24tamF2YXRvb2xzMRIwEAYDVQQL 9 | DAlqYXZhdG9vbHMxGTAXBgNVBAMMEHB5dGhvbi1qYXZhdG9vbHMxITAfBgkqhkiG 10 | 9w0BCQEWEm9icmllbmNqQGdtYWlsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw 11 | gYkCgYEAx2e1usZF3B/mya1MnRtPmr6Z+QMTho70GfzJDgiSflhUpGHZGm2vXVca 12 | 0IhFEl2ApmVwpLm0Z0m67776xBxsMflQoZQRACjiXWgalaLttYkhAWFCBK6iMfH8 13 | ejagP0TpTFO8+ide29x//gwx9fps7chwToRAqqRRybLtWzolN6cCAwEAAaNQME4w 14 | HQYDVR0OBBYEFLSwxhAmPDBFMniZEFyTiJkkkKiuMB8GA1UdIwQYMBaAFLSwxhAm 15 | PDBFMniZEFyTiJkkkKiuMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA 16 | knR0ngS8tlF7WDz3xYm0yibAia3CvHpOpm17nFl+04kWlOpP5vK8FM/ZZsnGHpTt 17 | aoN9e7GM1b1x3dmiLAdd7j5jwNQCzccWJFYXAW+NFzOsmFZHQ7n00SP12S6LKfXo 18 | PH8pLFd9V6ZqgSMxijUkbFY3GRjrKz0EOjzMnSJAsD8= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_and_verify__javatools.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMdntbrGRdwf5smt 3 | TJ0bT5q+mfkDE4aO9Bn8yQ4Ikn5YVKRh2Rptr11XGtCIRRJdgKZlcKS5tGdJuu++ 4 | +sQcbDH5UKGUEQAo4l1oGpWi7bWJIQFhQgSuojHx/Ho2oD9E6UxTvPonXtvcf/4M 5 | MfX6bO3IcE6EQKqkUcmy7Vs6JTenAgMBAAECgYEAwkyxDJy0Z8iCBlQiChgZmixN 6 | NhGkTgIvor7pXg5GSGxjlYVumcz1CpucmkOeIkYP3JONjkURn299gqzyBnO3i8Uo 7 | sBxrYNB0+2T5ZNtvsK1J8gc1dZ5O5KULGw5ov0w8/NG06/ZYvd0B9PHEgZj61HLt 8 | 4Ln5iKB0mEA0riTWRUECQQDxG/ozpOTQaw2mYzeDitVmeeCQ531Z+BKWyNG3aql9 9 | gcaSMd70ly19UidtQSuo0vqsjsezUbZBVX9XuMuO8IehAkEA07hf+6FZ53AXnPnn 10 | Ji/g9AgZvd73ENld4+l3YfUpChcUvoimcKdMBSZA+/rRpiJGueE3HwQy89oOY5Jw 11 | SiFaRwJACCvHjep/qqSGIOZp4jZZRxDIUIDX2a2zi5KgsNOXjN5SCXBROv7Ilt+q 12 | 4GP+A8mqnyBzmhshzxMDrshfdaenIQJBAJQjzgUjQOTPabZMpY/ysFQP1vMjr3v6 13 | m9d85CuGftCwlbM7qjno1ShFO/MT7N1x3krxasApD/3P9YF2VVuJOsECQCO+yJ0U 14 | t4aWCauVwyw71VzAxou+1pqDt920PHIM0bAgHAFhwNbF0U8m4glTI6jZYrANHhMe 15 | xvc6PLRvjyCjlwY= 16 | -----END PRIVATE KEY----- 17 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_and_verify_ecdsa_pkcs8_sha512__cli-sign-and-verify.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_cli_sign_and_verify_ecdsa_pkcs8_sha512__cli-sign-and-verify.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_and_verify_ecdsa_pkcs8_sha512__ec-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB4TCCAUKgAwIBAgIBATAKBggqhkjOPQQDBDANMQswCQYDVQQGEwJVUzAeFw0x 3 | NDEyMDExNTM5NThaFw0yNDExMjgxNTM5NThaMA0xCzAJBgNVBAYTAlVTMIGbMBAG 4 | ByqGSM49AgEGBSuBBAAjA4GGAAQAEdZUdeHPX0akwMaUwPSJ9v+NjKRodLjrTXdy 5 | lKq9wT1AADJlh5sNvxq9isbEGg/vYHfDaEJJNiT+OMR8Af9QORoAG3whPzFdQSPj 6 | b2zAK40AZbo1ikoBeMKIGhIUqEMgmVlsjG8Bop3LJiDFAy4T/rW6855wPyReD1Eo 7 | 5gJED2JuJeqjUDBOMB0GA1UdDgQWBBQrdf7dWoB9rvUKM8pZjcbR7q0HUjAfBgNV 8 | HSMEGDAWgBQrdf7dWoB9rvUKM8pZjcbR7q0HUjAMBgNVHRMEBTADAQH/MAoGCCqG 9 | SM49BAMEA4GMADCBiAJCAdgJ28pvdPK3eJ4pbOvb3ScEWdVDF6nmhyaW2nUtEiDk 10 | 0y0fPALrE0PrJVLnY1G/40ld4mB0AmUqMBPIJiRip0AIAkIBiHSKPtS31B45uPbf 11 | n43GDd5HOPesac7KXjqLz2L1KmdkDmn83sMkOK/532+69S29MUNrV8pOIie7fENP 12 | xAMTNVQ= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_and_verify_ecdsa_pkcs8_sha512__ec-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BgUrgQQAIw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MIHbAgEBBEF4SYHZe8pllm6zO3/yKxOGPVp/XWahU6ZZuWwzL1LqCDeOKPJ6SzyN 6 | Zhk7QYuWTwue+QDLy1Gqn/2CkaVFI8M/xKAHBgUrgQQAI6GBiQOBhgAEABHWVHXh 7 | z19GpMDGlMD0ifb/jYykaHS46013cpSqvcE9QAAyZYebDb8avYrGxBoP72B3w2hC 8 | STYk/jjEfAH/UDkaABt8IT8xXUEj429swCuNAGW6NYpKAXjCiBoSFKhDIJlZbIxv 9 | AaKdyyYgxQMuE/61uvOecD8kXg9RKOYCRA9ibiXq 10 | -----END EC PRIVATE KEY----- 11 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_new_file_and_verify__cli-sign-and-verify.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_cli_sign_new_file_and_verify__cli-sign-and-verify.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_new_file_and_verify__javatools-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDHDCCAoWgAwIBAgIJAIDa20BvHLGsMA0GCSqGSIb3DQEBBQUAMIGlMQswCQYD 3 | VQQGEwJVUzEXMBUGA1UECAwOTm9ydGgtQ2Fyb2xpbmExEDAOBgNVBAcMB1JhbGVp 4 | Z2gxGTAXBgNVBAoMEHB5dGhvbi1qYXZhdG9vbHMxEjAQBgNVBAsMCWphdmF0b29s 5 | czEZMBcGA1UEAwwQcHl0aG9uLWphdmF0b29sczEhMB8GCSqGSIb3DQEJARYSb2Jy 6 | aWVuY2pAZ21haWwuY29tMCAXDTE0MDkwNzIwMjc0NVoYDzIyODgwNjIxMjAyNzQ1 7 | WjCBpTELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoLUNhcm9saW5hMRAwDgYD 8 | VQQHDAdSYWxlaWdoMRkwFwYDVQQKDBBweXRob24tamF2YXRvb2xzMRIwEAYDVQQL 9 | DAlqYXZhdG9vbHMxGTAXBgNVBAMMEHB5dGhvbi1qYXZhdG9vbHMxITAfBgkqhkiG 10 | 9w0BCQEWEm9icmllbmNqQGdtYWlsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw 11 | gYkCgYEAx2e1usZF3B/mya1MnRtPmr6Z+QMTho70GfzJDgiSflhUpGHZGm2vXVca 12 | 0IhFEl2ApmVwpLm0Z0m67776xBxsMflQoZQRACjiXWgalaLttYkhAWFCBK6iMfH8 13 | ejagP0TpTFO8+ide29x//gwx9fps7chwToRAqqRRybLtWzolN6cCAwEAAaNQME4w 14 | HQYDVR0OBBYEFLSwxhAmPDBFMniZEFyTiJkkkKiuMB8GA1UdIwQYMBaAFLSwxhAm 15 | PDBFMniZEFyTiJkkkKiuMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA 16 | knR0ngS8tlF7WDz3xYm0yibAia3CvHpOpm17nFl+04kWlOpP5vK8FM/ZZsnGHpTt 17 | aoN9e7GM1b1x3dmiLAdd7j5jwNQCzccWJFYXAW+NFzOsmFZHQ7n00SP12S6LKfXo 18 | PH8pLFd9V6ZqgSMxijUkbFY3GRjrKz0EOjzMnSJAsD8= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_cli_sign_new_file_and_verify__javatools.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMdntbrGRdwf5smt 3 | TJ0bT5q+mfkDE4aO9Bn8yQ4Ikn5YVKRh2Rptr11XGtCIRRJdgKZlcKS5tGdJuu++ 4 | +sQcbDH5UKGUEQAo4l1oGpWi7bWJIQFhQgSuojHx/Ho2oD9E6UxTvPonXtvcf/4M 5 | MfX6bO3IcE6EQKqkUcmy7Vs6JTenAgMBAAECgYEAwkyxDJy0Z8iCBlQiChgZmixN 6 | NhGkTgIvor7pXg5GSGxjlYVumcz1CpucmkOeIkYP3JONjkURn299gqzyBnO3i8Uo 7 | sBxrYNB0+2T5ZNtvsK1J8gc1dZ5O5KULGw5ov0w8/NG06/ZYvd0B9PHEgZj61HLt 8 | 4Ln5iKB0mEA0riTWRUECQQDxG/ozpOTQaw2mYzeDitVmeeCQ531Z+BKWyNG3aql9 9 | gcaSMd70ly19UidtQSuo0vqsjsezUbZBVX9XuMuO8IehAkEA07hf+6FZ53AXnPnn 10 | Ji/g9AgZvd73ENld4+l3YfUpChcUvoimcKdMBSZA+/rRpiJGueE3HwQy89oOY5Jw 11 | SiFaRwJACCvHjep/qqSGIOZp4jZZRxDIUIDX2a2zi5KgsNOXjN5SCXBROv7Ilt+q 12 | 4GP+A8mqnyBzmhshzxMDrshfdaenIQJBAJQjzgUjQOTPabZMpY/ysFQP1vMjr3v6 13 | m9d85CuGftCwlbM7qjno1ShFO/MT7N1x3krxasApD/3P9YF2VVuJOsECQCO+yJ0U 14 | t4aWCauVwyw71VzAxou+1pqDt920PHIM0bAgHAFhwNbF0U8m4glTI6jZYrANHhMe 15 | xvc6PLRvjyCjlwY= 16 | -----END PRIVATE KEY----- 17 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_sign_with_certchain_and_verify__certchain-data.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/test_sign_with_certchain_and_verify__certchain-data.jar -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_sign_with_certchain_and_verify__certchain-intermediate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDtDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJGSTET 3 | MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ 4 | dHkgTHRkMRYwFAYDVQQDDA1Sb290IG9mIHRydXN0MCAXDTE2MTExNzE4MzMyNFoY 5 | DzIxMTYxMDI0MTgzMzI0WjBcMQswCQYDVQQGEwJGSTETMBEGA1UECAwKU29tZS1T 6 | dGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYDVQQD 7 | DAxJbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK 8 | fCN1xSKArypFDQE7Ruo+YlWx1bq7py3lwLDdqTwk4g3dpbXOgYg34r7Ywg+r/8jc 9 | 0qbu54YV/NE4TAXeFYh84Nm70nQ8dn0bFkpc2du+Jxb0jn4N2+FIfn/3VZylm2KM 10 | zLoYtratAgDPkYHHhcoXHNSvtHG8+Te336SegXIf/NP2qoNKlpx2AvD6KbgzuZhY 11 | OZWPlokTQeTpcTN19/jKJ1Q8iUbJV9de/ac5gZpp76wBINDNMEn9ZdfruPqNI/i6 12 | 02wRw9I/dxJ8qIIH+6Q+57rGUXXWJjrb0DOGl3kE5ZOOJmYzDN/BuTDVjwBYO5co 13 | bVuE5I9aKrI0CVigI8N1AgMBAAGjfjB8MAwGA1UdEwQFMAMBAf8wLAYJYIZIAYb4 14 | QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBR3 15 | YBBOKvuXLAMP0IJQhCqm0LFXmDAfBgNVHSMEGDAWgBTrEbkjGhq30vmcSVGsTx2c 16 | 4HsBGTANBgkqhkiG9w0BAQsFAAOCAQEAf5abElULwU3DcQYn7OzSVmEvIsv2yWoD 17 | Ubu1W2G58odXaI1zIqeyHws2xQwFiffyvpncOaJxrFBf7qYY3/vnggaaZBq/EJ0B 18 | rgIr26nu5peZMzCOJFkvgM4yGNQ9KrExcLpmAhFv9mgzUNPl6Iq8nTc3iWQVzxae 19 | TNyugJaV8QLsi3pSAMhRRsAdd2dvtsyyhV+Y0EHfLAXF7CjLl04THHBcLtK/qEY6 20 | 157zGi8/sR4pbY8H5+fXaE7MZJfh33Ire6+JftoXmxY6kBVYESTZF7YtI0yd0hxh 21 | 3ZwA46DTBIj/ZtDYU+fEkpQy2cngqdBNC9YKYKzTCoknnluGuJ2BEw== 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_sign_with_certchain_and_verify__certchain-root.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDjzCCAnegAwIBAgIJAMsyLQey+o/TMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV 3 | BAYTAkZJMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQxFjAUBgNVBAMMDVJvb3Qgb2YgdHJ1c3QwIBcNMTYxMTE3 5 | MTgzMTMwWhgPMjExNjEwMjQxODMxMzBaMF0xCzAJBgNVBAYTAkZJMRMwEQYDVQQI 6 | DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx 7 | FjAUBgNVBAMMDVJvb3Qgb2YgdHJ1c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 8 | ggEKAoIBAQC9iZOrylgI5K4xz4gx9qXpS/bBxVg6hcn7Lq7A1SSBKRsWltlw6jIi 9 | EvWm4fCnUaOPan0y25Nh1lgx1nDLgjzmND+2BHReC84RBQWjLh7dQle+LOhUJ6nz 10 | JpA6Jk/17hpJsHynRtM0XgTE1KLcZEZlKk/aT/itLtvVquTYcq63WMA668In5DB4 11 | g3RNGqmGYQOFP+Z+pzH8rcojPfr5BYAn37xFOZTpDNiZLQzXhGhzU0+NEYzVqukX 12 | nDDua1VjB+BA88DFDlO0gVtKNDhWntNlluNDcinhJTf8fYyJ/PGnabD1R/ocjIWn 13 | YocmpqHJ69SI62WDlrP3s4yMJ+JLGQApAgMBAAGjUDBOMB0GA1UdDgQWBBTrEbkj 14 | Ghq30vmcSVGsTx2c4HsBGTAfBgNVHSMEGDAWgBTrEbkjGhq30vmcSVGsTx2c4HsB 15 | GTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB9aPCT6rX9OQ1ytnUy 16 | BT1g3iH+8j8GAifmUW/GMrcOTRVO5TvchHCOXaFy6VR46SDfU9d9HnBEPn6HiM/Q 17 | m0V6+yYmQUsWQGLf1achJ4AK942rq9I1+PnaOiM5feMakCUuAfM95D4YloeWGM3r 18 | CFh1cn4P1hoOiCKDgXZhNnfseodbdnKDmRUBLc2xJQeIRwKJrYsupTBnkNBKUBFG 19 | 0pkYaHw4JyFZrupKOfJIEeP0cMcAKxwOEm7BnMSOFEwB3cmW9TDM6lT6yvCxVTEC 20 | VrgMDne3/wzAsMJL7ckHR3bdGKM62J8YKyVWVBl/CUdVyplM+4D/0o/AORLKb2rM 21 | FU47 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_sign_with_certchain_and_verify__certchain-signing-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCgR30hNu7xj3q6 3 | PNpMWUog1qbNhTG3umFZph2SPjTtmZugWW8ZSdMHsyEfxzf6TDqBaHVsMgVLnT9o 4 | zLVaotqYLYD33oXNNzJuiyYScmNHlkkjYRfkCPN/gZn/M6HbAi5Q71k9VZlDIGVF 5 | ciFH3TE4tDynl9e6CId4LBIbTJAYnoADTIgc/skL26Z1g4g/H6ot6kxPkLOR9OZl 6 | +8iZnIIcBD9vC4Gg6mACG78So1yFXj9d2KO0l3tsVydzYU9PNkDKbkdXAWU9Ql/v 7 | p2BIEAhipX62w0FmsQijABbFEfDXyvWStzkZ1A8A6vLqKtT3gUlpy4zGTKg1kdCC 8 | kPv3peoJAgMBAAECggEAHo2iJ8u9/uRYA9qHzpgSznG8uF7UnG52Ek3dQzyCgGyQ 9 | wx9pU0vEY6pc/R7P5/HSEUslXyul4MUoCkVDqPR0cR/zfsy3eugzv+jcqBWQIVxf 10 | stPWZwzhxgOhpIlmKEahJ6KIw21m2un5BCT+fSGIOYP6MAR9BiSMFndoODX/HgID 11 | rL8rNcZ+/PsUw9I+hOPCY//2KEW46IDj8c2uWz99+yKpaOMAqbVXQIFp+Bbvrnm+ 12 | dDvLdqgitsMart5scFcwj4PudcFYCgkTfO7XgFhI73bccDH+tZxY2oHbHt/Y+Iwz 13 | mCzSydLp7+nnO3ry8WQZq+0R2QbAFAW3tXwwCYhpdQKBgQDOqZ2aRP4/CRiwNllB 14 | OMJbv2LGsKyln9L51W6Qkyf1jhv0xto/svUlWKXwt7ze0mwXBAJWXG0ViF/EJiM8 15 | 9L4nRZhO4roItoXcyL3QoJK2cALhmoeLfS45cW0lMPv5ooixla1Ku2w9yK24gUkN 16 | ejTWkQdWCwEfATxsjEysNOLWywKBgQDGixypbIKFeO86i/zMxR0pjVIjcPOQFSLW 17 | RrVBg6QLKIXcIp7a7L+0y1blLBmKOznb1hJjq7zyCKZbANPbqp5w9kl7QfnoafGI 18 | lQGb9z8p6Z+FgMFrX0t5DOuzKr1iWZDzLs3Uk8V9GxAFXrGoFuwd7fW/DzdEisqQ 19 | 9QTb+BzT+wKBgQCVCBJEdu6WTJwGLxtMgn7+pNS5jhziz4/YZMb38XcGiLW2XlRz 20 | TT2l8fiwz/+e/EXAjz6UQtDTj2XoUMxmn+Qk8/YzJSOdNurv3b+snK9QaxRY1xRa 21 | TiqweBCKmnmLe19yGQs/8krLf1Vv0aP52SATf8C3lvX3AvAtIzwDj5vp4wKBgA1g 22 | C8NCIxzYw8z+5z3oPYmyEol+r3nSYrFqvAU42BFEXpgw4ODAuD12wVjY+rN8P+6W 23 | YlDCngz0FjjlOmB/AwN7JAIgtLQ6huH7n8shAelR6sQ0o1MXbV8vRqWgSHfartAj 24 | JAyhE9nUu+SQt4kqWie+AyMm5ENC0linmPc0pMSHAoGBAMorDe1sGCWnIBIZj3Od 25 | tdBNxKtXqwGlCgFuoaeApH2uiuVgrcMdHok4pc6U2InLtdoaFiNUVV6sVZw+JuGs 26 | tQnpY6RCtLTRCFX9TCm8XZ/8cxRxlrAPlntWIzTM+vkhooB3Ps3fN8IOeaeYdq5O 27 | c0QXhqWzu3AxHfSENHYPNb3n 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/test_sign_with_certchain_and_verify__certchain-signing.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDrjCCApagAwIBAgIBAjANBgkqhkiG9w0BAQsFADBcMQswCQYDVQQGEwJGSTET 3 | MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ 4 | dHkgTHRkMRUwEwYDVQQDDAxJbnRlcm1lZGlhdGUwIBcNMTYxMTE3MTgzMzUyWhgP 5 | MjExNjEwMjQxODMzNTJaMFcxCzAJBgNVBAYTAkZJMRMwEQYDVQQIDApTb21lLVN0 6 | YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEDAOBgNVBAMM 7 | B1NpZ25pbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgR30hNu7x 8 | j3q6PNpMWUog1qbNhTG3umFZph2SPjTtmZugWW8ZSdMHsyEfxzf6TDqBaHVsMgVL 9 | nT9ozLVaotqYLYD33oXNNzJuiyYScmNHlkkjYRfkCPN/gZn/M6HbAi5Q71k9VZlD 10 | IGVFciFH3TE4tDynl9e6CId4LBIbTJAYnoADTIgc/skL26Z1g4g/H6ot6kxPkLOR 11 | 9OZl+8iZnIIcBD9vC4Gg6mACG78So1yFXj9d2KO0l3tsVydzYU9PNkDKbkdXAWU9 12 | Ql/vp2BIEAhipX62w0FmsQijABbFEfDXyvWStzkZ1A8A6vLqKtT3gUlpy4zGTKg1 13 | kdCCkPv3peoJAgMBAAGjfjB8MAwGA1UdEwQFMAMBAf8wLAYJYIZIAYb4QgENBB8W 14 | HU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBT+eYSx6OsV 15 | oN4XBQL0Up7i1IPHpTAfBgNVHSMEGDAWgBR3YBBOKvuXLAMP0IJQhCqm0LFXmDAN 16 | BgkqhkiG9w0BAQsFAAOCAQEASVdU0Yffb3I/w0acMvdwAfhQ5Lawt3CvgUIPx7qf 17 | RUtctpdOsVBeJM4hu1XZMLPXnrF9ERr0ghhs15Zmz+AVLnemV1c1T1Pmbk7/3GQ2 18 | Als3qwZRYfrvSlTFAFPopXICXfZx8mTlwMzW8ol3JGP9PCvJFO4PmbgsOaKEgZQL 19 | yS70X0MsHpEwrD8KbyEhmQxEqz2t/g1m96CaCSZm+jglR7D+ap+tdp4Wwu8bqiIX 20 | nZOJN12FbonaYE58JGy9U/z/Xegz79k7q69Wr89LFquQ2Ip4r6hRnOCYTn5nAFXO 21 | hvFLip5KsMOr5JCyzxYmF347iCTcg/ytVqf6KqII6UNEJA== 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/data/test_jarutil/wrong-digest-manifest.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_jarutil/wrong-digest-manifest.jar -------------------------------------------------------------------------------- /tests/data/test_manifest/cli-verify-nok.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_manifest/cli-verify-nok.jar -------------------------------------------------------------------------------- /tests/data/test_manifest/cli-verify-ok.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_manifest/cli-verify-ok.jar -------------------------------------------------------------------------------- /tests/data/test_manifest/junk-entries.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_manifest/junk-entries.jar -------------------------------------------------------------------------------- /tests/data/test_manifest/manifest-sample1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_manifest/manifest-sample1.jar -------------------------------------------------------------------------------- /tests/data/test_manifest/manifest.SHA-512.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | Name: example.txt 4 | SHA-512-Digest: Ortmd680rFfAylgo/ZT52IbCbOWajOYOz2d4B5Qj3M/x1vGctlWAXV 5 | YJjm04oacQ3uWVI+7XUR5ankuMyzpGhg== 6 | 7 | Name: filename-which-is-longer-than-80-characters-and-does-not-fit-in- 8 | java-manifest-line.txt 9 | SHA-512-Digest: Y+Iuwvvuur8AXlj7+w7uYHxKpBcEWmigzGN2ewSONVkmjTXnLzZ9Oy 10 | 29Xb3fEvxDl3YroUkmCzeVoDkXE73c1w== 11 | 12 | -------------------------------------------------------------------------------- /tests/data/test_manifest/manifest.SHA1.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | Name: example.txt 4 | SHA1-Digest: 5fpE8rMcH7VTtgIec2DQfV2R/14= 5 | 6 | Name: filename-which-is-longer-than-80-characters-and-does-not-fit-in- 7 | java-manifest-line.txt 8 | SHA1-Digest: dEjYeYpDgBYtS1b5tFLi9vniTno= 9 | 10 | -------------------------------------------------------------------------------- /tests/data/test_manifest/manifest.dos-newlines.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: 1.7.0_51 (Oracle Corporation) 3 | 4 | Name: file.txt 5 | SHA-256-Digest: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= 6 | 7 | -------------------------------------------------------------------------------- /tests/data/test_manifest/manifest.ignores.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | Name: filename-which-is-longer-than-80-characters-and-does-not-fit-in- 4 | java-manifest-line.txt 5 | MD5-Digest: JqsNuQ1y4orQuh4i7lEFEA== 6 | SHA-512-Digest: Y+Iuwvvuur8AXlj7+w7uYHxKpBcEWmigzGN2ewSONVkmjTXnLzZ9Oy 7 | 29Xb3fEvxDl3YroUkmCzeVoDkXE73c1w== 8 | 9 | -------------------------------------------------------------------------------- /tests/data/test_manifest/multi-digests.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obriencj/python-javatools/416a6e47a57cfce80e70cd66af1f24c9436bb7d9/tests/data/test_manifest/multi-digests.jar -------------------------------------------------------------------------------- /tests/data/test_manifest/no-entries.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: 1.7.0_51 (Oracle Corporation) 3 | 4 | -------------------------------------------------------------------------------- /tests/data/test_manifest/one-valid-digest-of-several.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: 1.7.0_51 (Oracle Corporation) 3 | 4 | Name: a 5 | SHA1-Digest: invalid 6 | SHA-256-Digest: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= 7 | SHA-512-Digest: invalid 8 | 9 | -------------------------------------------------------------------------------- /tests/data/test_manifest/one-valid-digest-of-several.sf: -------------------------------------------------------------------------------- 1 | Signature-Version: 1.0 2 | SHA-512-Digest-Manifest-Main-Attributes: invalid 3 | SHA-256-Digest-Manifest: EmL8iefdINcxwq71SODxeLJ6uCWP2KuYEF87kuB0jhU= 4 | SHA-256-Digest-Manifest-Main-Attributes: AQtYHrY4BNvf1XaaJWea5rSY9Ew41 5 | jydwG8dXidfcqw= 6 | SHA-256-Digest-Manifest: invalid 7 | 8 | Name: a 9 | MD5-Digest: invalid 10 | SHA-256-Digest: FjEbPy+7j9mknn4AJVCf3kSMBPZ+AgCa3cY2fhhjuJs= 11 | 12 | -------------------------------------------------------------------------------- /tests/data/test_manifest/sf-no-whole-digest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: 1.7.0_51 (Oracle Corporation) 3 | 4 | Name: a 5 | SHA-256-Digest: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= 6 | 7 | -------------------------------------------------------------------------------- /tests/data/test_manifest/sf-no-whole-digest.sf: -------------------------------------------------------------------------------- 1 | Signature-Version: 1.0 2 | SHA-256-Digest-Manifest-Main-Attributes: AQtYHrY4BNvf1XaaJWea5rSY9Ew41 3 | jydwG8dXidfcqw= 4 | Created-By: python-javatools tester 5 | 6 | Name: a 7 | SHA-256-Digest: mig7TbtfO91Bsd7kLoCfURurltzOXNHG8JKjhBSR/Y0= 8 | 9 | -------------------------------------------------------------------------------- /tests/distdiff.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for javatools/classinfo.py 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | import os 24 | from unittest import TestCase 25 | from . import get_data_fn 26 | from javatools.distdiff import main 27 | 28 | 29 | class DistdiffTest(TestCase): 30 | 31 | # Options from relevant option groups are accepted: 32 | def test_options_accepted(self): 33 | left = get_data_fn(os.path.join("test_distdiff", "dist1")) 34 | right = get_data_fn(os.path.join("test_distdiff", "dist2")) 35 | # General options: 36 | self.assertEqual(1, main(["argv0", "-q", left, right])) 37 | # Distdiff options: 38 | self.assertEqual(1, main(["argv0", "--processes=1", left, right])) 39 | # JAR checking options: 40 | self.assertEqual(1, main(["argv0", "--ignore-jar-signature", left, right])) 41 | # Class checking options: 42 | self.assertEqual(1, main(["argv0", "--ignore-platform-up", left, right])) 43 | # Reporting options: 44 | self.assertEqual(1, main(["argv0", "--report-dir=foo", left, right])) 45 | # JSON reporting options: 46 | self.assertEqual(1, main(["argv0", "--json-indent=4", left, right])) 47 | # HTML reporting options: 48 | self.assertEqual(1, main(["argv0", "--html-copy-data=foo", left, right])) 49 | 50 | def test_changed_text(self): 51 | left = get_data_fn(os.path.join("test_distdiff", "text1")) 52 | right = get_data_fn(os.path.join("test_distdiff", "text2")) 53 | self.assertEqual(1, main(["argv0", left, right])) 54 | 55 | def test_different_manifests(self): 56 | left = get_data_fn(os.path.join("test_distdiff", "mf1")) 57 | right = get_data_fn(os.path.join("test_distdiff", "mf2")) 58 | self.assertEqual(1, main(["argv0", left, right])) 59 | -------------------------------------------------------------------------------- /tests/distinfo.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for javatools/distinfo.py 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | import os 24 | from unittest import TestCase 25 | from . import get_data_fn 26 | from javatools.distinfo import main 27 | 28 | 29 | class DistinfoTest(TestCase): 30 | 31 | dist = get_data_fn(os.path.join("test_distinfo", "dist1")) 32 | 33 | # classinfo-specific option is accepted: 34 | def test_classinfo_options(self): 35 | self.assertEqual(0, main(["argv0", "-p", self.dist])) 36 | 37 | # jarinfo-specific option is accepted: 38 | def test_jarinfo_options(self): 39 | self.assertEqual(0, main(["argv0", "--jar-classes", self.dist])) 40 | 41 | # distinfo-specific option is accepted: 42 | def test_distinfo_options(self): 43 | self.assertEqual(0, main(["argv0", "--dist-provides", self.dist])) 44 | -------------------------------------------------------------------------------- /tests/jardiff.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for creating/modifying JAR files with python-javatools. 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | import os 24 | from unittest import TestCase 25 | from . import get_data_fn 26 | from javatools.jardiff import cli_jars_diff, main 27 | 28 | 29 | class OptionsHolder(object): 30 | pass 31 | 32 | 33 | class JardiffTest(TestCase): 34 | 35 | options = OptionsHolder() 36 | 37 | def cli_jardiff_wrap(self, expected, left, right, message): 38 | self.assertEqual(expected, cli_jars_diff(self.options, 39 | get_data_fn(left), 40 | get_data_fn(right)), 41 | message) 42 | 43 | options.silent = True 44 | options.ignore_jar_signature = False 45 | 46 | # Two identical JARs (in different files, just in case) 47 | def test_identical_jars(self): 48 | self.cli_jardiff_wrap(0, "test_jardiff/ec.jar", "test_jardiff/ec-copied.jar", 49 | "Identical JARs reported as different") 50 | 51 | def test_sig_block_file_tampered(self): 52 | self.cli_jardiff_wrap(1, "test_jardiff/ec.jar", "test_jardiff/ec-tampered.jar", 53 | "Change in signature block file is not detected") 54 | 55 | def test_sig_block_file_removed(self): 56 | self.cli_jardiff_wrap(1, "test_jardiff/ec.jar", "test_jardiff/ec-sig-block-removed.jar", 57 | "Removal of signature block file is not detected") 58 | 59 | def test_sig_manifest_tampered(self): 60 | self.cli_jardiff_wrap(1, "test_jardiff/ec.jar", "test_jardiff/ec-sig-mf-tampered.jar", 61 | "Change in manifest signature file is not detected") 62 | 63 | def test_generic_file_change(self): 64 | self.options.ignore_jar_entry = [] # Needed, as argparse is not called 65 | self.cli_jardiff_wrap(1, os.path.join("test_jardiff", "generic1.jar"), 66 | os.path.join("test_jardiff", "generic2.jar"), 67 | "Change in generic file is not detected") 68 | 69 | def test_json_binary_diff(self): 70 | left = get_data_fn(os.path.join("test_jardiff", "ec.jar")) 71 | right = get_data_fn(os.path.join("test_jardiff", "ec-tampered.jar")) 72 | self.assertEqual(1, main(["argv0", "--json", left, right])) 73 | 74 | # Options from relevant option groups are accepted: 75 | def test_options_accepted(self): 76 | left = get_data_fn(os.path.join("test_jardiff", "ec.jar")) 77 | right = get_data_fn(os.path.join("test_jardiff", "ec-tampered.jar")) 78 | # General options: 79 | self.assertEqual(1, main(["argv0", "-q", left, right])) 80 | # JAR checking options: 81 | self.assertEqual(0, main(["argv0", "--ignore-jar-signature", left, right])) 82 | # Class checking options: 83 | self.assertEqual(1, main(["argv0", "--ignore-platform-up", left, right])) 84 | # Reporting options: 85 | self.assertEqual(1, main(["argv0", "--report-dir=foo", left, right])) 86 | # JSON reporting options: 87 | self.assertEqual(1, main(["argv0", "--json", "--json-indent=4", left, right])) 88 | # HTML reporting options: 89 | self.assertEqual(1, main(["argv0", "--html-copy-data=foo", left, right])) 90 | 91 | 92 | # 93 | # The end. 94 | -------------------------------------------------------------------------------- /tests/jarinfo.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for javatools/jarinfo.py 18 | 19 | author: Konstantin Shemyak 20 | license: LGPL v.3 21 | """ 22 | 23 | import os 24 | from unittest import TestCase 25 | from . import get_data_fn 26 | from javatools.jarinfo import main 27 | 28 | 29 | class JarinfoTest(TestCase): 30 | 31 | jar = get_data_fn(os.path.join("test_jarinfo", "Sample.jar")) 32 | 33 | # classinfo-specific option is accepted: 34 | def test_classinfo_options(self): 35 | self.assertEqual(0, main(["argv0", "-p", self.jar])) 36 | 37 | # Test that a classinfo-specific option is accepted. 38 | def test_jarinfo_options(self): 39 | self.assertEqual(0, main(["argv0", "--jar-classes", self.jar])) 40 | 41 | def test_jarinfo_manifest(self): 42 | """ Manifest CLI option is accepted """ 43 | self.assertEqual(0, main(["argv0", "--manifest", self.jar])) 44 | -------------------------------------------------------------------------------- /tests/manifest.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for manifest-related functionality of python-javatools 18 | 19 | author: Christopher O'Brien 20 | license: LGPL v.3 21 | """ 22 | 23 | 24 | from . import get_data_fn 25 | from javatools.manifest import main, Manifest, SignatureManifest 26 | 27 | from tempfile import NamedTemporaryFile 28 | from unittest import TestCase 29 | 30 | 31 | class ManifestTest(TestCase): 32 | 33 | 34 | def manifest_cli_create(self, args, expected_result): 35 | """ 36 | execute the CLI manifest tool with the given arguments on our 37 | sample JAR. Verifies that the resulting output manifest is 38 | identical to the expected result. 39 | """ 40 | 41 | # the result we expect to see from running the script 42 | with open(get_data_fn(expected_result), mode="rb") as f: 43 | expected_result = f.read() 44 | 45 | # the invocation of the script 46 | src_jar = get_data_fn("test_manifest/manifest-sample1.jar") 47 | with NamedTemporaryFile() as tmp_out: 48 | cmd = ["manifest", "c", src_jar, "-m", tmp_out.name] 49 | cmd.extend(args.split()) 50 | 51 | # rather than trying to actually execute the script in a 52 | # subprocess, we'll give it an output file call it in the 53 | # current process. This prevents issues when there's already 54 | # an installed version of python-javatools present which may 55 | # be down-version from the one being tested. Calling the 56 | # manifest utility by name will use the installed rather than 57 | # local dev copy. Might be able to tweak this, but for now, 58 | # this is safer. 59 | main(cmd) 60 | result = tmp_out.read() 61 | 62 | self.assertEqual( 63 | result, expected_result, 64 | "Result of \"%r\" does not match expected output." 65 | " Expected:\n%s\nReceived:\n%s" 66 | % (cmd, expected_result, result)) 67 | 68 | 69 | def manifest_load_store(self, src_file): 70 | """ 71 | Loads a manifest object from a given sample in the data directory, 72 | then re-writes it and verifies that the result matches the 73 | original. 74 | """ 75 | 76 | src_file = get_data_fn(src_file) 77 | 78 | # the expected result is identical to what we feed into the 79 | # manifest parser 80 | with open(src_file, mode='rb') as f: 81 | expected_result = f.read() 82 | 83 | # create a manifest and parse the chosen test data 84 | mf = Manifest() 85 | mf.parse_file(src_file) 86 | result = mf.get_data() 87 | 88 | self.assertEqual( 89 | result, expected_result, 90 | "Manifest load/store does not match with file %s. Received:\n%s" 91 | % (src_file, result)) 92 | 93 | return mf 94 | 95 | 96 | def test_create_sha1(self): 97 | self.manifest_cli_create("-d SHA1", "test_manifest/manifest.SHA1.mf") 98 | 99 | 100 | def test_create_sha512(self): 101 | self.manifest_cli_create("-d SHA-512", "test_manifest/manifest.SHA-512.mf") 102 | 103 | 104 | def test_create_with_ignore(self): 105 | self.manifest_cli_create("-i example.txt -d MD5,SHA-512", 106 | "test_manifest/manifest.ignores.mf") 107 | 108 | 109 | def test_load(self): 110 | self.manifest_load_store("test_manifest/manifest.SHA1.mf") 111 | 112 | 113 | def test_load_sha512(self): 114 | self.manifest_load_store("test_manifest/manifest.SHA-512.mf") 115 | 116 | 117 | def test_load_dos_newlines(self): 118 | mf = self.manifest_load_store("test_manifest/manifest.dos-newlines.mf") 119 | self.assertEqual(mf.linesep, "\r\n") 120 | 121 | 122 | def test_cli_verify_ok(self): 123 | jar_file = get_data_fn("test_manifest/cli-verify-ok.jar") 124 | self.assertEqual(0, main(["argv0", "v", jar_file])) 125 | 126 | 127 | def test_cli_verify_nok(self): 128 | jar_file = get_data_fn("test_manifest/cli-verify-nok.jar") 129 | self.assertEqual(1, main(["argv0", "v", jar_file])) 130 | 131 | 132 | def test_verify_mf_checksums_no_whole_digest(self): 133 | sf_file = "test_manifest/sf-no-whole-digest.sf" 134 | mf_file = "test_manifest/sf-no-whole-digest.mf" 135 | sf = SignatureManifest() 136 | sf.parse_file(get_data_fn(sf_file)) 137 | mf = Manifest() 138 | mf.parse_file(get_data_fn(mf_file)) 139 | 140 | self.assertFalse( 141 | sf.verify_manifest_main_checksum(mf), 142 | "Verification of main signature in file %s against manifest %s" 143 | " succeeded, but the SF file has no Digest-Manifest section" 144 | % (sf_file, mf_file)) 145 | 146 | self.assertTrue( 147 | sf.verify_manifest_main_attributes_checksum(mf), 148 | "Verification of Main-Attibutes in file %s against manifest %s" 149 | "failed" % (sf_file, mf_file)) 150 | 151 | errors = sf.verify_manifest_entry_checksums(mf) 152 | self.assertEqual( 153 | 0, len(errors), 154 | "The following entries in signature file %s against manifest %s" 155 | " failed: %s" 156 | % (sf_file, mf_file, ",".join(errors))) 157 | 158 | 159 | def test_multi_digests(self): 160 | jar_file = "test_manifest/multi-digests.jar" 161 | 162 | mf_ok_file = "test_manifest/one-valid-digest-of-several.mf" 163 | mf = Manifest() 164 | mf.parse_file(get_data_fn(mf_ok_file)) 165 | errors = mf.verify_jar_checksums(get_data_fn(jar_file)) 166 | self.assertEqual( 167 | 0, len(errors), 168 | "The following entries in jar file %s do not match" 169 | " in manifest %s: %s" 170 | % (jar_file, mf_ok_file, ",".join(errors))) 171 | 172 | sf_ok_file = "test_manifest/one-valid-digest-of-several.sf" 173 | sf = SignatureManifest() 174 | sf.parse_file(get_data_fn(sf_ok_file)) 175 | 176 | errors = sf.verify_manifest(mf) 177 | self.assertEqual( 178 | 0, len(errors), 179 | "The following entries in signature file %s against manifest %s" 180 | " failed: %s" 181 | % (sf_ok_file, mf_ok_file, ",".join(errors))) 182 | 183 | 184 | def test_add_jar_entries(self): 185 | mf = Manifest() 186 | mf.parse_file(get_data_fn("test_manifest/no-entries.mf")) 187 | mf.add_jar_entries(get_data_fn("test_manifest/junk-entries.jar"), "SHA-512") 188 | self.assertIsNotNone(mf.sub_sections.get("README.md", None), 189 | "Expected entry not added to the manifest") 190 | 191 | 192 | # 193 | # The end. 194 | -------------------------------------------------------------------------------- /tests/pack.py: -------------------------------------------------------------------------------- 1 | # This library is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU Lesser General Public License as 3 | # published by the Free Software Foundation; either version 3 of the 4 | # License, or (at your option) any later version. 5 | # 6 | # This library is distributed in the hope that it will be useful, but 7 | # WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | # Lesser General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public 12 | # License along with this library; if not, see 13 | # . 14 | 15 | 16 | """ 17 | unit tests for javatools.pack 18 | 19 | author: Christopher O'Brien 20 | license: LGPL v.3 21 | """ 22 | 23 | 24 | from abc import ABCMeta, abstractmethod 25 | from unittest import TestCase 26 | from six import add_metaclass, BytesIO 27 | 28 | from javatools.pack import * 29 | 30 | 31 | @add_metaclass(ABCMeta) 32 | class UnpackerTests(object): 33 | """ 34 | Common tests for both unpacker types 35 | """ 36 | 37 | 38 | @abstractmethod 39 | def unpacker_type(self): 40 | pass 41 | 42 | 43 | @abstractmethod 44 | def unpack(self, data): 45 | pass 46 | 47 | 48 | def test_type(self): 49 | data = b"\x05\x04\x03\x02\x01" 50 | up = self.unpack(data) 51 | self.assertEqual(type(up), self.unpacker_type()) 52 | 53 | 54 | def test_nope(self): 55 | self.assertRaises(TypeError, lambda: self.unpack(5)) 56 | 57 | 58 | def test_basics(self): 59 | data = b"\x05\x04\x03\x02\x01" 60 | 61 | with self.unpack(data) as up: 62 | 63 | col = up.read(1) 64 | self.assertEqual(col, b"\x05") 65 | 66 | col = up.unpack(">H") 67 | self.assertEqual(col, (0x0403,)) 68 | 69 | _H = compile_struct(">H") 70 | col = up.unpack_struct(_H) 71 | self.assertEqual(col, (0x0201,)) 72 | 73 | self.assertRaises(UnpackException, lambda: up.read(1)) 74 | self.assertRaises(UnpackException, lambda: up.unpack(">H")) 75 | self.assertRaises(UnpackException, lambda: up.unpack_struct(_H)) 76 | 77 | up = self.unpack(data) 78 | up.close() 79 | 80 | self.assertRaises(UnpackException, lambda: up.read(1)) 81 | self.assertRaises(UnpackException, lambda: up.unpack(">H")) 82 | self.assertRaises(UnpackException, lambda: up.unpack_struct(_H)) 83 | 84 | 85 | def test_array(self): 86 | data = "\x00\x02AB" 87 | 88 | self.assertEqual(len(data), 4) 89 | 90 | with self.unpack(data) as up: 91 | count,a,b = up.unpack(">HBB") 92 | self.assertEqual(count, 2) 93 | self.assertEqual(a, 65) 94 | self.assertEqual(b, 66) 95 | 96 | with self.unpack(data) as up: 97 | a,b = up.unpack_array(">B") 98 | self.assertEqual(a, (65,)) 99 | self.assertEqual(b, (66,)) 100 | 101 | _B = compile_struct(">B") 102 | with self.unpack(data) as up: 103 | a,b = up.unpack_struct_array(_B) 104 | self.assertEqual(a, (65,)) 105 | self.assertEqual(b, (66,)) 106 | 107 | 108 | class BufferTest(UnpackerTests, TestCase): 109 | 110 | def unpacker_type(self): 111 | return BufferUnpacker 112 | 113 | 114 | def unpack(self, data): 115 | if isinstance(data, bytes): 116 | return unpack(data) 117 | elif isinstance(data, str): # Py3 here, as in Py2 str is bytes 118 | return unpack(data.encode('utf-8')) 119 | else: 120 | raise TypeError("This test expects instance of 'bytes' or 'str', " 121 | "but {} received".format(type(data).__name__)) 122 | 123 | 124 | class StreamTest(UnpackerTests, TestCase): 125 | 126 | def unpacker_type(self): 127 | return StreamUnpacker 128 | 129 | 130 | def unpack(self, data): 131 | if isinstance(data, bytes): 132 | return unpack(BytesIO(data)) 133 | elif isinstance(data, str): # Py3 here, as in Py2 str is bytes 134 | return unpack(BytesIO(data.encode('utf-8'))) 135 | else: 136 | raise TypeError("This test expects instance of 'bytes' or 'str', " 137 | "but {} received".format(type(data).__name__)) 138 | 139 | # 140 | # The end. 141 | --------------------------------------------------------------------------------