├── .gitignore ├── AUTHORS.rst ├── CHANGELOG.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── docs ├── Makefile ├── __init__.py ├── _config.yml ├── changelog.rst ├── conf.py ├── configuration.rst ├── detailed-guide │ ├── admin-commands.rst │ ├── certificates.rst │ ├── data-dir.rst │ ├── email-notifications.rst │ ├── index.rst │ ├── monitoring.rst │ ├── organizations.rst │ ├── partners.rst │ ├── sendreceive-mdns.rst │ └── sendreceive-messages.rst ├── images │ ├── P1_Home.png │ ├── P1_SendFile.png │ ├── P2_Home.png │ ├── P2_SendFile.png │ ├── SendFile1.png │ └── SendFile2.png ├── index.rst ├── installation.rst ├── make.bat ├── quick-start-guide.rst └── spelling_wordlist.txt ├── pyas2 ├── __init__.py ├── admin.py ├── as2lib.py ├── as2utils.py ├── forms.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ ├── cleanas2server.py │ │ ├── retryfailedas2comms.py │ │ ├── runas2daemon.py │ │ ├── runas2server.py │ │ ├── sendas2message.py │ │ └── sendasyncmdn.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_partner_compress.py │ ├── 0003_auto_20150311_1141.py │ ├── 0004_auto_20150311_1258.py │ ├── 0005_message_compressed.py │ ├── 0006_auto_20150313_0548.py │ ├── 0007_auto_20150313_0707.py │ ├── 0008_auto_20150317_0450.py │ ├── 0009_auto_20150317_1324.py │ ├── 0010_auto_20150416_0745.py │ ├── 0011_auto_20150427_1029.py │ ├── 0012_auto_20151006_0526.py │ ├── 0013_auto_20160307_0233.py │ ├── 0014_auto_20160420_0515.py │ ├── 0015_auto_20160615_0409.py │ ├── 0016_auto_20161004_0543.py │ ├── 0017_auto_20170404_0730.py │ ├── 0018_auto_20180109_0942.py │ ├── 0019_auto_20180127_0509.py │ ├── 0020_auto_20190315_1048.py │ ├── 0021_auto_20190329_2014.py │ └── __init__.py ├── models.py ├── pyas2init.py ├── static │ ├── admin │ │ ├── css │ │ │ ├── base.css │ │ │ ├── changelists.css │ │ │ ├── dashboard.css │ │ │ ├── fonts.css │ │ │ ├── forms.css │ │ │ ├── login.css │ │ │ ├── rtl.css │ │ │ └── widgets.css │ │ ├── fonts │ │ │ ├── LICENSE.txt │ │ │ ├── README.txt │ │ │ ├── Roboto-Bold-webfont.woff │ │ │ ├── Roboto-Light-webfont.woff │ │ │ └── Roboto-Regular-webfont.woff │ │ ├── img │ │ │ ├── LICENSE │ │ │ ├── README.txt │ │ │ ├── calendar-icons.svg │ │ │ ├── changelist-bg.gif │ │ │ ├── changelist-bg_rtl.gif │ │ │ ├── chooser-bg.gif │ │ │ ├── chooser_stacked-bg.gif │ │ │ ├── default-bg-reverse.gif │ │ │ ├── default-bg.gif │ │ │ ├── deleted-overlay.gif │ │ │ ├── gis │ │ │ │ ├── move_vertex_off.svg │ │ │ │ └── move_vertex_on.svg │ │ │ ├── icon-addlink.svg │ │ │ ├── icon-alert.svg │ │ │ ├── icon-calendar.svg │ │ │ ├── icon-changelink.svg │ │ │ ├── icon-clock.svg │ │ │ ├── icon-deletelink.svg │ │ │ ├── icon-no.gif │ │ │ ├── icon-no.svg │ │ │ ├── icon-unknown-alt.svg │ │ │ ├── icon-unknown.gif │ │ │ ├── icon-unknown.svg │ │ │ ├── icon-yes.gif │ │ │ ├── icon-yes.svg │ │ │ ├── icon_addlink.gif │ │ │ ├── icon_alert.gif │ │ │ ├── icon_calendar.gif │ │ │ ├── icon_changelink.gif │ │ │ ├── icon_clock.gif │ │ │ ├── icon_deletelink.gif │ │ │ ├── icon_error.gif │ │ │ ├── icon_searchbox.png │ │ │ ├── icon_success.gif │ │ │ ├── inline-delete-8bit.png │ │ │ ├── inline-delete.png │ │ │ ├── inline-delete.svg │ │ │ ├── inline-restore-8bit.png │ │ │ ├── inline-restore.png │ │ │ ├── inline-splitter-bg.gif │ │ │ ├── nav-bg-grabber.gif │ │ │ ├── nav-bg-reverse.gif │ │ │ ├── nav-bg-selected.gif │ │ │ ├── nav-bg.gif │ │ │ ├── search.svg │ │ │ ├── selector-icons.gif │ │ │ ├── selector-icons.svg │ │ │ ├── selector-search.gif │ │ │ ├── sorting-icons.gif │ │ │ ├── sorting-icons.svg │ │ │ ├── tool-left.gif │ │ │ ├── tool-left_over.gif │ │ │ ├── tool-right.gif │ │ │ ├── tool-right_over.gif │ │ │ ├── tooltag-add.gif │ │ │ ├── tooltag-add.svg │ │ │ ├── tooltag-add_over.gif │ │ │ ├── tooltag-arrowright.gif │ │ │ ├── tooltag-arrowright.svg │ │ │ └── tooltag-arrowright_over.gif │ │ └── js │ │ │ ├── SelectBox.js │ │ │ ├── SelectFilter2.js │ │ │ ├── actions.js │ │ │ ├── actions.min.js │ │ │ ├── admin │ │ │ ├── DateTimeShortcuts.js │ │ │ └── RelatedObjectLookups.js │ │ │ ├── calendar.js │ │ │ ├── collapse.js │ │ │ ├── collapse.min.js │ │ │ ├── core.js │ │ │ ├── inlines.js │ │ │ ├── inlines.min.js │ │ │ ├── jquery.init.js │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ ├── prepopulate.js │ │ │ ├── prepopulate.min.js │ │ │ ├── timeparse.js │ │ │ ├── urlify.js │ │ │ └── vendor │ │ │ ├── jquery │ │ │ ├── LICENSE-JQUERY.txt │ │ │ ├── jquery.js │ │ │ └── jquery.min.js │ │ │ └── xregexp │ │ │ ├── LICENSE-XREGEXP.txt │ │ │ └── xregexp.min.js │ ├── css │ │ ├── dataTables.jqueryui.min.css │ │ ├── jquery-ui-timepicker-addon.css │ │ ├── jquery-ui.min.css │ │ └── pyas2.css │ ├── images │ │ ├── favicon.ico │ │ ├── icon-pass.gif │ │ ├── icon-pass_parse.gif │ │ ├── pyas2logo.png │ │ ├── star.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_444444_256x240.png │ │ ├── ui-icons_454545_256x240.png │ │ ├── ui-icons_555555_256x240.png │ │ ├── ui-icons_777620_256x240.png │ │ ├── ui-icons_777777_256x240.png │ │ ├── ui-icons_888888_256x240.png │ │ ├── ui-icons_cc0000_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ └── js │ │ ├── dataTables.jqueryui.min.js │ │ ├── jquery-ui-timepicker-addon.js │ │ ├── jquery-ui.min.js │ │ └── jquery.dataTables.min.js ├── templates │ ├── 400.html │ ├── 404.html │ ├── 500.html │ ├── admin │ │ └── base.html │ └── pyas2 │ │ ├── about.html │ │ ├── file_view.html │ │ ├── mdn_list.html │ │ ├── mdn_search.html │ │ ├── menu.html │ │ ├── message_detail.html │ │ ├── message_list.html │ │ ├── message_search.html │ │ ├── pagination.html │ │ └── sendmessage.html ├── templatetags │ ├── __init__.py │ └── pyas2_extras.py ├── test_settings.py ├── tests │ ├── __init__.py │ ├── fixtures │ │ ├── as2client.crt │ │ ├── as2client.pem │ │ ├── as2server.crt │ │ ├── as2server.pem │ │ ├── si_public_key.ca │ │ ├── si_public_key.crt │ │ ├── si_signed.mdn │ │ ├── si_signed_cmp.msg │ │ └── testmessage.edi │ ├── tests.py │ └── urls.py ├── urls.py ├── viewlib.py └── views.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | db.sqlite3 50 | 51 | # Sphinx documentation 52 | docs/_build/ 53 | 54 | # PyBuilder 55 | target/ 56 | 57 | #PyCharm 58 | .idea/ 59 | 60 | #PyAS2 61 | messages/ 62 | certificates/ 63 | logging/ 64 | venv 65 | .DS_STORE -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | pyAS2 is written and maintained by Abhishek Ram `@abhishek-ram `_ and various contributors: 2 | 3 | - Michael Reinig (`@MReinigJr `_) 4 | - `@klaasfeenstra `_ 5 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Release History 2 | =============== 3 | 4 | 0.4.6 - 2019-04-17 5 | ~~~~~~~~~~~~~~~ 6 | 7 | * Add support for sending CSV files 8 | * Handle cases where compression can happen before signing 9 | 10 | 0.4.5 - 2019-03-20 11 | ~~~~~~~~~~~~~~~ 12 | 13 | * Use uuid for filenames and not message id 14 | * More verbose logging of exceptions 15 | 16 | 0.4.4 - 2019-03-15 17 | ~~~~~~~~~~~~~~~ 18 | 19 | * Increase the length of string fields 20 | 21 | 0.4.3 - 2018-06-09 22 | ~~~~~~~~~~~~~~~ 23 | 24 | * Send encrypted content as binary data instead of base64 25 | 26 | 0.4.2 - 2018-06-07 27 | ~~~~~~~~~~~~~~~ 28 | 29 | * Also look for `application/x-pkcs7-signature` when verifying MDN signatures 30 | * Limit size of exception logged to database 31 | * Handle case where Sync MDN does not have a Message ID 32 | 33 | 0.4.1 - 2018-05-07 34 | ~~~~~~~~~~~~~~~ 35 | 36 | * Also look for `application/x-pkcs7-signature` when verifying signatures 37 | 38 | 0.4.0 - 2018-01-27 39 | ~~~~~~~~~~~~~~~ 40 | 41 | * Cleaner handling of signature verifications 42 | * Added test cases for sterling b2b integrator message and mdn 43 | * Set `max_length` for file fields to manage long folder names. 44 | 45 | 0.3.8 - 2018-01-09 46 | ~~~~~~~~~~~~~~~~~~ 47 | 48 | * Give option to download certs from the admin. 49 | 50 | 51 | 0.3.7 - 2018-01-09 52 | ~~~~~~~~~~~~~~~~~~ 53 | 54 | * Use a function to get the certificate upload_to. 55 | 56 | 0.3.6 - 2018-01-05 57 | ~~~~~~~~~~~~~~~~~~ 58 | 59 | * Added view for downloading certificates from the admin. 60 | 61 | 0.3.5 - 2017-12-20 62 | ~~~~~~~~~~~~~~~~~~ 63 | 64 | * Renewed the certificates used in the django tests. 65 | 66 | 0.3.4 - 2017-08-17 67 | ~~~~~~~~~~~~~~~~~~ 68 | 69 | * Add migration to the distribution. 70 | 71 | 0.3.3 - 2017-04-04 72 | ~~~~~~~~~~~~~~~~~~ 73 | 74 | * Use pagination when listing messages in the GUI, also do not use Datatables. 75 | * Set the request MDN field default value to False. 76 | 77 | 0.3.2 - 2017-03-07 78 | ~~~~~~~~~~~~~~~~~~ 79 | 80 | * Freeze versions of django and CherryPy in setup.py. 81 | 82 | 0.3.1 - 2016-10-03 83 | ~~~~~~~~~~~~~~~~~~ 84 | 85 | * Fixed pagination issue where it was showing only 25 messages and mdns. 86 | * Added the admin command cleanas2server for deleting old data and logs. 87 | 88 | 0.3.0 - 2016-06-28 89 | ~~~~~~~~~~~~~~~~~~ 90 | 91 | * Added django test cases for testing each of the permutations as defined in RFC 4130 Section 2.4.2 92 | * Code now follows the pep-8 standard 93 | * Django admin commands now use argparse instead or optparse 94 | 95 | 0.2.3 - 2016-04-20 96 | ~~~~~~~~~~~~~~~~~~ 97 | 98 | * Added functionality to customize MDN messages at organization and partner levels. 99 | 100 | 0.2.2 - 2015-10-12 101 | ~~~~~~~~~~~~~~~~~~ 102 | 103 | * Fixes to take care of changes in Django 1.9.x 104 | 105 | 0.2.1 - 2015-10-12 106 | ~~~~~~~~~~~~~~~~~~ 107 | 108 | * Updated installation and upgrade documentation. 109 | 110 | 0.2 - 2015-10-11 111 | ~~~~~~~~~~~~~~~~ 112 | 113 | * Added option to disable verification of public certificates at the time of signature verification. 114 | * Fixed bug in the send daemon. 115 | * Added debug log statements. 116 | * Added some internationlization to model fields. 117 | 118 | 0.1.2 - 2015-09-07 119 | ~~~~~~~~~~~~~~~~~~ 120 | 121 | * Created readthedocs documentation. 122 | * Fixed bug where inbox and outbox folders were not created on saving partners and orgs. 123 | * Fixed bug where MDN search was failing due to orphaned MDNs. 124 | 125 | 0.1.1 - 2015-09-04 126 | ~~~~~~~~~~~~~~~~~~ 127 | 128 | * Increased the max length of MODE_CHOICES model field. 129 | * Detect Signature Algorithm from the MIME message for outbound messages. 130 | 131 | 0.1 - 2015-04-29 132 | ~~~~~~~~~~~~~~~~ 133 | 134 | * Initial release. 135 | 136 | .. _`master`: https://github.com/abhishek-ram/pyas2 137 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | recursive-include pyas2/static * 4 | recursive-include pyas2/templates * 5 | recursive-include pyas2/templatetags * 6 | recursive-include pyas2/management * 7 | recursive-include pyas2/migrations * 8 | recursive-include pyas2/tests * 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | `which django-admin.py` test --settings=pyas2.test_settings --pythonpath=. 3 | 4 | run: 5 | `which django-admin.py` runas2server --settings=pyas2.test_settings --pythonpath=. 6 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | pyAS2 3 | ===== 4 | 5 | .. image:: https://img.shields.io/pypi/v/pyAS2.svg 6 | :target: https://pypi.python.org/pypi/pyAS2 7 | 8 | .. image:: https://readthedocs.org/projects/pyas2/badge/?version=latest 9 | :target: http://pyas2.readthedocs.org 10 | :alt: Latest Docs 11 | 12 | 13 | ``pyAS2`` is an AS2 server/client written in python and built on the django framework. 14 | The application supports AS2 version 1.2 as defined in the `RFC 4130`_. Our goal is to provide a native 15 | python library for implementing the AS2 protocol. It supports Python 2.6-2.7. 16 | 17 | ``pyAS2`` includes a set of django-admin commands that can be used to start the server, send files as 18 | a client, send asynchronous MDNs and so on. It also has a web based front end interface for 19 | configuring partners and organizations, monitoring message transfers and also initiating new transfers. 20 | 21 | Features 22 | ~~~~~~~~ 23 | 24 | * Technical 25 | 26 | * Asyncronous and syncronous MDN 27 | * Partner and Organization management 28 | * Digital signatures 29 | * Message encryption 30 | * Secure transport (SSL) 31 | * Support for SSL client authentication 32 | * System task to auto clear old log entries 33 | * Data compression (AS2 1.1) 34 | * Multinational support: Uses Django's internationalization feature 35 | 36 | * Integration 37 | 38 | * Easy integration to existing systems, using a partner based file system interface 39 | * Daemon Process picks up data from directories when it becomes available 40 | * Message post processing (scripting on receipt) 41 | 42 | * Monitoring 43 | 44 | * Web interface for transaction monitoring 45 | * Email event notification 46 | 47 | * The following encryption algorithms are supported: 48 | 49 | * Triple DES 50 | * DES 51 | * RC2-40 52 | * AES-128 53 | * AES-192 54 | * AES-256 55 | 56 | * The following hash algorithms are supported: 57 | 58 | * SHA-1 59 | 60 | Documentation 61 | ~~~~~~~~~~~~~ 62 | 63 | You can find more information in the `documentation`_. 64 | 65 | Discussion 66 | ~~~~~~~~~~ 67 | 68 | If you run into bugs, you can file them in our `issue tracker`_. 69 | 70 | Contribute 71 | ~~~~~~~~~~ 72 | 73 | #. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. 74 | #. Fork `the repository`_ on GitHub to start making your changes to the **master** branch (or branch off of it). 75 | #. Create your feature branch: `git checkout -b my-new-feature` 76 | #. Commit your changes: `git commit -am 'Add some feature'` 77 | #. Push to the branch: `git push origin my-new-feature` 78 | #. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_. 79 | 80 | Running Tests 81 | ~~~~~~~~~~~~~ 82 | 83 | To run ``pyAS2's`` test suite: 84 | 85 | ``django-admin.py test pyas2 --settings=pyas2.test_settings --pythonpath=.`` 86 | 87 | License 88 | ~~~~~~~ 89 | 90 | GNU GENERAL PUBLIC LICENSE 91 | Version 2, June 1991 92 | 93 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 94 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 95 | Everyone is permitted to copy and distribute verbatim copies 96 | of this license document, but changing it is not allowed. 97 | 98 | .. _`RFC 4130`: https://www.ietf.org/rfc/rfc4130.txt 99 | .. _`documentation`: http://pyas2.readthedocs.org 100 | .. _`the repository`: http://github.com/abhishek-ram/pyas2 101 | .. _AUTHORS: https://github.com/abhishek-ram/pyas2/blob/master/AUTHORS.rst 102 | .. _`issue tracker`: https://github.com/abhishek-ram/pyas2/issues 103 | -------------------------------------------------------------------------------- /docs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/__init__.py -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CHANGELOG.rst 2 | -------------------------------------------------------------------------------- /docs/detailed-guide/admin-commands.rst: -------------------------------------------------------------------------------- 1 | Admin Commands 2 | ============== 3 | ``pyAS2`` provides a set of Django ``manage.py`` admin commands that perform various functions. We have 4 | already seen the usage of some of these commands in the previous sections. Let us now go through the list 5 | of available commands: 6 | 7 | runas2server 8 | ------------ 9 | The ``runas2server`` command starts the AS2 server which includes both the web UI and the AS2 receiver. 10 | The command does not take any arguments. The command should be started in the background and also a 11 | schedule should be added to run the command on system startup. 12 | 13 | runas2daemon 14 | ------------ 15 | The ``runas2daemon`` command starts the directory monitoring process. The process monitors all the partner inbox 16 | folders and triggers a file transfer when file becomes available. The command should be started in the background and also a 17 | schedule should be added to run the command on system startup. The process needs to be restarted when a new 18 | partner is created so that its inbox can be added to the monitored directory list. 19 | 20 | sendas2message 21 | -------------- 22 | The ``sendas2message`` command triggers a file transfer, it takes the mandatory arguments organization id, partner id and 23 | the full path to the file to be transferred. The command can be used by other applications to integrate with ``pyAS2``. 24 | 25 | sendasyncmdn 26 | ------------ 27 | The ``sendasyncmdn`` command performs two functions; it sends asynchronous MDNs for messages received from your partners and 28 | also checks if we have received asynchronous MDNs for sent messages so that the message status can be updated appropriately. 29 | The command does not take any arguments and should be run on a repeating schedule. 30 | 31 | retryfailedas2comms 32 | ------------------- 33 | The ``retryfailedas2comms`` command checks for any messages that have been set for retries and then retriggers the transfer 34 | for these messages. The command does not take any arguments and should be run on a repeating schedule. 35 | 36 | cleanas2server 37 | -------------- 38 | The ``cleanas2server`` command is a maintenance command and it deletes all DB objects, logs and files older that the ``MAXARCHDAYS`` 39 | setting. It is recommended to run this command once a day using cron or windows scheduler. 40 | -------------------------------------------------------------------------------- /docs/detailed-guide/data-dir.rst: -------------------------------------------------------------------------------- 1 | The Data Directory 2 | ================== 3 | The ``Data Directory`` is a file system directory that stores certificates, logs, archives, sent and received files. 4 | The location of this directory is set to the ``Django`` project folder by default. We can also change this directory 5 | by updating the ``DATADIR`` setting in the ``pyAS2`` :doc:`global settings <../configuration>`. The structure of the 6 | directory is below: 7 | 8 | .. code-block:: console 9 | 10 | {DATA DIRECTORY} 11 | ├── certificates 12 | │   ├── P1_public.pem 13 | │   └── P2_private.pem 14 | ├── logging 15 | │   ├── cherrypy_error.log 16 | │   ├── pyas2.log 17 | │   └── pyas2.log.2015-09-08 18 | └── messages 19 | ├── __store 20 | │   ├── mdn 21 | │   │   ├── received 22 | │   │   └── sent 23 | │   │   ├── 20150908 24 | │   │   │   ├── 20150908115337.7244.44635@Abhisheks-MacBook-Air.local.mdn 25 | │   │   │   └── 20150908121942.7244.71894@Abhisheks-MacBook-Air.local.mdn 26 | │   │   └── 20150913 27 | │   │   ├── 20150913071324.20065.47671@Abhisheks-MacBook-Air.local.mdn 28 | │   │   └── 20150913083125.20403.32480@Abhisheks-MacBook-Air.local.mdn 29 | │   └── payload 30 | │   ├── received 31 | │   │   ├── 20150908 32 | │   │   │   ├── 20150908115458.7255.98107@Abhisheks-MacBook-Air.local 33 | │   │   │   └── 20150908121933.7343.83150@Abhisheks-MacBook-Air.local 34 | │   │   └── 20150913 35 | │   │   ├── 20150913071323.20074.48016@Abhisheks-MacBook-Air.local 36 | │   │   └── 20150913083125.20475.14667@Abhisheks-MacBook-Air.local 37 | │   └── sent 38 | ├── p1as2 39 | │   └── outbox 40 | │   └── p2as2 41 | └── p2as2 42 | └── inbox 43 | └── p1as2 44 | ├── 20150908115458.7255.98107@Abhisheks-MacBook-Air.local.msg 45 | └── 20150913083125.20475.14667@Abhisheks-MacBook-Air.local.msg 46 | 47 | certificates 48 | ------------ 49 | The ``certificates`` directory stores all the ``PEM`` encoded public and private key files. 50 | 51 | logging 52 | ------- 53 | The ``logging`` directory stores the server error logs and application logs. The server error logs are saved as ``cherrypy_error.log`` 54 | and the application logs are saved as ``pyas2.log``. 55 | 56 | __store 57 | ------- 58 | The ``__store`` directory under the ``messages`` directory archives the payloads and MDNs. The ``payloads`` directory saves the 59 | sent and received files in the corresponding sub-folders and the ``mdn`` directory also does the same for sent and received MDNs. 60 | The payloads and MDNs in the sent or received folders are further saved under sub-folders for each day named as ``YYYYMMDD``. 61 | 62 | inbox 63 | ----- 64 | The inbox directory stores files received from your partners. The path of this directory is ``{DATA DIRECTORY}/{ORG AS2 ID}/inbox/{PARTNER AS2 ID}``. 65 | We need to take this location into account when integrating ``pyAS2`` with other applications. 66 | 67 | outbox 68 | ------ 69 | The outbox folder works in conjecture with the ``send-daemon`` process. The daemon process monitors all the outbox 70 | folder and will trigger a transfer when a file becomes available. The path of this directory is ``{DATA DIRECTORY}/{PARTNER AS2 ID}/outbox/{ORG AS2 ID}``. 71 | -------------------------------------------------------------------------------- /docs/detailed-guide/email-notifications.rst: -------------------------------------------------------------------------------- 1 | Email Notifications 2 | =================== 3 | We can configure ``pyAS2`` to send email reports in case of errors encountered while sending 4 | or receiving AS2 messages with your trading partner. To use this feature just set the relevent information 5 | in your `project's settings.py `_ module: 6 | 7 | .. code-block:: python 8 | 9 | MANAGERS = ( #bots will send error reports to the MANAGERS 10 | ('name_manager', 'myemailaddress@gmail'), 11 | ) 12 | EMAIL_HOST = 'smtp.gmail.com' #Default: 'localhost' 13 | EMAIL_PORT = '587' #Default: 25 14 | EMAIL_USE_TLS = True #Default: False 15 | EMAIL_HOST_USER = 'username' #Default: ''. Username to use for the SMTP server defined in EMAIL_HOST. If empty, Django won't attempt authentication. 16 | EMAIL_HOST_PASSWORD = '*******' #Default: ''. PASSWORD to use for the SMTP server defined in EMAIL_HOST. If empty, Django won't attempt authentication. 17 | SERVER_EMAIL = 'botserrors@gmail.com' #Sender of bots error reports. Default: 'root@localhost' 18 | EMAIL_SUBJECT_PREFIX = '' #This is prepended on email subject. 19 | -------------------------------------------------------------------------------- /docs/detailed-guide/index.rst: -------------------------------------------------------------------------------- 1 | Detailed Guide 2 | ============== 3 | 4 | We have seen how to send a file to the partner with the basic settings. Now lets go through each of the components 5 | of ``pyAS2`` in greater detail. In this section we will cover topics related to configuration of partners, organizations and 6 | certificates; sending messages and MDNs; monitoring messages and MDNs; and usage of the admin commands. 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | organizations 12 | partners 13 | certificates 14 | data-dir 15 | sendreceive-messages 16 | sendreceive-mdns 17 | monitoring 18 | admin-commands 19 | email-notifications 20 | -------------------------------------------------------------------------------- /docs/detailed-guide/monitoring.rst: -------------------------------------------------------------------------------- 1 | Monitoring 2 | ========== 3 | ``pyAS2`` maintains a log of all inbound and outbound messages exchanged with your trading partners. The logs 4 | can be accessed from the web UI ``Messages`` menu. The menu has options to list messages, search messages and MDNs. 5 | ``pyAS2`` saves message details such as status, message ID, sender, receiver, payload; and MDN details such as message ID, 6 | original message ID and mode. 7 | 8 | List Messages 9 | ------------- 10 | The list of all sent and received messages can be viewed from the web UI at ``Messages->All Messages``. The screen lists 11 | all messages ordered by timestamp so that the latest message is first on the list. We can further list only inbound messages 12 | at ``Messages->Inbound Messages`` and outbound messages at ``Messages->Outbound Messages``. 13 | 14 | 15 | Search Messages 16 | --------------- 17 | ``pyAS2`` lets you search for messages based on a number of criteria. The search screen can be accessed at ``Messages->Search Messages``. 18 | The following filter criteria are available: 19 | 20 | ================== ========================================================================== 21 | Field Name Description 22 | ================== ========================================================================== 23 | ``Datefrom`` Messages processed after this date will be included in the search results. 24 | ``Dateuntil`` Messages processed before this date will be included in the search results. 25 | ``Organization`` Messages that belong to this organization will be included. 26 | ``Partner`` Messages that belong to this partner will be included. 27 | ``Direction`` Filter by the direction of the AS2 message, can be inbound or outbound. 28 | ``Status`` Filter by the status of the AS2 message. 29 | ``Message ID`` Filter by the AS2 message ID of the message. 30 | ``Payload Name`` Filter by the file name of the sent/received message. 31 | ================== ========================================================================== 32 | 33 | Search MDNs 34 | ----------- 35 | ``pyAS2`` also lets you search for MDNs for messages based on a number of criteria. The search screen can be 36 | accessed at ``Messages->Search MDNs``. The following filter criteria are available: 37 | 38 | ========================== ========================================================================== 39 | Field Name Description 40 | ========================== ========================================================================== 41 | ``Datefrom`` MDNs processed after this date will be included in the search results. 42 | ``Dateuntil`` MDNs processed before this date will be included in the search results. 43 | ``Organization`` MDNs that belong to this organization will be included. 44 | ``Partner`` MDNs that belong to this partner will be included. 45 | ``MDN mode`` Filter by the MDN mode, can be synchronous or asynchronous. 46 | ``Status`` Filter by the status of the MDN. 47 | ``MDN Message ID`` Filter by the message ID of the MDN. 48 | ``Original Message ID`` Filter by the message ID of the original message for which it is an MDN. 49 | ========================== ========================================================================== 50 | 51 | -------------------------------------------------------------------------------- /docs/detailed-guide/organizations.rst: -------------------------------------------------------------------------------- 1 | Organizations 2 | ============= 3 | Organizations in ``pyAS2`` mean the host of the AS2 server, i.e. it is the sender when sending messages and the 4 | receiver when receiving the messages. Organizations can be managed from the web UI at ``Configuration->Organizations``. 5 | The following screen lists the existing organizations and also you gives the option to create new ones. Each 6 | organization is characterized by the following fields: 7 | 8 | ================== ========================================== ========= 9 | Field Name Description Mandatory 10 | ================== ========================================== ========= 11 | ``Name`` The descriptive name of the organization. Yes 12 | ``As2 Name`` The as2 identifies for this organization, Yes 13 | must be a unique value as it identifies 14 | the as2 host. 15 | ``Email Address`` The email address for the organization. No 16 | ``Encryption Key`` The ``Private Key`` used for decrypting Yes 17 | incoming messages from trading partners. 18 | ``Signature Key`` The ``Private Key`` used to sign outgoing Yes 19 | messages to trading partners 20 | ================== ========================================== ========= 21 | -------------------------------------------------------------------------------- /docs/detailed-guide/sendreceive-mdns.rst: -------------------------------------------------------------------------------- 1 | Send & Receive MDNs 2 | =================== 3 | Message Disposition Notifications or MDNs are return receipts used to notify the sender of a message of any of 4 | the several conditions that may occur after successful delivery. In the context of the AS2 protocol, the MDN is used 5 | to notify if the message was successfully processed by the receiver's system or not and in case of failures the 6 | reason for the failure is sent with the MDN. 7 | 8 | MDNs can be transmitted either in a synchronous manner or in an asynchronous manner. The synchronous transmission uses 9 | the same HTTP session as that of the AS2 message and the MDN is returned as an HTTP response message. The asynchronous 10 | transmission uses a new HTTP session to send the MDN to the original AS2 message sender. 11 | 12 | Send MDNs 13 | --------- 14 | The choice of whether to send an MDN and its transfer mode is with the sender of the AS2 message. The sender lets us know what 15 | to do through an AS2 header field. In case the partner requests a synchronous MDN no action is needed as ``pyAS2`` 16 | takes care of this internally, however in the case of an asynchronous MDN the admin command ``sendasyncmdn`` needs to be 17 | run to send the MDN to the trading partner. 18 | 19 | The command ``{PYTHONPATH}/python {DJANGOPROJECTPATH}/manage.py sendasyncmdn`` should be scheduled every 10 minutes so 20 | that ``pyAS2`` sends any pending asynchronous MDN requests received from your trading partners. 21 | 22 | Receive MDNs 23 | ------------ 24 | The choice of whether or not to receive MDN and its transfer mode is with us. The `MDN Settings `__ 25 | for the partner should be used to specify your preference. In case of synchronous mode ``pyAS2`` processes the received MDN 26 | without any action from you. 27 | 28 | In the case of asynchronous mode we do need to take care of a couple of details to enable the receipt of the MDNs. 29 | The :doc:`global setting<../configuration>` ``MDNURL`` should be set to the URL ``http://{hostname}:{port}/pyas2/as2receive`` 30 | so that the trading partner knows where to send the MDN. The other setting of note here is the ``ASYNCMDNWAIT`` 31 | that decides how long ``pyAS2`` waits for an MDN before setting the message as failed so that it can be retried. The admin 32 | command ``sendasyncmdn`` makes this check for all pending messages so it must be scheduled to run regularly. 33 | -------------------------------------------------------------------------------- /docs/detailed-guide/sendreceive-messages.rst: -------------------------------------------------------------------------------- 1 | Send & Receive Messages 2 | ======================= 3 | We have so far covered all the topics related to configuration of the ``pyAS2`` server. Now we will see how 4 | to use these configurations to send messages to your trading partners using the AS2 protocol. We can send files 5 | using any of the following techniques: 6 | 7 | Send Messages From the Web UI 8 | ----------------------------- 9 | The simplest method for sending messages to your trading partner is by using the Web UI. This method is generally used 10 | for testing the AS2 connection with your trading partner. The steps are as follows: 11 | 12 | * Navigate to ``Run->Send Message``. 13 | * Select the sender(Organization), the receiver(Partner) and choose the file to be transmitted. 14 | * Click on ``Send File`` to initiate the file transfer and monitor the transfers at ``Messages->Outbound Messages``. 15 | 16 | .. image:: ../images/SendFile1.png 17 | .. image:: ../images/SendFile2.png 18 | 19 | Send Messages From the Command-Line 20 | ----------------------------------- 21 | The next method for sending messages involves the ``pyAS2`` admin command ``sendas2message``. The command is invoked 22 | from the shell prompt and can be used by other applications to invoke an AS2 file transfer. The command usage is 23 | as follows: 24 | 25 | .. code-block:: console 26 | 27 | $ python manage.py sendas2message --help 28 | Usage: python manage.py sendas2message [options] 29 | 30 | Send an as2 message to your trading partner 31 | 32 | Options: 33 | --delete Delete source file after processing 34 | -h, --help show this help message and exit 35 | 36 | The mandatory arguments to be passed to the command include ``organization_as2name`` i.e. the AS2 Identifier of this organization, 37 | ``partner_as2name`` i.e. the AS2 Identifier of your trading partner and ``path_to_payload`` the full path to the file to be transmitted. 38 | The command also lets you set the ``--delete`` option to delete the file once it is begins the transfer. A sample usage of the command: 39 | 40 | .. code-block:: console 41 | 42 | $ python manage.py sendas2message p1as2 p2as2 /Users/abhishekram/Downloads/updateInvoice.txt 43 | 44 | Send Messages Using the Send-Daemon 45 | ----------------------------------- 46 | The last method for sending messages involves the ``pyAS2`` admin command ``runas2daemon``. The command once started in the background 47 | monitors the data directory and when a file is available in a partner's `outbox `__ folder 48 | then the transfer is initiated for that file. 49 | 50 | .. code-block:: console 51 | 52 | $ python manage.py runas2daemon 53 | 20150915 04:23:37 INFO : Starting PYAS2 send daemon. 54 | 20150915 04:23:37 INFO : Process exisitng files in the directory. 55 | 20150915 04:23:37 INFO : PYAS2 send daemon started started. 56 | 20150915 04:23:37 INFO : Watching directory /opt/pyapp/djproject/messages/MTSAS2Tst/outbox/pyas2test 57 | 20150915 04:23:37 INFO : Watching directory /opt/pyapp/djproject/messages/likemindsas2/outbox/pyas2test 58 | 59 | The above example runs the admin command in the foreground, however in a production environment it should be started in the background 60 | and also OS specific configuration should be added to start this process on system startup. 61 | 62 | Receive Messages 63 | ---------------- 64 | In order to receive files from your trading partners they need to post the AS2 message to the URL 65 | ``http://{hostname}:{port}/pyas2/as2receive``. The configuration of the :doc:`Organization `, 66 | :doc:`Partner ` and :doc:`Certificates ` need to be completed for successfully receiving 67 | messages from your trading partner. Once the message has been received it will be placed in the organizations 68 | `inbox `__ folder. 69 | -------------------------------------------------------------------------------- /docs/images/P1_Home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/images/P1_Home.png -------------------------------------------------------------------------------- /docs/images/P1_SendFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/images/P1_SendFile.png -------------------------------------------------------------------------------- /docs/images/P2_Home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/images/P2_Home.png -------------------------------------------------------------------------------- /docs/images/P2_SendFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/images/P2_SendFile.png -------------------------------------------------------------------------------- /docs/images/SendFile1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/images/SendFile1.png -------------------------------------------------------------------------------- /docs/images/SendFile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/images/SendFile2.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. pyAS2 documentation master file, created by 2 | sphinx-quickstart on Sat Sep 5 15:03:49 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to ``pyAS2's`` documentation! 7 | ===================================== 8 | 9 | ``pyAS2`` is an AS2 server/client written in python and built on the `Django framework`_. 10 | The application supports AS2 version 1.2 as defined in the `RFC 4130`_. Our goal is to 11 | provide a native python library for implementing the AS2 protocol. It supports Python 2.6-2.7. 12 | 13 | The application includes a server for receiving files from partners, a front-end web interface for 14 | configuration and monitoring, a set of ``django-admin`` commands that serves as a client 15 | for sending messages, asynchronous MDNs and a daemon process that monitors directories 16 | and sends files to partners when they are placed in the partner's watched directory. 17 | 18 | Features 19 | -------- 20 | 21 | * Technical 22 | 23 | * Asynchronous and synchronous MDN 24 | * Partner and Organization management 25 | * Digital signatures 26 | * Message encryption 27 | * Secure transport (SSL) 28 | * Support for SSL client authentication 29 | * System task to auto clear old log entries 30 | * Data compression (AS2 1.1) 31 | * Multinational support: Uses Django's internationalization feature 32 | 33 | * Integration 34 | 35 | * Easy integration to existing systems, using a partner based file system interface 36 | * Daemon Process picks up data from directories when it becomes available 37 | * Message post processing (scripting on receipt) 38 | 39 | * Monitoring 40 | 41 | * Web interface for transaction monitoring 42 | * Email event notification 43 | 44 | * The following encryption algorithms are supported: 45 | 46 | * Triple DES 47 | * DES 48 | * RC2-40 49 | * AES-128 50 | * AES-192 51 | * AES-256 52 | 53 | * The following hash algorithms are supported: 54 | 55 | * SHA-1 56 | 57 | Dependencies 58 | ------------ 59 | * Python (2.6.5+, 2.7+) 60 | * Django (1.7+) 61 | * M2Crypto (This is dependent on `openssl`_.) 62 | * requests 63 | * pyasn1 64 | * cherrypy 65 | * pyinotify on \*nix (Optional for using the ``send daemon``) 66 | * Python for Windows extensions (pywin) for windows (Optional for using the ``send daemon``) 67 | 68 | 69 | Installation 70 | ------------ 71 | You can install ``pyAS2`` with ``pip``: 72 | 73 | .. code-block:: console 74 | 75 | $ pip install pyas2 76 | 77 | See :doc:`Installation ` for more information. 78 | 79 | Table of Contents: 80 | ------------------ 81 | .. toctree:: 82 | :maxdepth: 2 83 | 84 | installation 85 | configuration 86 | quick-start-guide 87 | detailed-guide/index 88 | changelog 89 | 90 | .. _`RFC 4130`: https://www.ietf.org/rfc/rfc4130.txt 91 | .. _`Django framework`: https://www.djangoproject.com/ 92 | .. _`openssl`: https://wiki.openssl.org/index.php/Compilation_and_Installation 93 | -------------------------------------------------------------------------------- /docs/spelling_wordlist.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/docs/spelling_wordlist.txt -------------------------------------------------------------------------------- /pyas2/__init__.py: -------------------------------------------------------------------------------- 1 | __title__ = 'pyAS2' 2 | __version__ = '0.4.6' 3 | -------------------------------------------------------------------------------- /pyas2/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from pyas2 import forms 3 | from pyas2 import models 4 | import os 5 | 6 | 7 | class PrivateCertificateAdmin(admin.ModelAdmin): 8 | form = forms.PrivateCertificateForm 9 | list_display = ('__str__', 'download_link',) 10 | 11 | def download_link(self, obj): 12 | return '' + 'Click Here' + '' 14 | 15 | download_link.allow_tags = True 16 | download_link.short_description = "Download Link" 17 | 18 | 19 | class PublicCertificateAdmin(admin.ModelAdmin): 20 | list_display = ('__str__', 'download_link',) 21 | 22 | def download_link(self, obj): 23 | return '' + 'Click Here' + '' 25 | 26 | download_link.allow_tags = True 27 | download_link.short_description = "Download Link" 28 | 29 | 30 | class PartnerAdmin(admin.ModelAdmin): 31 | form = forms.PartnerForm 32 | list_display = ['name', 'as2_name', 'target_url', 'encryption', 'encryption_key', 'signature', 'signature_key', 33 | 'mdn', 'mdn_mode'] 34 | list_filter = ('name', 'as2_name') 35 | fieldsets = ( 36 | (None, { 37 | 'fields': ( 38 | 'name', 'as2_name', 'email_address', 'target_url', 'subject', 'content_type', 'confirmation_message') 39 | }), 40 | ('Http Authentication', { 41 | 'classes': ('collapse', 'wide'), 42 | 'fields': ('http_auth', 'http_auth_user', 'http_auth_pass', 'https_ca_cert') 43 | }), 44 | ('Security Settings', { 45 | 'classes': ('collapse', 'wide'), 46 | 'fields': ('compress', 'encryption', 'encryption_key', 'signature', 'signature_key') 47 | }), 48 | ('MDN Settings', { 49 | 'classes': ('collapse', 'wide'), 50 | 'fields': ('mdn', 'mdn_mode', 'mdn_sign') 51 | }), 52 | ('Advanced Settings', { 53 | 'classes': ('collapse', 'wide'), 54 | 'fields': ('keep_filename', 'cmd_send', 'cmd_receive') 55 | }), 56 | ) 57 | 58 | 59 | class OrganizationAdmin(admin.ModelAdmin): 60 | list_display = ['name', 'as2_name'] 61 | list_filter = ('name', 'as2_name') 62 | 63 | 64 | admin.site.register(models.PrivateCertificate, PrivateCertificateAdmin) 65 | admin.site.register(models.PublicCertificate, PublicCertificateAdmin) 66 | admin.site.register(models.Organization, OrganizationAdmin) 67 | admin.site.register(models.Partner, PartnerAdmin) 68 | admin.site.register(models.Message) 69 | admin.site.register(models.MDN) 70 | -------------------------------------------------------------------------------- /pyas2/forms.py: -------------------------------------------------------------------------------- 1 | from pyas2 import models 2 | from django import forms 3 | from pyas2 import viewlib 4 | 5 | HIDDEN_INPUT = forms.widgets.HiddenInput 6 | 7 | 8 | class PartnerForm(forms.ModelForm): 9 | def clean(self): 10 | cleaned_data = super(PartnerForm, self).clean() 11 | if cleaned_data.get('http_auth'): 12 | if not cleaned_data.get('http_auth_user'): 13 | self._errors['http_auth_user'] = self.error_class( 14 | ['HTTP username is mandatory when HTTP authentication is enabled']) 15 | if not cleaned_data.get('http_auth_pass'): 16 | self._errors['http_auth_pass'] = self.error_class( 17 | ['HTTP password is mandatory when HTTP authentication is enabled']) 18 | if cleaned_data.get('encryption') and not cleaned_data.get('encryption_key'): 19 | self._errors['encryption_key'] = self.error_class( 20 | ['Encryption Key is mandatory when message encryption is enabled']) 21 | if cleaned_data.get('signature') and not cleaned_data.get('signature_key'): 22 | self._errors['signature_key'] = self.error_class( 23 | ['Signature Key is mandatory when message signature is enabled']) 24 | if cleaned_data.get('mdn') and not cleaned_data.get('mdn_mode'): 25 | self._errors['mdn_mode'] = self.error_class(['MDN Mode needs to be specified']) 26 | if cleaned_data.get('mdn_sign') and not cleaned_data.get('signature_key'): 27 | self._errors['signature_key'] = self.error_class( 28 | ['Signature Key is mandatory when signed mdn is requested']) 29 | return cleaned_data 30 | 31 | class Meta: 32 | model = models.Partner 33 | exclude = [] 34 | 35 | 36 | class PrivateCertificateForm(forms.ModelForm): 37 | certificate_passphrase = forms.CharField(widget=forms.PasswordInput()) 38 | 39 | class Meta: 40 | model = models.PrivateCertificate 41 | fields = ['certificate', 'ca_cert', 'certificate_passphrase'] 42 | 43 | 44 | class Select(forms.Form): 45 | datefrom = forms.DateTimeField(initial=viewlib.datetimefrom) 46 | dateuntil = forms.DateTimeField(initial=viewlib.datetimeuntil) 47 | page = forms.IntegerField(required=False, initial=1, widget=HIDDEN_INPUT()) 48 | # sortedby = forms.CharField(initial='ts',widget=HIDDENINPUT()) 49 | # sortedasc = forms.BooleanField(initial=False,required=False,widget=HIDDENINPUT()) 50 | 51 | 52 | class MessageSearchForm(Select): 53 | organization = forms.ChoiceField([], required=False) 54 | partner = forms.ChoiceField([], required=False) 55 | direction = forms.ChoiceField([], required=False) 56 | status = forms.ChoiceField([], required=False) 57 | message_id = forms.CharField(required=False, label='Message ID', max_length=255) 58 | filename = forms.CharField(required=False, label='Payload Name', max_length=100) 59 | 60 | def __init__(self, *args, **kwargs): 61 | super(MessageSearchForm, self).__init__(*args, **kwargs) 62 | self.fields['organization'].choices = models.getorganizations() 63 | self.fields['partner'].choices = models.getpartners() 64 | self.fields['direction'].choices = [models.DEFAULT_ENTRY] + list(models.Message.DIRECTION_CHOICES) 65 | self.fields['status'].choices = [models.DEFAULT_ENTRY] + list(models.Message.STATUS_CHOICES) 66 | 67 | 68 | class MDNSearchForm(Select): 69 | organization = forms.ChoiceField([], required=False) 70 | partner = forms.ChoiceField([], required=False) 71 | mdn_mode = forms.ChoiceField([], required=False) 72 | status = forms.ChoiceField([], required=False) 73 | message_id = forms.CharField(required=False, label='MDN Message ID', max_length=255) 74 | omessage_id = forms.CharField(required=False, label='Original Message ID', max_length=255) 75 | 76 | def __init__(self, *args, **kwargs): 77 | super(MDNSearchForm, self).__init__(*args, **kwargs) 78 | self.fields['organization'].choices = models.getorganizations() 79 | self.fields['partner'].choices = models.getpartners() 80 | self.fields['status'].choices = [models.DEFAULT_ENTRY] + list(models.MDN.STATUS_CHOICES) 81 | self.fields['mdn_mode'].choices = [models.DEFAULT_ENTRY] + list(models.Message.MODE_CHOICES) 82 | 83 | 84 | class SendMessageForm(forms.Form): 85 | organization = forms.ChoiceField([], required=True) 86 | partner = forms.ChoiceField([], required=True) 87 | file = forms.FileField(required=True, allow_empty_file=False) 88 | 89 | def __init__(self, *args, **kwargs): 90 | super(SendMessageForm, self).__init__(*args, **kwargs) 91 | self.fields['organization'].choices = models.getorganizations() 92 | self.fields['partner'].choices = models.getpartners() 93 | -------------------------------------------------------------------------------- /pyas2/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/management/__init__.py -------------------------------------------------------------------------------- /pyas2/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/management/commands/__init__.py -------------------------------------------------------------------------------- /pyas2/management/commands/cleanas2server.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from django.utils.translation import ugettext as _ 3 | from datetime import timedelta 4 | from django.utils import timezone 5 | from pyas2 import models 6 | from pyas2 import pyas2init 7 | import os 8 | import glob 9 | 10 | 11 | class Command(BaseCommand): 12 | help = _(u'Automatic maintenance for the AS2 server. ' 13 | u'Cleans up all the old logs, messages and archived files.') 14 | 15 | def handle(self, *args, **options): 16 | pyas2init.logger.info(_(u'Automatic maintenance process started')) 17 | max_archive_dt = timezone.now() - timedelta( 18 | pyas2init.gsettings['max_arch_days']) 19 | max_archive_ts = int(max_archive_dt.strftime("%s")) 20 | 21 | pyas2init.logger.info( 22 | _(u'Delete all DB Objects older than max archive days')) 23 | old_message = models.Message.objects.filter( 24 | timestamp__lt=max_archive_dt).order_by('timestamp') 25 | for message in old_message: 26 | pyas2init.logger.debug( 27 | _(u'Delete Message {} and all related ' 28 | u'objects'.format(message))) 29 | if message.payload: 30 | message.payload.delete() 31 | if message.mdn: 32 | message.mdn.delete() 33 | message.delete() 34 | 35 | pyas2init.logger.info( 36 | _(u'Delete all logs older than max archive days')) 37 | log_folder = os.path.join(pyas2init.gsettings['log_dir'], 'pyas2*') 38 | for logfile in glob.iglob(log_folder): 39 | filename = os.path.join( 40 | pyas2init.gsettings['log_dir'], logfile) 41 | if os.path.getmtime(filename) < max_archive_ts: 42 | pyas2init.logger.debug( 43 | _(u'Delete Log file {}'.format(filename))) 44 | os.remove(filename) 45 | 46 | pyas2init.logger.info( 47 | _(u'Delete all Archive Files older than max archive days')) 48 | archive_folders = [ 49 | pyas2init.gsettings['payload_send_store'], 50 | pyas2init.gsettings['payload_receive_store'], 51 | pyas2init.gsettings['mdn_send_store'], 52 | pyas2init.gsettings['mdn_receive_store'] 53 | ] 54 | for archive_folder in archive_folders: 55 | for (dir_path, dir_names, arch_files) in os.walk(archive_folder): 56 | if len(arch_files) > 0: 57 | for arch_file in arch_files: 58 | filename = os.path.join(dir_path, arch_file) 59 | if os.path.getmtime(filename) < max_archive_ts: 60 | pyas2init.logger.debug(_(u'Delete Archive file ' 61 | u'{}'.format(filename))) 62 | os.remove(filename) 63 | 64 | # Delete the folder if it is empty 65 | try: 66 | os.rmdir(dir_path) 67 | pyas2init.logger.debug(_(u'Delete Empty Archive folder' 68 | u' {}'.format(dir_path))) 69 | except OSError: 70 | pass 71 | pyas2init.logger.info(_(u'Automatic maintenance process completed')) 72 | -------------------------------------------------------------------------------- /pyas2/management/commands/retryfailedas2comms.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from django.utils.translation import ugettext as _ 3 | from pyas2 import models 4 | from pyas2 import pyas2init 5 | from pyas2 import as2lib 6 | from pyas2 import as2utils 7 | 8 | 9 | class Command(BaseCommand): 10 | help = _(u'Retrying all failed outbound communications') 11 | 12 | def handle(self, *args, **options): 13 | pyas2init.logger.info(_(u'Retrying all failed outbound messages')) 14 | 15 | # Get the list of all messages with status retry 16 | failed_msgs = models.Message.objects.filter(status='R', direction='OUT') 17 | 18 | for failed_msg in failed_msgs: 19 | # Increase the retry count 20 | if not failed_msg.retries: 21 | failed_msg.retries = 1 22 | else: 23 | failed_msg.retries += failed_msg.retries 24 | 25 | # if max retries has exceeded then mark message status as error 26 | if failed_msg.retries > pyas2init.gsettings['max_retries']: 27 | failed_msg.status = 'E' 28 | models.Log.objects.create(message=failed_msg, 29 | status='E', 30 | text=_(u'Message exceeded maximum retries, marked as error')) 31 | failed_msg.save() 32 | continue 33 | 34 | pyas2init.logger.info(_(u'Retrying send of message with ID %s' % failed_msg)) 35 | try: 36 | # Build and resend the AS2 message 37 | payload = as2lib.build_message(failed_msg) 38 | as2lib.send_message(failed_msg, payload) 39 | except Exception, e: 40 | # In case of any errors mark message as failed and send email if enabled 41 | failed_msg.status = 'E' 42 | models.Log.objects.create(message=failed_msg, 43 | status='E', 44 | text=_(u'Failed to send message, error is %s' % e)) 45 | failed_msg.save() 46 | # Send mail here 47 | as2utils.senderrorreport(failed_msg, _(u'Failed to send message, error is %s' % e)) 48 | pyas2init.logger.info(_(u'Successfully processed all failed outbound messages')) 49 | -------------------------------------------------------------------------------- /pyas2/management/commands/runas2server.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from django.core.handlers.wsgi import WSGIHandler 3 | from django.utils.translation import ugettext as _ 4 | from pyas2 import pyas2init 5 | import pyas2 6 | import os 7 | 8 | 9 | class Command(BaseCommand): 10 | help = _(u'Starts the PyAS2 server') 11 | 12 | def handle(self, *args, **options): 13 | try: 14 | import cherrypy 15 | from cherrypy import wsgiserver 16 | except Exception: 17 | raise ImportError(_(u'Dependency failure: cherrypy library is needed to start the as2 server')) 18 | 19 | cherrypy.config.update({ 20 | 'global': { 21 | 'log.screen': False, 22 | 'log.error_file': os.path.join(pyas2init.gsettings['log_dir'], 'cherrypy_error.log'), 23 | 'server.environment': pyas2init.gsettings['environment'] 24 | } 25 | }) 26 | 27 | # cherrypy handling of static files 28 | conf = { 29 | '/': { 30 | 'tools.staticdir.on': True, 31 | 'tools.staticdir.dir': 'static', 32 | 'tools.staticdir.root': os.path.abspath( 33 | os.path.dirname(pyas2.__file__)) 34 | } 35 | } 36 | servestaticfiles = cherrypy.tree.mount(None, '/static', conf) 37 | 38 | # cherrypy handling of django 39 | # was: servedjango = AdminMediaHandler(WSGIHandler()) 40 | # but django does not need the AdminMediaHandler in this setup. is much faster. 41 | servedjango = WSGIHandler() 42 | 43 | # cherrypy uses a dispatcher in order to handle the serving of 44 | # static files and django. 45 | dispatcher = wsgiserver.WSGIPathInfoDispatcher( 46 | {'/': servedjango, '/static': servestaticfiles}) 47 | 48 | pyas2server = wsgiserver.CherryPyWSGIServer( 49 | bind_addr=('0.0.0.0', pyas2init.gsettings['port']), 50 | wsgi_app=dispatcher, 51 | server_name='pyas2-webserver' 52 | ) 53 | 54 | pyas2init.logger.log( 55 | 25, _(u'PyAS2 server running at port: "%s".' % pyas2init.gsettings['port'])) 56 | 57 | # handle ssl: cherrypy < 3.2 always uses pyOpenssl. cherrypy >= 3.2 58 | # uses python buildin ssl (python >= 2.6 has buildin support for ssl). 59 | ssl_certificate = pyas2init.gsettings['ssl_certificate'] 60 | ssl_private_key = pyas2init.gsettings['ssl_private_key'] 61 | if ssl_certificate and ssl_private_key: 62 | if cherrypy.__version__ >= '3.2.0': 63 | adapter_class = wsgiserver.get_ssl_adapter_class('builtin') 64 | pyas2server.ssl_adapter = adapter_class(ssl_certificate, ssl_private_key) 65 | else: 66 | # but: pyOpenssl should be there! 67 | pyas2server.ssl_certificate = ssl_certificate 68 | pyas2server.ssl_private_key = ssl_private_key 69 | pyas2init.logger.log(25, _(u'PyAS2 server uses ssl (https).')) 70 | else: 71 | pyas2init.logger.log(25, _(u'PyAS2 server uses plain http (no ssl).')) 72 | 73 | # start the cherrypy webserver. 74 | try: 75 | pyas2server.start() 76 | except KeyboardInterrupt: 77 | pyas2server.stop() 78 | -------------------------------------------------------------------------------- /pyas2/management/commands/sendas2message.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand, CommandError 2 | from django.utils.translation import ugettext as _ 3 | from pyas2 import models 4 | from pyas2 import as2lib 5 | from pyas2 import as2utils 6 | from pyas2 import pyas2init 7 | import traceback 8 | import email.utils 9 | import shutil 10 | import time 11 | import os 12 | import sys 13 | 14 | 15 | class Command(BaseCommand): 16 | help = _(u'Send an as2 message to your trading partner') 17 | args = '' 18 | 19 | def add_arguments(self, parser): 20 | parser.add_argument('organization_as2name', type=str) 21 | parser.add_argument('partner_as2name', type=str) 22 | parser.add_argument('path_to_payload', type=str) 23 | 24 | parser.add_argument( 25 | '--delete', 26 | action='store_true', 27 | dest='delete', 28 | default=False, 29 | help=_(u'Delete source file after processing') 30 | ) 31 | 32 | def handle(self, *args, **options): 33 | # Check if organization and partner exists 34 | try: 35 | org = models.Organization.objects.get(as2_name=options['organization_as2name']) 36 | except models.Organization.DoesNotExist: 37 | raise CommandError(_(u'Organization "%s" does not exist' % options['organization_as2name'])) 38 | try: 39 | partner = models.Partner.objects.get(as2_name=options['partner_as2name']) 40 | except models.Partner.DoesNotExist: 41 | raise CommandError(_(u'Partner "%s" does not exist' % options['partner_as2name'])) 42 | 43 | # Check if file exists and we have the right permissions 44 | if not os.path.isfile(options['path_to_payload']): 45 | raise CommandError(_(u'Payload at location "%s" does not exist' % options['path_to_payload'])) 46 | if options['delete'] and not os.access(options['path_to_payload'], os.W_OK): 47 | raise CommandError('Insufficient file permission for payload %s' % options['path_to_payload']) 48 | 49 | # Copy the file to the store 50 | output_dir = as2utils.join(pyas2init.gsettings['payload_send_store'], time.strftime('%Y%m%d')) 51 | as2utils.dirshouldbethere(output_dir) 52 | outfile = as2utils.join(output_dir, os.path.basename(options['path_to_payload'])) 53 | shutil.copy2(options['path_to_payload'], outfile) 54 | 55 | # Delete original file if option is set 56 | if options['delete']: 57 | os.remove(options['path_to_payload']) 58 | 59 | # Create the payload and message objects 60 | payload = models.Payload.objects.create(name=os.path.basename(options['path_to_payload']), 61 | file=outfile, 62 | content_type=partner.content_type) 63 | message = models.Message.objects.create(message_id=email.utils.make_msgid().strip('<>'), 64 | partner=partner, 65 | organization=org, 66 | direction='OUT', 67 | status='IP', 68 | payload=payload) 69 | 70 | # Build and send the AS2 message 71 | try: 72 | payload = as2lib.build_message(message) 73 | as2lib.send_message(message, payload) 74 | except Exception: 75 | message.status = 'E' 76 | txt = traceback.format_exc(None).decode('utf-8', 'ignore') 77 | message.adv_status = \ 78 | _(u'Failed to send message, error:\n%(txt)s') % {'txt': txt} 79 | pyas2init.logger.error(message.adv_status) 80 | 81 | models.Log.objects.create( 82 | message=message, status='E', text=message.adv_status) 83 | message.save() 84 | 85 | # Send mail here 86 | as2utils.senderrorreport(message, message.adv_status) 87 | sys.exit(2) 88 | 89 | sys.exit(0) 90 | -------------------------------------------------------------------------------- /pyas2/management/commands/sendasyncmdn.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from django.utils.translation import ugettext as _ 3 | from pyas2 import models 4 | from pyas2 import pyas2init 5 | from email.parser import HeaderParser 6 | from django.utils import timezone 7 | from datetime import timedelta 8 | import requests 9 | 10 | 11 | class Command(BaseCommand): 12 | help = _(u'Send all pending asynchronous mdns to your trading partners') 13 | 14 | def handle(self, *args, **options): 15 | # First part of script sends asynchronous MDNs for inbound messages received from partners 16 | # Fetch all the pending asynchronous MDN objects 17 | pyas2init.logger.info(_(u'Sending all pending asynchronous MDNs')) 18 | in_pending_mdns = models.MDN.objects.filter(status='P') # , timestamp__gt=time_threshold) --> why do this? 19 | 20 | for pending_mdn in in_pending_mdns: 21 | # Parse the MDN headers from text 22 | header_parser = HeaderParser() 23 | mdn_headers = header_parser.parsestr(pending_mdn.headers) 24 | try: 25 | # Set http basic auth if enabled in the partner profile 26 | auth = None 27 | if pending_mdn.omessage.partner and pending_mdn.omessage.partner.http_auth: 28 | auth = (pending_mdn.omessage.partner.http_auth_user, pending_mdn.omessage.partner.http_auth_pass) 29 | 30 | # Set the ca cert if given in the partner profile 31 | verify = True 32 | if pending_mdn.omessage.partner.https_ca_cert: 33 | verify = pending_mdn.omessage.partner.https_ca_cert.path 34 | 35 | # Post the MDN message to the url provided on the original as2 message 36 | with open(pending_mdn.file, 'rb') as payload: 37 | requests.post(pending_mdn.return_url, 38 | auth=auth, 39 | verify=verify, 40 | headers=dict(mdn_headers.items()), 41 | data=payload) 42 | pending_mdn.status = 'S' 43 | models.Log.objects.create(message=pending_mdn.omessage, 44 | status='S', 45 | text=_(u'Successfully sent asynchronous mdn to partner')) 46 | except Exception, e: 47 | models.Log.objects.create(message=pending_mdn.omessage, 48 | status='E', 49 | text=_( 50 | u'Failed to send asynchronous mdn to partner, error is {0:s}'.format(e))) 51 | finally: 52 | pending_mdn.save() 53 | 54 | # Second Part of script checks if MDNs have been received for outbound messages to partners 55 | pyas2init.logger.info(_(u'Marking messages waiting for MDNs for more than {0:d} minutes'.format( 56 | pyas2init.gsettings['async_mdn_wait']))) 57 | 58 | # Find all messages waiting MDNs for more than the set async mdn wait time 59 | time_threshold = timezone.now() - timedelta(minutes=pyas2init.gsettings['async_mdn_wait']) 60 | out_pending_msgs = models.Message.objects.filter(status='P', direction='OUT', timestamp__lt=time_threshold) 61 | 62 | # Mark these messages as erred 63 | for pending_msg in out_pending_msgs: 64 | status_txt = _(u'Failed to receive asynchronous MDN within the threshold limit') 65 | pending_msg.status = 'E' 66 | pending_msg.adv_status = status_txt 67 | models.Log.objects.create(message=pending_msg, status='E', text=status_txt) 68 | pending_msg.save() 69 | 70 | pyas2init.logger.info(_(u'Successfully processed all pending mdns')) 71 | -------------------------------------------------------------------------------- /pyas2/migrations/0002_partner_compress.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='partner', 16 | name='compress', 17 | field=models.BooleanField(default=True, verbose_name=b'Compress Message'), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyas2/migrations/0003_auto_20150311_1141.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0002_partner_compress'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='message', 16 | name='encryption', 17 | field=models.CharField(max_length=20, null=True, blank=True), 18 | preserve_default=True, 19 | ), 20 | migrations.AddField( 21 | model_name='message', 22 | name='signature', 23 | field=models.CharField(max_length=20, null=True, blank=True), 24 | preserve_default=True, 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /pyas2/migrations/0004_auto_20150311_1258.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0003_auto_20150311_1141'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='message', 16 | name='encryption', 17 | ), 18 | migrations.RemoveField( 19 | model_name='message', 20 | name='signature', 21 | ), 22 | migrations.AddField( 23 | model_name='mdn', 24 | name='signed', 25 | field=models.BooleanField(default=False), 26 | preserve_default=True, 27 | ), 28 | migrations.AddField( 29 | model_name='message', 30 | name='encrypted', 31 | field=models.BooleanField(default=False), 32 | preserve_default=True, 33 | ), 34 | migrations.AddField( 35 | model_name='message', 36 | name='signed', 37 | field=models.BooleanField(default=False), 38 | preserve_default=True, 39 | ), 40 | ] 41 | -------------------------------------------------------------------------------- /pyas2/migrations/0005_message_compressed.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0004_auto_20150311_1258'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='message', 16 | name='compressed', 17 | field=models.BooleanField(default=False), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyas2/migrations/0006_auto_20150313_0548.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.core.files.storage 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0005_message_compressed'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='partner', 17 | name='cmd_receive', 18 | field=models.CharField(max_length=255, null=True, verbose_name=b'Command on Message Receipt', blank=True), 19 | preserve_default=True, 20 | ), 21 | migrations.AddField( 22 | model_name='partner', 23 | name='cmd_send', 24 | field=models.CharField(max_length=255, null=True, verbose_name=b'Command on Successful Message Send', blank=True), 25 | preserve_default=True, 26 | ), 27 | migrations.AddField( 28 | model_name='partner', 29 | name='email_address', 30 | field=models.EmailField(max_length=75, null=True, blank=True), 31 | preserve_default=True, 32 | ), 33 | migrations.AddField( 34 | model_name='partner', 35 | name='https_ca_cert', 36 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), null=True, upload_to=b'certificates', blank=True), 37 | preserve_default=True, 38 | ), 39 | migrations.AddField( 40 | model_name='partner', 41 | name='keep_filename', 42 | field=models.BooleanField(default=False, verbose_name=b'Keep Original Filename'), 43 | preserve_default=True, 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /pyas2/migrations/0007_auto_20150313_0707.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.core.files.storage 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0006_auto_20150313_0548'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='message', 17 | name='reties', 18 | field=models.IntegerField(null=True), 19 | preserve_default=True, 20 | ), 21 | migrations.AlterField( 22 | model_name='message', 23 | name='status', 24 | field=models.CharField(max_length=2, choices=[(b'S', b'Success'), (b'E', b'Error'), (b'W', b'Warning'), (b'P', b'Pending'), (b'R', b'Retry'), (b'IP', b'In Process')]), 25 | preserve_default=True, 26 | ), 27 | migrations.AlterField( 28 | model_name='partner', 29 | name='cmd_receive', 30 | field=models.CharField(help_text=b'Command exectued after successful message receipt, replacements are ${filename}, ${fullfilename}, ${subject}, ${sender}, ${recevier}, ${messageid}', max_length=255, null=True, verbose_name=b'Command on Message Receipt', blank=True), 31 | preserve_default=True, 32 | ), 33 | migrations.AlterField( 34 | model_name='partner', 35 | name='cmd_send', 36 | field=models.CharField(help_text=b'Command exectued after successful message send, replacements are ${filename}, ${subject}, ${sender}, ${recevier}, ${messageid}', max_length=255, null=True, verbose_name=b'Command on Message Send', blank=True), 37 | preserve_default=True, 38 | ), 39 | migrations.AlterField( 40 | model_name='partner', 41 | name='encryption', 42 | field=models.CharField(blank=True, max_length=20, null=True, verbose_name=b'Encrypt Message', choices=[(b'des_ede3_cbc', b'3DES'), (b'des_ede_cbc', b'DES'), (b'rc2_40_cbc', b'RC2-40'), (b'rc4', b'RC4-40'), (b'aes_128_cbc', b'AES-128'), (b'aes_192_cbc', b'AES-192'), (b'aes_256_cbc', b'AES-256')]), 43 | preserve_default=True, 44 | ), 45 | migrations.AlterField( 46 | model_name='partner', 47 | name='http_auth', 48 | field=models.BooleanField(default=False, verbose_name=b'Enable Authentication'), 49 | preserve_default=True, 50 | ), 51 | migrations.AlterField( 52 | model_name='partner', 53 | name='https_ca_cert', 54 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates', null=True, verbose_name=b'HTTPS Local CA Store', blank=True), 55 | preserve_default=True, 56 | ), 57 | migrations.AlterField( 58 | model_name='partner', 59 | name='keep_filename', 60 | field=models.BooleanField(default=False, help_text=b'Use Original Filename to to store file on receipt, use this option only if you are sure partner sends unique names', verbose_name=b'Keep Original Filename'), 61 | preserve_default=True, 62 | ), 63 | migrations.AlterField( 64 | model_name='partner', 65 | name='signature', 66 | field=models.CharField(blank=True, max_length=20, null=True, verbose_name=b'Sign Message', choices=[(b'sha1', b'SHA-1')]), 67 | preserve_default=True, 68 | ), 69 | migrations.AlterField( 70 | model_name='privatecertificate', 71 | name='ca_cert', 72 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates', null=True, verbose_name=b'Local CA Store', blank=True), 73 | preserve_default=True, 74 | ), 75 | migrations.AlterField( 76 | model_name='publiccertificate', 77 | name='ca_cert', 78 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates', null=True, verbose_name=b'Local CA Store', blank=True), 79 | preserve_default=True, 80 | ), 81 | ] 82 | -------------------------------------------------------------------------------- /pyas2/migrations/0008_auto_20150317_0450.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0007_auto_20150313_0707'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='partner', 16 | name='mdn_mode', 17 | field=models.CharField(blank=True, max_length=20, null=True, choices=[(b'SYNC', b'Synchronous'), (b'ASYNC', b'Asynchronous')]), 18 | preserve_default=True, 19 | ), 20 | migrations.AlterField( 21 | model_name='partner', 22 | name='mdn_sign', 23 | field=models.CharField(blank=True, max_length=20, null=True, verbose_name=b'Request Signed MDN', choices=[(b'sha1', b'SHA-1')]), 24 | preserve_default=True, 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /pyas2/migrations/0009_auto_20150317_1324.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0008_auto_20150317_0450'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RenameField( 15 | model_name='message', 16 | old_name='reties', 17 | new_name='retries', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /pyas2/migrations/0010_auto_20150416_0745.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.core.files.storage 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0009_auto_20150317_1324'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='partner', 17 | name='cmd_receive', 18 | field=models.TextField(help_text=b'Command exectued after successful message receipt, replacements are $filename, $fullfilename, $sender, $recevier, $messageid and any messsage header such as $subject', null=True, verbose_name=b'Command on Message Receipt', blank=True), 19 | preserve_default=True, 20 | ), 21 | migrations.AlterField( 22 | model_name='partner', 23 | name='cmd_send', 24 | field=models.TextField(help_text=b'Command exectued after successful message send, replacements are $filename, $sender, $recevier, $messageid and any messsage header such as $subject', null=True, verbose_name=b'Command on Message Send', blank=True), 25 | preserve_default=True, 26 | ), 27 | migrations.AlterField( 28 | model_name='partner', 29 | name='https_ca_cert', 30 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/AS2App/djproject'), upload_to=b'certificates', null=True, verbose_name=b'HTTPS Local CA Store', blank=True), 31 | preserve_default=True, 32 | ), 33 | migrations.AlterField( 34 | model_name='privatecertificate', 35 | name='ca_cert', 36 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/AS2App/djproject'), upload_to=b'certificates', null=True, verbose_name=b'Local CA Store', blank=True), 37 | preserve_default=True, 38 | ), 39 | migrations.AlterField( 40 | model_name='privatecertificate', 41 | name='certificate', 42 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/AS2App/djproject'), upload_to=b'certificates'), 43 | preserve_default=True, 44 | ), 45 | migrations.AlterField( 46 | model_name='publiccertificate', 47 | name='ca_cert', 48 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/AS2App/djproject'), upload_to=b'certificates', null=True, verbose_name=b'Local CA Store', blank=True), 49 | preserve_default=True, 50 | ), 51 | migrations.AlterField( 52 | model_name='publiccertificate', 53 | name='certificate', 54 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/AS2App/djproject'), upload_to=b'certificates'), 55 | preserve_default=True, 56 | ), 57 | ] 58 | -------------------------------------------------------------------------------- /pyas2/migrations/0011_auto_20150427_1029.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.core.files.storage 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0010_auto_20150416_0745'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='partner', 17 | name='cmd_receive', 18 | field=models.TextField(help_text=b'Command exectued after successful message receipt, replacements are $filename, $fullfilename, $sender, $recevier, $messageid and any messsage header such as $Subject', null=True, verbose_name=b'Command on Message Receipt', blank=True), 19 | preserve_default=True, 20 | ), 21 | migrations.AlterField( 22 | model_name='partner', 23 | name='cmd_send', 24 | field=models.TextField(help_text=b'Command exectued after successful message send, replacements are $filename, $sender, $recevier, $messageid and any messsage header such as $Subject', null=True, verbose_name=b'Command on Message Send', blank=True), 25 | preserve_default=True, 26 | ), 27 | migrations.AlterField( 28 | model_name='partner', 29 | name='encryption', 30 | field=models.CharField(blank=True, max_length=20, null=True, verbose_name=b'Encrypt Message', choices=[(b'des_ede3_cbc', b'3DES'), (b'des_cbc', b'DES'), (b'aes_128_cbc', b'AES-128'), (b'aes_192_cbc', b'AES-192'), (b'aes_256_cbc', b'AES-256'), (b'rc2_40_cbc', b'RC2-40')]), 31 | preserve_default=True, 32 | ), 33 | migrations.AlterField( 34 | model_name='partner', 35 | name='https_ca_cert', 36 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates', null=True, verbose_name=b'HTTPS Local CA Store', blank=True), 37 | preserve_default=True, 38 | ), 39 | migrations.AlterField( 40 | model_name='privatecertificate', 41 | name='ca_cert', 42 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates', null=True, verbose_name=b'Local CA Store', blank=True), 43 | preserve_default=True, 44 | ), 45 | migrations.AlterField( 46 | model_name='privatecertificate', 47 | name='certificate', 48 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates'), 49 | preserve_default=True, 50 | ), 51 | migrations.AlterField( 52 | model_name='publiccertificate', 53 | name='ca_cert', 54 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates', null=True, verbose_name=b'Local CA Store', blank=True), 55 | preserve_default=True, 56 | ), 57 | migrations.AlterField( 58 | model_name='publiccertificate', 59 | name='certificate', 60 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/djproject'), upload_to=b'certificates'), 61 | preserve_default=True, 62 | ), 63 | ] 64 | -------------------------------------------------------------------------------- /pyas2/migrations/0012_auto_20151006_0526.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pyas2', '0011_auto_20150427_1029'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='publiccertificate', 16 | name='verify_cert', 17 | field=models.BooleanField(default=True, help_text='Uncheck this option to disable certificate verification.', verbose_name='Verify Certificate'), 18 | preserve_default=True, 19 | ), 20 | migrations.AlterField( 21 | model_name='message', 22 | name='mdn_mode', 23 | field=models.CharField(max_length=5, null=True, choices=[(b'SYNC', 'Synchronous'), (b'ASYNC', 'Asynchronous')]), 24 | preserve_default=True, 25 | ), 26 | migrations.AlterField( 27 | model_name='partner', 28 | name='as2_name', 29 | field=models.CharField(max_length=100, serialize=False, verbose_name='AS2 Identifier', primary_key=True), 30 | preserve_default=True, 31 | ), 32 | migrations.AlterField( 33 | model_name='partner', 34 | name='cmd_receive', 35 | field=models.TextField(help_text='Command executed after successful message receipt, replacements are $filename, $fullfilename, $sender, $recevier, $messageid and any message header such as $Subject', null=True, verbose_name='Command on Message Receipt', blank=True), 36 | preserve_default=True, 37 | ), 38 | migrations.AlterField( 39 | model_name='partner', 40 | name='cmd_send', 41 | field=models.TextField(help_text='Command executed after successful message send, replacements are $filename, $sender, $recevier, $messageid and any message header such as $Subject', null=True, verbose_name='Command on Message Send', blank=True), 42 | preserve_default=True, 43 | ), 44 | migrations.AlterField( 45 | model_name='partner', 46 | name='name', 47 | field=models.CharField(max_length=100, verbose_name='Partner Name'), 48 | preserve_default=True, 49 | ), 50 | ] 51 | -------------------------------------------------------------------------------- /pyas2/migrations/0013_auto_20160307_0233.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-03-07 02:33 3 | from __future__ import unicode_literals 4 | 5 | import django.core.files.storage 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyas2', '0012_auto_20151006_0526'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='organization', 18 | name='as2_name', 19 | field=models.CharField(max_length=100, primary_key=True, serialize=False, verbose_name='AS2 Identifier'), 20 | ), 21 | migrations.AlterField( 22 | model_name='organization', 23 | name='email_address', 24 | field=models.EmailField(blank=True, max_length=254, null=True), 25 | ), 26 | migrations.AlterField( 27 | model_name='organization', 28 | name='name', 29 | field=models.CharField(max_length=100, verbose_name='Organization Name'), 30 | ), 31 | migrations.AlterField( 32 | model_name='partner', 33 | name='email_address', 34 | field=models.EmailField(blank=True, max_length=254, null=True), 35 | ), 36 | migrations.AlterField( 37 | model_name='partner', 38 | name='https_ca_cert', 39 | field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/dj93'), upload_to=b'certificates', verbose_name='HTTPS Local CA Store'), 40 | ), 41 | migrations.AlterField( 42 | model_name='privatecertificate', 43 | name='ca_cert', 44 | field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/dj93'), upload_to=b'certificates', verbose_name='Local CA Store'), 45 | ), 46 | migrations.AlterField( 47 | model_name='privatecertificate', 48 | name='certificate', 49 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/dj93'), upload_to=b'certificates'), 50 | ), 51 | migrations.AlterField( 52 | model_name='publiccertificate', 53 | name='ca_cert', 54 | field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/dj93'), upload_to=b'certificates', verbose_name='Local CA Store'), 55 | ), 56 | migrations.AlterField( 57 | model_name='publiccertificate', 58 | name='certificate', 59 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/opt/pyapp/dj93'), upload_to=b'certificates'), 60 | ), 61 | ] 62 | -------------------------------------------------------------------------------- /pyas2/migrations/0014_auto_20160420_0515.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-04-20 05:15 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0013_auto_20160307_0233'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='organization', 17 | name='confirmation_message', 18 | field=models.CharField(blank=True, help_text='Use this field to send a customized message in the MDN Confirmations for this Organization', max_length=300, null=True, verbose_name='Confirmation Message'), 19 | ), 20 | migrations.AddField( 21 | model_name='partner', 22 | name='confirmation_message', 23 | field=models.CharField(blank=True, help_text='Use this field to send a customized message in the MDN Confirmations for this Partner', max_length=300, null=True, verbose_name='Confirmation Message'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /pyas2/migrations/0015_auto_20160615_0409.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.7 on 2016-06-15 04:09 3 | from __future__ import unicode_literals 4 | 5 | import django.core.files.storage 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyas2', '0014_auto_20160420_0515'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='partner', 18 | name='https_ca_cert', 19 | field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/pyAS2/pyas2_dev'), upload_to=b'certificates', verbose_name='HTTPS Local CA Store'), 20 | ), 21 | migrations.AlterField( 22 | model_name='privatecertificate', 23 | name='ca_cert', 24 | field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/pyAS2/pyas2_dev'), upload_to=b'certificates', verbose_name='Local CA Store'), 25 | ), 26 | migrations.AlterField( 27 | model_name='privatecertificate', 28 | name='certificate', 29 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/pyAS2/pyas2_dev'), upload_to=b'certificates'), 30 | ), 31 | migrations.AlterField( 32 | model_name='publiccertificate', 33 | name='ca_cert', 34 | field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/pyAS2/pyas2_dev'), upload_to=b'certificates', verbose_name='Local CA Store'), 35 | ), 36 | migrations.AlterField( 37 | model_name='publiccertificate', 38 | name='certificate', 39 | field=models.FileField(storage=django.core.files.storage.FileSystemStorage(base_url=b'/pyas2', location=b'/Users/abhishekram/Documents/work/Research/pyAS2/pyas2_dev'), upload_to=b'certificates'), 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /pyas2/migrations/0016_auto_20161004_0543.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.7 on 2016-10-04 05:43 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyas2', '0015_auto_20160615_0409'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='log', 18 | name='message', 19 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='pyas2.Message'), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /pyas2/migrations/0017_auto_20170404_0730.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.7 on 2017-04-04 07:30 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0016_auto_20161004_0543'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='partner', 17 | name='mdn', 18 | field=models.BooleanField(default=False, verbose_name='Request MDN'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyas2/migrations/0018_auto_20180109_0942.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.7 on 2018-01-09 09:42 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import pyas2.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyas2', '0017_auto_20170404_0730'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='partner', 18 | name='https_ca_cert', 19 | field=models.FileField(blank=True, null=True, upload_to=pyas2.models.get_certificate_path, verbose_name='HTTPS Local CA Store'), 20 | ), 21 | migrations.AlterField( 22 | model_name='privatecertificate', 23 | name='ca_cert', 24 | field=models.FileField(blank=True, null=True, upload_to=pyas2.models.get_certificate_path, verbose_name='Local CA Store'), 25 | ), 26 | migrations.AlterField( 27 | model_name='privatecertificate', 28 | name='certificate', 29 | field=models.FileField(upload_to=pyas2.models.get_certificate_path), 30 | ), 31 | migrations.AlterField( 32 | model_name='publiccertificate', 33 | name='ca_cert', 34 | field=models.FileField(blank=True, null=True, upload_to=pyas2.models.get_certificate_path, verbose_name='Local CA Store'), 35 | ), 36 | migrations.AlterField( 37 | model_name='publiccertificate', 38 | name='certificate', 39 | field=models.FileField(upload_to=pyas2.models.get_certificate_path), 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /pyas2/migrations/0019_auto_20180127_0509.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.7 on 2018-01-27 05:09 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import pyas2.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyas2', '0018_auto_20180109_0942'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='mdn', 18 | name='file', 19 | field=models.CharField(max_length=500), 20 | ), 21 | migrations.AlterField( 22 | model_name='partner', 23 | name='https_ca_cert', 24 | field=models.FileField(blank=True, max_length=500, null=True, upload_to=pyas2.models.get_certificate_path, verbose_name='HTTPS Local CA Store'), 25 | ), 26 | migrations.AlterField( 27 | model_name='payload', 28 | name='file', 29 | field=models.CharField(max_length=500), 30 | ), 31 | migrations.AlterField( 32 | model_name='privatecertificate', 33 | name='ca_cert', 34 | field=models.FileField(blank=True, max_length=500, null=True, upload_to=pyas2.models.get_certificate_path, verbose_name='Local CA Store'), 35 | ), 36 | migrations.AlterField( 37 | model_name='privatecertificate', 38 | name='certificate', 39 | field=models.FileField(max_length=500, upload_to=pyas2.models.get_certificate_path), 40 | ), 41 | migrations.AlterField( 42 | model_name='publiccertificate', 43 | name='ca_cert', 44 | field=models.FileField(blank=True, max_length=500, null=True, upload_to=pyas2.models.get_certificate_path, verbose_name='Local CA Store'), 45 | ), 46 | migrations.AlterField( 47 | model_name='publiccertificate', 48 | name='certificate', 49 | field=models.FileField(max_length=500, upload_to=pyas2.models.get_certificate_path), 50 | ), 51 | ] 52 | -------------------------------------------------------------------------------- /pyas2/migrations/0020_auto_20190315_1048.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.6 on 2019-03-15 10:48 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0019_auto_20180127_0509'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='log', 17 | name='text', 18 | field=models.TextField(), 19 | ), 20 | migrations.AlterField( 21 | model_name='mdn', 22 | name='message_id', 23 | field=models.CharField(max_length=250, primary_key=True, serialize=False), 24 | ), 25 | migrations.AlterField( 26 | model_name='message', 27 | name='adv_status', 28 | field=models.TextField(null=True), 29 | ), 30 | migrations.AlterField( 31 | model_name='message', 32 | name='message_id', 33 | field=models.CharField(max_length=250, primary_key=True, serialize=False), 34 | ), 35 | migrations.AlterField( 36 | model_name='payload', 37 | name='file', 38 | field=models.TextField(), 39 | ), 40 | ] 41 | -------------------------------------------------------------------------------- /pyas2/migrations/0021_auto_20190329_2014.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.20 on 2019-03-29 20:14 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyas2', '0020_auto_20190315_1048'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='partner', 17 | name='content_type', 18 | field=models.CharField(choices=[(b'application/EDI-X12', b'application/EDI-X12'), (b'application/EDIFACT', b'application/EDIFACT'), (b'application/edi-consent', b'application/edi-consent'), (b'application/XML', b'application/XML'), (b'text/CSV', b'text/CSV')], default=b'application/edi-consent', max_length=100), 19 | ), 20 | ] -------------------------------------------------------------------------------- /pyas2/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/migrations/__init__.py -------------------------------------------------------------------------------- /pyas2/pyas2init.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import sys 4 | from django.conf import settings 5 | from pyas2 import as2utils 6 | 7 | # Declare global variables 8 | gsettings = {} 9 | logger = None 10 | convertini2logger = { 11 | 'DEBUG': logging.DEBUG, 12 | 'INFO': logging.INFO, 13 | 'WARNING': logging.WARNING, 14 | 'ERROR': logging.ERROR, 15 | 'CRITICAL': logging.CRITICAL, 16 | 'STARTINFO': 25 17 | } 18 | 19 | 20 | def initialize(): 21 | """ Function initializes the global variables for pyAS2 """ 22 | 23 | global gsettings 24 | pyas2_settings = {} 25 | if hasattr(settings, 'PYAS2'): 26 | pyas2_settings = settings.PYAS2 27 | if not gsettings: 28 | gsettings['environment'] = pyas2_settings.get('ENVIRONMENT', 'production') 29 | gsettings['port'] = pyas2_settings.get('PORT', 8080) 30 | gsettings['ssl_certificate'] = pyas2_settings.get('SSLCERTIFICATE', None) 31 | gsettings['ssl_private_key'] = pyas2_settings.get('SSLPRIVATEKEY', None) 32 | gsettings['environment_text'] = pyas2_settings.get('ENVIRONMENTTEXT', 'Production') 33 | gsettings['environment_text_color'] = pyas2_settings.get('ENVIRONMENTTEXTCOLOR', 'Black') 34 | gsettings['root_dir'] = settings.BASE_DIR 35 | gsettings['python_path'] = pyas2_settings.get('PYTHONPATH', sys.executable) 36 | gsettings['managepy_path'] = as2utils.join(settings.BASE_DIR, 'manage.py') 37 | gsettings['daemon_port'] = pyas2_settings.get('DAEMONPORT', 16388) 38 | if pyas2_settings.get('DATADIR') and os.path.isdir(pyas2_settings.get('DATADIR')): 39 | gsettings['root_dir'] = pyas2_settings.get('DATADIR') 40 | gsettings['payload_receive_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'payload', 41 | 'received') 42 | gsettings['payload_send_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'payload', 'sent') 43 | gsettings['mdn_receive_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'mdn', 'received') 44 | gsettings['mdn_send_store'] = as2utils.join(gsettings['root_dir'], 'messages', '__store', 'mdn', 'sent') 45 | gsettings['log_dir'] = as2utils.join(gsettings['root_dir'], 'logging') 46 | for sett in ['payload_receive_store', 'payload_send_store', 'mdn_receive_store', 'mdn_send_store', 'log_dir']: 47 | as2utils.dirshouldbethere(gsettings[sett]) 48 | gsettings['log_level'] = pyas2_settings.get('LOGLEVEL', 'INFO') 49 | gsettings['log_console'] = pyas2_settings.get('LOGCONSOLE', True) 50 | gsettings['log_console_level'] = pyas2_settings.get('LOGCONSOLELEVEL', 'STARTINFO') 51 | gsettings['max_retries'] = pyas2_settings.get('MAXRETRIES', 30) 52 | gsettings['mdn_url'] = pyas2_settings.get('MDNURL', 'http://localhost:8080/pyas2/as2receive') 53 | gsettings['async_mdn_wait'] = pyas2_settings.get('ASYNCMDNWAIT', 30) 54 | gsettings['max_arch_days'] = pyas2_settings.get('MAXARCHDAYS', 30) 55 | gsettings['minDate'] = 0 - gsettings['max_arch_days'] 56 | 57 | 58 | def initserverlogging(logname): 59 | # initialise file logging 60 | global logger 61 | logger = logging.getLogger(logname) 62 | logger.setLevel(convertini2logger[gsettings['log_level']]) 63 | handler = logging.handlers.TimedRotatingFileHandler(os.path.join(gsettings['log_dir'], logname + '.log'), 64 | when='midnight', backupCount=10) 65 | fileformat = logging.Formatter("%(asctime)s %(levelname)-9s: %(message)s", '%Y%m%d %H:%M:%S') 66 | handler.setFormatter(fileformat) 67 | logger.addHandler(handler) 68 | # initialise console/screen logging 69 | if gsettings['log_console']: 70 | console = logging.StreamHandler() 71 | console.setLevel(convertini2logger[gsettings['log_console_level']]) 72 | consoleformat = logging.Formatter("%(asctime)s %(levelname)-9s: %(message)s", '%Y%m%d %H:%M:%S') 73 | console.setFormatter(consoleformat) # add formatter to console 74 | logger.addHandler(console) # add console to logger 75 | return logger 76 | -------------------------------------------------------------------------------- /pyas2/static/admin/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* DASHBOARD */ 2 | 3 | .dashboard .module table th { 4 | width: 100%; 5 | } 6 | 7 | .dashboard .module table td { 8 | white-space: nowrap; 9 | } 10 | 11 | .dashboard .module table td a { 12 | display: block; 13 | padding-right: .6em; 14 | } 15 | 16 | /* RECENT ACTIONS MODULE */ 17 | 18 | .module ul.actionlist { 19 | margin-left: 0; 20 | } 21 | 22 | ul.actionlist li { 23 | list-style-type: none; 24 | } 25 | 26 | ul.actionlist li { 27 | overflow: hidden; 28 | text-overflow: ellipsis; 29 | -o-text-overflow: ellipsis; 30 | } 31 | -------------------------------------------------------------------------------- /pyas2/static/admin/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | src: url('../fonts/Roboto-Bold-webfont.woff'); 4 | font-weight: 700; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'Roboto'; 10 | src: url('../fonts/Roboto-Regular-webfont.woff'); 11 | font-weight: 400; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Roboto'; 17 | src: url('../fonts/Roboto-Light-webfont.woff'); 18 | font-weight: 300; 19 | font-style: normal; 20 | } 21 | -------------------------------------------------------------------------------- /pyas2/static/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | body.login { 4 | background: #f8f8f8; 5 | } 6 | 7 | .login #header { 8 | height: auto; 9 | padding: 5px 16px; 10 | } 11 | 12 | .login #header h1 { 13 | font-size: 18px; 14 | } 15 | 16 | .login #header h1 a { 17 | color: #fff; 18 | } 19 | 20 | .login #content { 21 | padding: 20px 20px 0; 22 | } 23 | 24 | .login #container { 25 | background: #fff; 26 | border: 1px solid #eaeaea; 27 | border-radius: 4px; 28 | overflow: hidden; 29 | width: 28em; 30 | min-width: 300px; 31 | margin: 100px auto; 32 | } 33 | 34 | .login #content-main { 35 | width: 100%; 36 | } 37 | 38 | .login .form-row { 39 | padding: 4px 0; 40 | float: left; 41 | width: 100%; 42 | border-bottom: none; 43 | } 44 | 45 | .login .form-row label { 46 | padding-right: 0.5em; 47 | line-height: 2em; 48 | font-size: 1em; 49 | clear: both; 50 | color: #333; 51 | } 52 | 53 | .login .form-row #id_username, .login .form-row #id_password { 54 | clear: both; 55 | padding: 8px; 56 | width: 100%; 57 | -webkit-box-sizing: border-box; 58 | -moz-box-sizing: border-box; 59 | box-sizing: border-box; 60 | } 61 | 62 | .login span.help { 63 | font-size: 10px; 64 | display: block; 65 | } 66 | 67 | .login .submit-row { 68 | clear: both; 69 | padding: 1em 0 0 9.4em; 70 | margin: 0; 71 | border: none; 72 | background: none; 73 | text-align: left; 74 | } 75 | 76 | .login .password-reset-link { 77 | text-align: center; 78 | } 79 | -------------------------------------------------------------------------------- /pyas2/static/admin/css/rtl.css: -------------------------------------------------------------------------------- 1 | body { 2 | direction: rtl; 3 | } 4 | 5 | /* LOGIN */ 6 | 7 | .login .form-row { 8 | float: right; 9 | } 10 | 11 | .login .form-row label { 12 | float: right; 13 | padding-left: 0.5em; 14 | padding-right: 0; 15 | text-align: left; 16 | } 17 | 18 | .login .submit-row { 19 | clear: both; 20 | padding: 1em 9.4em 0 0; 21 | } 22 | 23 | /* GLOBAL */ 24 | 25 | th { 26 | text-align: right; 27 | } 28 | 29 | .module h2, .module caption { 30 | text-align: right; 31 | } 32 | 33 | .module ul, .module ol { 34 | margin-left: 0; 35 | margin-right: 1.5em; 36 | } 37 | 38 | .addlink, .changelink { 39 | padding-left: 0; 40 | padding-right: 16px; 41 | background-position: 100% 1px; 42 | } 43 | 44 | .deletelink { 45 | padding-left: 0; 46 | padding-right: 16px; 47 | background-position: 100% 1px; 48 | } 49 | 50 | .object-tools { 51 | float: left; 52 | } 53 | 54 | thead th:first-child, 55 | tfoot td:first-child { 56 | border-left: none; 57 | } 58 | 59 | /* LAYOUT */ 60 | 61 | #user-tools { 62 | right: auto; 63 | left: 0; 64 | text-align: left; 65 | } 66 | 67 | div.breadcrumbs { 68 | text-align: right; 69 | } 70 | 71 | #content-main { 72 | float: right; 73 | } 74 | 75 | #content-related { 76 | float: left; 77 | margin-left: -300px; 78 | margin-right: auto; 79 | } 80 | 81 | .colMS { 82 | margin-left: 300px; 83 | margin-right: 0; 84 | } 85 | 86 | /* SORTABLE TABLES */ 87 | 88 | table thead th.sorted .sortoptions { 89 | float: left; 90 | } 91 | 92 | thead th.sorted .text { 93 | padding-right: 0; 94 | padding-left: 42px; 95 | } 96 | 97 | /* dashboard styles */ 98 | 99 | .dashboard .module table td a { 100 | padding-left: .6em; 101 | padding-right: 16px; 102 | } 103 | 104 | /* changelists styles */ 105 | 106 | .change-list .filtered table { 107 | border-left: none; 108 | border-right: 0px none; 109 | } 110 | 111 | #changelist-filter { 112 | right: auto; 113 | left: 0; 114 | border-left: none; 115 | border-right: none; 116 | } 117 | 118 | .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { 119 | margin-right: 0; 120 | margin-left: 280px; 121 | } 122 | 123 | #changelist-filter li.selected { 124 | border-left: none; 125 | padding-left: 10px; 126 | margin-left: 0; 127 | border-right: 5px solid #eaeaea; 128 | padding-right: 10px; 129 | margin-right: -15px; 130 | } 131 | 132 | .filtered .actions { 133 | margin-left: 280px; 134 | margin-right: 0; 135 | } 136 | 137 | #changelist table tbody td:first-child, #changelist table tbody th:first-child { 138 | border-right: none; 139 | border-left: none; 140 | } 141 | 142 | /* FORMS */ 143 | 144 | .aligned label { 145 | padding: 0 0 3px 1em; 146 | float: right; 147 | } 148 | 149 | .submit-row { 150 | text-align: left 151 | } 152 | 153 | .submit-row p.deletelink-box { 154 | float: right; 155 | } 156 | 157 | .submit-row input.default { 158 | margin-left: 0; 159 | } 160 | 161 | .vDateField, .vTimeField { 162 | margin-left: 2px; 163 | } 164 | 165 | .aligned .form-row input { 166 | margin-left: 5px; 167 | } 168 | 169 | form ul.inline li { 170 | float: right; 171 | padding-right: 0; 172 | padding-left: 7px; 173 | } 174 | 175 | input[type=submit].default, .submit-row input.default { 176 | float: left; 177 | } 178 | 179 | fieldset .field-box { 180 | float: right; 181 | margin-left: 20px; 182 | margin-right: 0; 183 | } 184 | 185 | .errorlist li { 186 | background-position: 100% 12px; 187 | padding: 0; 188 | } 189 | 190 | .errornote { 191 | background-position: 100% 12px; 192 | padding: 10px 12px; 193 | } 194 | 195 | /* WIDGETS */ 196 | 197 | .calendarnav-previous { 198 | top: 0; 199 | left: auto; 200 | right: 10px; 201 | } 202 | 203 | .calendarnav-next { 204 | top: 0; 205 | right: auto; 206 | left: 10px; 207 | } 208 | 209 | .calendar caption, .calendarbox h2 { 210 | text-align: center; 211 | } 212 | 213 | .selector { 214 | float: right; 215 | } 216 | 217 | .selector .selector-filter { 218 | text-align: right; 219 | } 220 | 221 | .inline-deletelink { 222 | float: left; 223 | } 224 | 225 | form .form-row p.datetime { 226 | overflow: hidden; 227 | } 228 | 229 | /* MISC */ 230 | 231 | .inline-related h2, .inline-group h2 { 232 | text-align: right 233 | } 234 | 235 | .inline-related h3 span.delete { 236 | padding-right: 20px; 237 | padding-left: inherit; 238 | left: 10px; 239 | right: inherit; 240 | float:left; 241 | } 242 | 243 | .inline-related h3 span.delete label { 244 | margin-left: inherit; 245 | margin-right: 2px; 246 | } 247 | 248 | /* IE7 specific bug fixes */ 249 | 250 | div.colM { 251 | position: relative; 252 | } 253 | 254 | .submit-row input { 255 | float: left; 256 | } 257 | -------------------------------------------------------------------------------- /pyas2/static/admin/fonts/README.txt: -------------------------------------------------------------------------------- 1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto 2 | Weights used in this project: Light (300), Regular (400), Bold (700) 3 | -------------------------------------------------------------------------------- /pyas2/static/admin/fonts/Roboto-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/fonts/Roboto-Bold-webfont.woff -------------------------------------------------------------------------------- /pyas2/static/admin/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /pyas2/static/admin/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /pyas2/static/admin/img/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Code Charm Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/README.txt: -------------------------------------------------------------------------------- 1 | All icons are taken from Font Awesome (http://fontawesome.io/) project. 2 | The Font Awesome font is licensed under the SIL OFL 1.1: 3 | - http://scripts.sil.org/OFL 4 | 5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG 6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license 7 | in current folder). 8 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/changelist-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/changelist-bg.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/changelist-bg_rtl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/changelist-bg_rtl.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/chooser-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/chooser-bg.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/chooser_stacked-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/chooser_stacked-bg.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/default-bg-reverse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/default-bg-reverse.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/default-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/default-bg.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/deleted-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/deleted-overlay.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-no.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon-no.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-unknown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon-unknown.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-yes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon-yes.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_addlink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_addlink.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_alert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_alert.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_calendar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_calendar.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_changelink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_changelink.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_clock.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_clock.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_deletelink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_deletelink.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_error.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_error.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_searchbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_searchbox.png -------------------------------------------------------------------------------- /pyas2/static/admin/img/icon_success.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/icon_success.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/inline-delete-8bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/inline-delete-8bit.png -------------------------------------------------------------------------------- /pyas2/static/admin/img/inline-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/inline-delete.png -------------------------------------------------------------------------------- /pyas2/static/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/inline-restore-8bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/inline-restore-8bit.png -------------------------------------------------------------------------------- /pyas2/static/admin/img/inline-restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/inline-restore.png -------------------------------------------------------------------------------- /pyas2/static/admin/img/inline-splitter-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/inline-splitter-bg.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/nav-bg-grabber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/nav-bg-grabber.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/nav-bg-reverse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/nav-bg-reverse.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/nav-bg-selected.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/nav-bg-selected.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/nav-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/nav-bg.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/selector-icons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/selector-icons.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/selector-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/selector-search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/selector-search.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/sorting-icons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/sorting-icons.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/sorting-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/tool-left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tool-left.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tool-left_over.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tool-left_over.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tool-right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tool-right.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tool-right_over.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tool-right_over.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tooltag-add.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tooltag-add.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/tooltag-add_over.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tooltag-add_over.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tooltag-arrowright.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tooltag-arrowright.gif -------------------------------------------------------------------------------- /pyas2/static/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pyas2/static/admin/img/tooltag-arrowright_over.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/admin/img/tooltag-arrowright_over.gif -------------------------------------------------------------------------------- /pyas2/static/admin/js/actions.min.js: -------------------------------------------------------------------------------- 1 | (function(a){var f;a.fn.actions=function(q){var b=a.extend({},a.fn.actions.defaults,q),g=a(this),e=!1,k=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()},l=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},m=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},n=function(){m(); 2 | a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)},p=function(c){c?k():m();a(g).prop("checked",c).parent().parent().toggleClass(b.selectedClass,c)},h=function(){var c=a(g).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).prop("checked",function(){var a;c===g.length?(a=!0,k()):(a=!1,n());return a})};a(b.counterContainer).show();a(this).filter(":checked").each(function(c){a(this).parent().parent().toggleClass(b.selectedClass); 3 | h();1===a(b.acrossInput).val()&&l()});a(b.allToggle).show().click(function(){p(a(this).prop("checked"));h()});a("a",b.acrossQuestions).click(function(c){c.preventDefault();a(b.acrossInput).val(1);l()});a("a",b.acrossClears).click(function(c){c.preventDefault();a(b.allToggle).prop("checked",!1);n();p(0);h()});f=null;a(g).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(f&&a.data(f)!==a.data(d)&&!0===c.shiftKey){var e=!1;a(f).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass, 4 | d.checked);a(g).each(function(){if(a.data(this)===a.data(f)||a.data(this)===a.data(d))e=e?!1:!0;e&&a(this).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);f=d;h()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"]').click(function(a){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))}); 5 | a('form#changelist-form input[name="_save"]').click(function(c){var d=!1;a("select option:selected",b.actionContainer).each(function(){a(this).val()&&(d=!0)});if(d)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})}; 6 | a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery); 7 | -------------------------------------------------------------------------------- /pyas2/static/admin/js/collapse.js: -------------------------------------------------------------------------------- 1 | /*global gettext*/ 2 | (function($) { 3 | 'use strict'; 4 | $(document).ready(function() { 5 | // Add anchor tag for Show/Hide link 6 | $("fieldset.collapse").each(function(i, elem) { 7 | // Don't hide if fields in this fieldset have errors 8 | if ($(elem).find("div.errors").length === 0) { 9 | $(elem).addClass("collapsed").find("h2").first().append(' (' + gettext("Show") + 11 | ')'); 12 | } 13 | }); 14 | // Add toggle to anchor tag 15 | $("fieldset.collapse a.collapse-toggle").click(function(ev) { 16 | if ($(this).closest("fieldset").hasClass("collapsed")) { 17 | // Show 18 | $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]); 19 | } else { 20 | // Hide 21 | $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]); 22 | } 23 | return false; 24 | }); 25 | }); 26 | })(django.jQuery); 27 | -------------------------------------------------------------------------------- /pyas2/static/admin/js/collapse.min.js: -------------------------------------------------------------------------------- 1 | (function(a){a(document).ready(function(){a("fieldset.collapse").each(function(b,c){0===a(c).find("div.errors").length&&a(c).addClass("collapsed").find("h2").first().append(' ('+gettext("Show")+")")});a("fieldset.collapse a.collapse-toggle").click(function(b){a(this).closest("fieldset").hasClass("collapsed")?a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]):a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", 2 | [a(this).attr("id")]);return!1})})})(django.jQuery); 3 | -------------------------------------------------------------------------------- /pyas2/static/admin/js/inlines.min.js: -------------------------------------------------------------------------------- 1 | (function(b){b.fn.formset=function(d){var a=b.extend({},b.fn.formset.defaults,d),e=b(this);d=e.parent();var k=function(a,f,l){var c=new RegExp("("+f+"-(\\d+|__prefix__))");f=f+"-"+l;b(a).prop("for")&&b(a).prop("for",b(a).prop("for").replace(c,f));a.id&&(a.id=a.id.replace(c,f));a.name&&(a.name=a.name.replace(c,f))},h=b("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(h.val(),10),f=b("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),c=""===f.val()||0'+a.addText+""),m=d.find("tr:last a")):(e.filter(":last").after('"),m=e.filter(":last").next().find("a"));m.click(function(c){c.preventDefault();c=b("#"+a.prefix+ 3 | "-empty");var g=c.clone(!0);g.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);g.is("tr")?g.children(":last").append('"):g.is("ul")||g.is("ol")?g.append('
  • '+a.deleteText+"
  • "):g.children(":first").append(''+a.deleteText+"");g.find("*").each(function(){k(this, 4 | a.prefix,h.val())});g.insertBefore(b(c));b(h).val(parseInt(h.val(),10)+1);l+=1;""!==f.val()&&0>=f.val()-h.val()&&m.parent().hide();g.find("a."+a.deleteCssClass).click(function(c){c.preventDefault();g.remove();--l;a.removed&&a.removed(g);b(document).trigger("formset:removed",[g,a.prefix]);c=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(c.length);(""===f.val()||0 0) { 26 | values.push(field.val()); 27 | } 28 | }); 29 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 30 | }; 31 | 32 | prepopulatedField.data('_changed', false); 33 | prepopulatedField.change(function() { 34 | prepopulatedField.data('_changed', true); 35 | }); 36 | 37 | if (!prepopulatedField.val()) { 38 | $(dependencies.join(',')).keyup(populate).change(populate).focus(populate); 39 | } 40 | }); 41 | }; 42 | })(django.jQuery); 43 | -------------------------------------------------------------------------------- /pyas2/static/admin/js/prepopulate.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.prepopulate=function(e,f,g){return this.each(function(){var a=c(this),b=function(){if(!a.data("_changed")){var b=[];c.each(e,function(a,d){d=c(d);0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /pyas2/static/css/jquery-ui-timepicker-addon.css: -------------------------------------------------------------------------------- 1 | .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } 2 | .ui-timepicker-div dl { text-align: left; } 3 | .ui-timepicker-div dl dt { float: left; clear:left; padding: 0 0 0 5px; } 4 | .ui-timepicker-div dl dd { margin: 0 10px 10px 40%; } 5 | .ui-timepicker-div td { font-size: 90%; } 6 | .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } 7 | .ui-timepicker-div .ui_tpicker_unit_hide{ display: none; } 8 | 9 | .ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input { background: none; color: inherit; border: none; outline: none; border-bottom: solid 1px #555; width: 95%; } 10 | .ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input:focus { border-bottom-color: #aaa; } 11 | 12 | .ui-timepicker-rtl{ direction: rtl; } 13 | .ui-timepicker-rtl dl { text-align: right; padding: 0 5px 0 0; } 14 | .ui-timepicker-rtl dl dt{ float: right; clear: right; } 15 | .ui-timepicker-rtl dl dd { margin: 0 40% 10px 10px; } 16 | 17 | /* Shortened version style */ 18 | .ui-timepicker-div.ui-timepicker-oneLine { padding-right: 2px; } 19 | .ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time, 20 | .ui-timepicker-div.ui-timepicker-oneLine dt { display: none; } 21 | .ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label { display: block; padding-top: 2px; } 22 | .ui-timepicker-div.ui-timepicker-oneLine dl { text-align: right; } 23 | .ui-timepicker-div.ui-timepicker-oneLine dl dd, 24 | .ui-timepicker-div.ui-timepicker-oneLine dl dd > div { display:inline-block; margin:0; } 25 | .ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_minute:before, 26 | .ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before { content:':'; display:inline-block; } 27 | .ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_millisec:before, 28 | .ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_microsec:before { content:'.'; display:inline-block; } 29 | .ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide, 30 | .ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide:before{ display: none; } 31 | -------------------------------------------------------------------------------- /pyas2/static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/favicon.ico -------------------------------------------------------------------------------- /pyas2/static/images/icon-pass.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/icon-pass.gif -------------------------------------------------------------------------------- /pyas2/static/images/icon-pass_parse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/icon-pass_parse.gif -------------------------------------------------------------------------------- /pyas2/static/images/pyas2logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/pyas2logo.png -------------------------------------------------------------------------------- /pyas2/static/images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/star.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /pyas2/static/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/static/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /pyas2/static/js/dataTables.jqueryui.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * DataTables jQuery UI integration 3 | * ©2011-2014 SpryMedia Ltd - datatables.net/license 4 | * */ 5 | (function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,d){b||(b=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(b,d).$;return a(d,b,b.document)}:a(jQuery,window,document)})(function(a){var b=a.fn.dataTable;a.extend(!0,b.defaults,{dom:'<"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-tl ui-corner-tr"lfr>t<"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-bl ui-corner-br"ip>', 6 | renderer:"jqueryui"});a.extend(b.ext.classes,{sWrapper:"dataTables_wrapper dt-jqueryui",sPageButton:"fg-button ui-button ui-state-default",sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:"ui-state-default sorting_asc",sSortDesc:"ui-state-default sorting_desc",sSortable:"ui-state-default sorting",sSortableAsc:"ui-state-default sorting_asc_disabled",sSortableDesc:"ui-state-default sorting_desc_disabled", 7 | sSortableNone:"ui-state-default sorting_disabled",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead ui-state-default",sScrollFoot:"dataTables_scrollFoot ui-state-default",sHeaderTH:"ui-state-default",sFooterTH:"ui-state-default"});b.ext.renderer.header.jqueryui=function(b,h,e,c){var f="css_right ui-icon ui-icon-carat-2-n-s",g=-1!==a.inArray("asc",e.asSorting),i=-1!==a.inArray("desc",e.asSorting);!e.bSortable||!g&&!i?f="":g&&!i?f="css_right ui-icon ui-icon-carat-1-n":!g&&i&&(f="css_right ui-icon ui-icon-carat-1-s"); 8 | a("
    ").addClass("DataTables_sort_wrapper").append(h.contents()).append(a("").addClass(c.sSortIcon+" "+f)).appendTo(h);a(b.nTable).on("order.dt",function(a,g,i,j){b===g&&(a=e.idx,h.removeClass(c.sSortAsc+" "+c.sSortDesc).addClass("asc"==j[a]?c.sSortAsc:"desc"==j[a]?c.sSortDesc:e.sSortingClass),h.find("span."+c.sSortIcon).removeClass("css_right ui-icon ui-icon-triangle-1-n css_right ui-icon ui-icon-triangle-1-s css_right ui-icon ui-icon-carat-2-n-s css_right ui-icon ui-icon-carat-1-n css_right ui-icon ui-icon-carat-1-s").addClass("asc"== 9 | j[a]?"css_right ui-icon ui-icon-triangle-1-n":"desc"==j[a]?"css_right ui-icon ui-icon-triangle-1-s":f))})};b.TableTools&&a.extend(!0,b.TableTools.classes,{container:"DTTT_container ui-buttonset ui-buttonset-multi",buttons:{normal:"DTTT_button ui-button ui-state-default"},collection:{container:"DTTT_collection ui-buttonset ui-buttonset-multi"}});return b}); 10 | -------------------------------------------------------------------------------- /pyas2/templates/400.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %}{% endblock %} 5 | 6 | {% block title %}{% trans 'Client error (400)' %}{% endblock %} 7 | 8 | {% block content %} 9 |

    {% trans 'Client Error (400)' %}

    10 | {% if exc_info %} 11 |
    12 |         {{ exc_info }}
    13 |         
    14 | {% endif %} 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /pyas2/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans 'Page not found' %}{% endblock %} 5 | 6 | {% block content %} 7 | 8 |

    {% trans 'Page not found' %}

    9 | 10 |

    {% trans "We're sorry, but the requested page could not be found." %}

    11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /pyas2/templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %}{% endblock %} 5 | 6 | {% block title %}{% trans 'Server error (500)' %}{% endblock %} 7 | 8 | {% block content %} 9 |

    {% trans 'Server Error (500)' %}

    10 | {% if exc_info %} 11 |
    12 |         {{ exc_info }}
    13 |         
    14 | {% endif %} 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /pyas2/templates/admin/base.html: -------------------------------------------------------------------------------- 1 | {% load admin_static %} 2 | {% load pyas2_extras %} 3 | 4 | 5 | 6 | 7 | pyAS2 {% block title %}{% endblock %} 8 | 9 | 10 | {% block extrastyle %}{% endblock %} 11 | 12 | {% block extrahead %}{% endblock %} 13 | {% if LANGUAGE_BIDI %}{% endif %} 14 | 15 | 16 | 17 | 18 | 19 | {% load i18n %} 20 | 21 | 22 | 23 | {% if not is_popup %} 24 | 27 |
    28 |
    {% get_init "environment_text" %} SERVER
    29 |
    30 | {% include "pyas2/menu.html" %} 31 | {% endif %} 32 |
    33 | {% block messages %} 34 | {% if messages %} 35 |
      {% for message in messages %} 36 | {{ message|capfirst }} 37 | {% endfor %}
    38 | {% endif %} 39 | {% endblock messages %} 40 | 41 |
    42 | {% block pretitle %}{% endblock %} 43 | {% block content_title %}{% if title %}

    {{ title }}

    {% endif %}{% endblock %} 44 | {% block content %} 45 | {% block object-tools %}{% endblock %} 46 | {{ content }} 47 | {% endblock %} 48 | {% block sidebar %}{% endblock %} 49 |
    50 |
    51 | 52 | 53 | {% block footer %}{% endblock %} 54 |
    55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/about.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n %} 3 | {% block title %} 4 | Home 5 | {% endblock %} 6 | {% block content %} 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
    10 |

    {% trans 'pyAS2 Global Settings' %}

    11 | {% trans 'pyAS2 documentation' %}
    12 | {% trans 'pyAS2 Issue Tracker' %}
    13 |
    14 |
    {% trans 'Current user' %}{{ user.username }}
    {% trans 'Last login' %}{{ user.last_login|date:"Y-m-d G:i" }}
    Environment{{ pyas2info.environment }}
    Port{{ pyas2info.port }}
    Python Path{{ pyas2info.python_path }}
    Manage.py Path{{ pyas2info.managepy_path }}
    Base Data Dir{{ pyas2info.root_dir }}
    ASYNC MDN Receive URL{{ pyas2info.mdn_url }}
    ASYNC MDN Max Wait Mins{{ pyas2info.async_mdn_wait }}
    Max Retries{{ pyas2info.max_retries }}
    Log Folder{{ pyas2info.log_dir }}
    Log Level{{ pyas2info.log_level }}
    Log Console{{ pyas2info.log_console }}
    Log Console Level{{ pyas2info.log_console_level }}
    Max Archive Days{{ pyas2info.max_arch_days }}
    63 | {% endblock %} 64 | 65 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/file_view.html: -------------------------------------------------------------------------------- 1 | {% load admin_static %} 2 | 3 | 4 | pyAS2 File Viewer 5 | 6 | 7 | 8 | 9 | {% load i18n %} 10 | 11 | {% if error_content %} 12 | {{ error_content }} 13 | {% else %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 30 | 31 |
    {{ file_obj.type }}{{ file_obj.name }}{{ file_obj.direction }}{% trans 'Download' %} 22 |
    Headers 23 | 24 | {% for key,value in file_obj.headers.items %} 25 | 26 | {% endfor %} 27 |
    {% trans key %}{{ value }}
    28 |
    29 |
    32 |
    {{ file_obj.content }}
    33 |
    34 |
    35 | {% endif %} 36 | 37 | 38 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/mdn_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n static %} 3 | {% block title %} 4 | MDNs 5 | {% endblock %} 6 | 7 | {% block content %} 8 |

    MDN List

    9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% for row in page_obj.object_list %} 24 | {% if row.omessage %} 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 41 | {% endif %} 42 | {% endfor %} 43 | 44 |
    {% trans 'Timestamp' %}{% trans 'Status' %}{% trans 'Message ID' %}{% trans 'Original Message ID' %}{% trans 'Organization' %}{% trans 'Partner' %}{% trans 'Mode' %}{% trans 'Signed' %}
    {{row.timestamp|date:"Y-m-d H:i:s" }}{{row.get_status_display}}{{row.message_id}}{{row.omessage.message_id}}{{row.omessage.organization}}{{row.omessage.partner}}{{row.omessage.get_mdn_mode_display}} 34 | {% if row.signed %} 35 | 36 | {% else %} 37 | 38 | {% endif %} 39 |
    45 | 46 | {% include "pyas2/pagination.html" %} 47 | {% endblock %} 48 | 49 | 50 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/mdn_search.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n %} 3 | {% load pyas2_extras %} 4 | {% block title %} 5 | Search MDNs 6 | {% endblock %} 7 | {% load static %} 8 | 9 | 11 | {% block extrahead %} 12 | 13 | 14 | 15 | 16 | 17 | 34 | {% endblock %} 35 | 36 | {% block content %} 37 |

    Select MDNs

    38 |

     Make your required selections below:

    39 |
    40 |
    {% csrf_token %} 41 | 42 | {{ form.as_table }} 43 |
    44 |
      45 |

    46 | 47 |
    48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/menu.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 64 | 65 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/message_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n static %} 3 | {% block title %} 4 | Message 5 | {% endblock %} 6 | {% block content %} 7 |

    Details of message {{message.message_id}}

    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
    {% trans 'Timestamp' %}{{message.timestamp|date:"Y-m-d H:i:s"}}
    {% trans 'Status' %}{{message.get_status_display}}
    {% trans 'Direction' %}{{message.get_direction_display}}
    {% trans 'Organization' %}{{message.organization}}
    {% trans 'Partner' %}{{message.partner}}
    {% trans 'Compressed' %} 17 | {% if message.compressed %} 18 | 19 | {% else %} 20 | 21 | {% endif %} 22 |
    {% trans 'Encrypted' %} 27 | {% if message.encrypted %} 28 | 29 | {% else %} 30 | 31 | {% endif %} 32 |
    {% trans 'Signed' %} 37 | {% if message.signed %} 38 | 39 | {% else %} 40 | 41 | {% endif %} 42 |
    {% trans 'Payload' %}{% if message.payload %} {{message.payload}}{% endif %}
    {% trans 'MDN' %}{% if message.mdn %}{{message.mdn}}{% endif %}
    50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {% for log in logs %} 59 | 60 | 61 | 70 | 71 | 72 | {% endfor %} 73 | 74 |
    {{log.timestamp|date:"Y-m-d H:i:s"}} 62 | {% if log.status == "S" %} 63 | 64 | {% elif log.status == "E" %} 65 | 66 | {% elif log.status == "W" %} 67 | 68 | {% endif %} 69 | {{log.text}}
    75 | {% endblock %} 76 | 77 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/message_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n static pyas2_extras%} 3 | {% block title %} 4 | Messages 5 | {% endblock %} 6 | 7 | {% block content %} 8 |

    Message List

    9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% for row in page_obj.object_list %} 26 | 27 | 47 | 48 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {% endfor %} 69 | 70 |
    {% trans 'Timestamp' %}{% trans 'Direction' %}{% trans 'Status' %}{% trans 'Message ID' %}{% trans 'Organization' %}{% trans 'Partner' %}{% trans 'Payload' %}{% trans 'MDN Mode' %}{% trans 'MDN' %}
    28 | 46 | {{row.timestamp|date:"Y-m-d H:i:s" }}{{row.get_direction_display}} 49 | {% if row.status == "S" %} 50 | 51 | {% elif row.status == "E" %} 52 | 53 | {% elif row.status == "W" or row.status == "R" %} 54 | 55 | {% elif row.status == "P" %} 56 | 57 | {% elif row.status == "IP" %} 58 | 59 | {% endif %} 60 | {{row.message_id}}{{row.organization}}{{row.partner}}{% if row.payload %} View Payload{% endif %}{{row.get_mdn_mode_display}}{% if row.mdn %}View MDN{% endif %}
    71 | 72 | 73 | {% include "pyas2/pagination.html" %} 74 | 75 | {% endblock %} 76 | 77 | 78 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/message_search.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n %} 3 | {% load static %} 4 | {% load pyas2_extras %} 5 | {% block title %} 6 | Search Messages 7 | {% endblock %} 8 | {% block extrahead %} 9 | 10 | 11 | 12 | 13 | 14 | 31 | {% endblock %} 32 | 33 | {% block content %} 34 |

    Select Messages

    35 |

     Make your required selections below:

    36 |
    37 |
    {% csrf_token %} 38 | 39 | {{ form.as_table }} 40 |
    41 |
      42 |

    43 | 44 |
    45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/pagination.html: -------------------------------------------------------------------------------- 1 | {% load i18n pyas2_extras %} 2 |
    3 |

    Showing {{ page_obj.start_index }} to 4 | {{ page_obj.end_index }} of {{ page_obj.paginator.count }} entries

    5 | 6 | {% if page_obj.has_previous %} 7 | Previous 8 | {% endif %} 9 | 10 | 11 | Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }} 12 | 13 | 14 | {% if page_obj.has_next %} 15 | Next 16 | {% endif %} 17 | 18 |
    19 | 20 | -------------------------------------------------------------------------------- /pyas2/templates/pyas2/sendmessage.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n %} 3 | {% load static %} 4 | {% block title %} 5 | Send Message 6 | {% endblock %} 7 | {% block content %} 8 |

    Select File to Send

    9 |

     Make your required selections below:

    10 |
    11 |
    {% csrf_token %} 12 | 13 | {{ form.as_table }} 14 |
    15 |
      16 |

    17 | 18 |
    19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /pyas2/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/templatetags/__init__.py -------------------------------------------------------------------------------- /pyas2/templatetags/pyas2_extras.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from pyas2 import pyas2init 3 | 4 | register = template.Library() 5 | 6 | 7 | @register.simple_tag 8 | def get_init(key): 9 | return pyas2init.gsettings.get(key,'') 10 | 11 | 12 | def easy_tag(func): 13 | """deal with the repetitive parts of parsing template tags""" 14 | 15 | def inner(parser, token): 16 | # print token 17 | try: 18 | return func(*token.split_contents()) 19 | except TypeError: 20 | raise template.TemplateSyntaxError( 21 | 'Bad arguments for tag "%s"' % token.split_contents()[0]) 22 | 23 | inner.__name__ = func.__name__ 24 | inner.__doc__ = inner.__doc__ 25 | return inner 26 | 27 | 28 | class AppendGetNode(template.Node): 29 | def __init__(self, dict): 30 | self.dict_pairs = {} 31 | for pair in dict.split(','): 32 | pair = pair.split('=') 33 | self.dict_pairs[pair[0]] = template.Variable(pair[1]) 34 | 35 | def render(self, context): 36 | request = context['request'] 37 | get = request.GET.copy() 38 | for k, v in self.dict_pairs.items(): 39 | get[k] = v.resolve(context) 40 | return "%s?%s" % (request.path, get.urlencode()) 41 | 42 | 43 | @register.tag() 44 | @easy_tag 45 | def append_to_get(_tag_name, q_dict): 46 | return AppendGetNode(q_dict) 47 | -------------------------------------------------------------------------------- /pyas2/test_settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for pyas2_dev project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.9.7. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.9/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'bf8&ly_hw%oe(vn5qx^jkh*$xzqv5i4_^as-1=n50ze^ja$zmm' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'pyas2', 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | ] 42 | 43 | MIDDLEWARE_CLASSES = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ] 53 | 54 | ROOT_URLCONF = 'pyas2.tests.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [], 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | 73 | # Database 74 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 75 | 76 | DATABASES = { 77 | 'default': { 78 | 'ENGINE': 'django.db.backends.sqlite3', 79 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 80 | } 81 | } 82 | 83 | 84 | # Password validation 85 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 86 | 87 | AUTH_PASSWORD_VALIDATORS = [ 88 | { 89 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 90 | }, 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 99 | }, 100 | ] 101 | 102 | 103 | # Internationalization 104 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 105 | 106 | LANGUAGE_CODE = 'en-us' 107 | 108 | TIME_ZONE = 'UTC' 109 | 110 | USE_I18N = True 111 | 112 | USE_L10N = True 113 | 114 | USE_TZ = True 115 | 116 | 117 | # Static files (CSS, JavaScript, Images) 118 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 119 | 120 | STATIC_URL = '/static/' 121 | 122 | PYAS2 = { 123 | 'ENVIRONMENT': 'production', 124 | 'PORT': 8080, 125 | 'ENVIRONMENTTEXT': 'BETA', 126 | 'ENVIRONMENTTEXTCOLOR': 'Yellow', 127 | 'LOGLEVEL': 'INFO', 128 | 'LOGCONSOLE': True, 129 | 'LOGCONSOLELEVEL': 'INFO', 130 | 'MAXRETRIES': 5, 131 | 'MDNURL': 'https://127.0.0.1:8080/pyas2/as2receive', 132 | 'ASYNCMDNWAIT': 30, 133 | 'MAXARCHDAYS': 30, 134 | } 135 | 136 | SESSION_COOKIE_NAME = 'pyas2old' 137 | -------------------------------------------------------------------------------- /pyas2/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/tests/__init__.py -------------------------------------------------------------------------------- /pyas2/tests/fixtures/as2client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDLjCCAhYCCQCGVDGniU2WiDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJJ 3 | TjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 4 | cyBQdHkgTHRkMRIwEAYDVQQDDAlhczJjbGllbnQwHhcNMTcxMjIwMDkxMzU5WhcN 5 | MjIxMjE5MDkxMzU5WjBZMQswCQYDVQQGEwJJTjETMBEGA1UECAwKU29tZS1TdGF0 6 | ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlh 7 | czJjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH197he/Si 8 | jOLzKSx5+agYFwy8g/oZsShaCkmksLAuJAukvKqvrhjT4hVipVB03BEQXVuZpYLU 9 | NxXJJ5b0/Jx2hL7gndwP4qBcbFDdZSZHWwrahB992Y4OzRgwfEUx5cPyNdJ2x+Nj 10 | NcJ6TPKryUOYkRkkF7JsmeC5Bt6XStwW3xg0LBU4JrYrrM9Y40w0z8UPIu1E5trf 11 | 7wVq+oRs6w793rXLQtgeCuNnfqvNfw/GaeYFu3FigK4qvuWbc5sYn8YwAgEiaX3q 12 | EbtAInQEFCnA2in7f1ur+Po97XA8x3ov/kyFGvuEiHID0Jhqxdww50lyqdfr0Ch2 13 | A3HNV23Pj2GhAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGeaT4BWBZ01DY/nVIr9 14 | 5ouZ+G25SI15IiSkbJGBppGeb0O/xRywMlGYLcH+I22K9W7BiRFY1cQGV10W5waX 15 | HcOnXxyCH34f+Xl9tJ0tRMk2inPmm1tkDbmFydSqZKZ4m1uDZJHENjnzHW/dI7pf 16 | vFxBI+QP0G0991yXJWt0kuWs1CccusgydzmvbUIM5v1bo32dmewZ1VFfvMv9Wp4+ 17 | 3X1UivEK5dQ68MDD5hcLidc6juJEKAgcmLuQEvMmPCoJd3nsZ9N8dNzPNSDnlCFV 18 | dqefp5XZfjIJA/+a4eQDhHqO+EwJCoMDLCT+AEcFk3A6di8TfmFQ2qY8msUQSEMH 19 | z+o= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /pyas2/tests/fixtures/as2client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIZfBjMQm7dAgCAggA 3 | MB0GCWCGSAFlAwQBKgQQ2MezwMvMu2Z7GaDr+QXqdQSCBNDRez/a6sh2FhLy6Om7 4 | 3A6ORqS6MNIxlWmKymoI12G2A+MI00nJcKXzQsuE4S1AAOtXUSmyxNY8Ynaq7dY9 5 | 9HJEkZcjfv3KN83H6oq3QYwQoFWVjnObqkdLyfcaQ19B4PDMdpQUD8PazjOCJd0B 6 | Kn0geRs7XpprWDA1x++bN5dFOLcZnS2OGCp63CFIlvA23Sfuf9C35yonoGOxGJQT 7 | bZZoO13pcGbQJsbBEwrQWSWg1Tp8ht8+YwWlqO1QwOGlWksELRe4hzi5ZjAvajJl 8 | Hc+BOypA4yhodoK/H8vSJdqNckYHQoMr8z0XhIjB6O2o/lXnb+p4HCouKN3wai3h 9 | yCiyzTzDrLlIzEBB+mL1fc2gVYB+gR31Idgb3AX+vzebJjvzQCTFcSy0DsJYuJQH 10 | I+29uyx5DGDZfiyUXPVg9CsmORFPOHM1a21Fj/DYwUegBLYqWv4IIfAp3qXAulbe 11 | IfoqWdwA84kUzyfv3v5teLt1qJc/L8iCbz2XhoDUGgPskad8gIKRxQbkGgTj5bey 12 | goOVKfni54II0a/7vf1I9Mr+5qS6PC1xRftL8gfhZA+Cr9AVUq5XvhZBfFEjyoZ8 13 | e1W4jCtlLg0aF1ti3DVrJpyjgkGTGJ68L+nPyZhh2k6VqCNSH9WCwqWheYKZr6UL 14 | 7jSedq9ET2sbZ+8FoWlTC3ewYIbZfpKxf4i+VJiyXQbqyKAjMqPzVnwbNNfxMMCk 15 | lOwqULF7oqbnFAkwAM3IohgmqZlUm4R59WBadYReyf6zF3Y1B1xJeO+2vNNQ4x7r 16 | cg6XflxKgSH3p8Qoyvx+70nxYddBuOb1OzBpqW03DxWKa69DBh8VBWfhg8bKiGzo 17 | hVfdmvGfrYsd47T8or75HHviqUH/uxFKzaYBpN9PPY1SpOCqSixSASLaR1H1CyLf 18 | 0kaH8avik1Y2fw6UoSK8faxuhYVHRD+K4Ds5kugeoNMcHKFIJs0b5t0jUtnGwQpB 19 | sBbL4wlPI/HVBitsmKD42kHMaB8tA63jBvYzVmjSbWRumm20k0doqf3AavRr/sjp 20 | L7mdN++nqy24HxfbzVG8GbIvSIKbxlPh32cwlR/i8tM4KWFv1z9+/yIBeAQcx8z/ 21 | jklEKHP/Qx/zQfpBmjF5q+E+o65ZfR1n6oH0CLjr8h8U53KV6ifyNvruHsJAeDjA 22 | JI/p+Hae0Ao1xv7KugzI11LhFHpfcRXT3Z50Y3ik20r2129sPVYvq00KB15zr+G8 23 | //ZoRO29IzGsT/vG10SSCnOf/07UJU3kHU49/eUfJMgheTnjDXVmc6fEsBh8NJwi 24 | M0+yfk0RO5AMvUzth6x1fBYYpYSwpXDqHQyKVZjEmccS6ZmPs2mulMJwrqqbDe+3 25 | pk6E6H0PHQg8GB1UkRu1qBLAHRL8VG29xpA7uu5+BK/KcxdCyUoydZagCIko7T7r 26 | RlkpgOnBqzNgYxtroAJiTK1LrPrN7CYvY8igQD72YLnQL8Qx4E+0+Te78OuFZm4u 27 | sN8IjqgaSkvO8ilLF+K8qWNKY6NOeTwL7rd+OMDFkon+Ck38Gd2lm3K/PbEDFL5i 28 | JEUTCGkEZpfY9ozDRQfrfNLe5GbdaLeVag+GlPAxqwcsp3MrF4lhb+2L/dCaBvoY 29 | 3macQVgE8ngvS28BiJGO7OZ6jA== 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -----BEGIN CERTIFICATE----- 32 | MIIDLjCCAhYCCQCGVDGniU2WiDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJJ 33 | TjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 34 | cyBQdHkgTHRkMRIwEAYDVQQDDAlhczJjbGllbnQwHhcNMTcxMjIwMDkxMzU5WhcN 35 | MjIxMjE5MDkxMzU5WjBZMQswCQYDVQQGEwJJTjETMBEGA1UECAwKU29tZS1TdGF0 36 | ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlh 37 | czJjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH197he/Si 38 | jOLzKSx5+agYFwy8g/oZsShaCkmksLAuJAukvKqvrhjT4hVipVB03BEQXVuZpYLU 39 | NxXJJ5b0/Jx2hL7gndwP4qBcbFDdZSZHWwrahB992Y4OzRgwfEUx5cPyNdJ2x+Nj 40 | NcJ6TPKryUOYkRkkF7JsmeC5Bt6XStwW3xg0LBU4JrYrrM9Y40w0z8UPIu1E5trf 41 | 7wVq+oRs6w793rXLQtgeCuNnfqvNfw/GaeYFu3FigK4qvuWbc5sYn8YwAgEiaX3q 42 | EbtAInQEFCnA2in7f1ur+Po97XA8x3ov/kyFGvuEiHID0Jhqxdww50lyqdfr0Ch2 43 | A3HNV23Pj2GhAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGeaT4BWBZ01DY/nVIr9 44 | 5ouZ+G25SI15IiSkbJGBppGeb0O/xRywMlGYLcH+I22K9W7BiRFY1cQGV10W5waX 45 | HcOnXxyCH34f+Xl9tJ0tRMk2inPmm1tkDbmFydSqZKZ4m1uDZJHENjnzHW/dI7pf 46 | vFxBI+QP0G0991yXJWt0kuWs1CccusgydzmvbUIM5v1bo32dmewZ1VFfvMv9Wp4+ 47 | 3X1UivEK5dQ68MDD5hcLidc6juJEKAgcmLuQEvMmPCoJd3nsZ9N8dNzPNSDnlCFV 48 | dqefp5XZfjIJA/+a4eQDhHqO+EwJCoMDLCT+AEcFk3A6di8TfmFQ2qY8msUQSEMH 49 | z+o= 50 | -----END CERTIFICATE----- 51 | -------------------------------------------------------------------------------- /pyas2/tests/fixtures/as2server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDLjCCAhYCCQD7SuhYur9VTTANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJJ 3 | TjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 4 | cyBQdHkgTHRkMRIwEAYDVQQDDAlhczJzZXJ2ZXIwHhcNMTcxMjIwMDkxNDU3WhcN 5 | MjIxMjE5MDkxNDU3WjBZMQswCQYDVQQGEwJJTjETMBEGA1UECAwKU29tZS1TdGF0 6 | ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlh 7 | czJzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNC0Vq/TJz 8 | Qasi8VqCvMhDRSN68C00J4GbDGxbbIjpXZ9+4wKd7JcPm6HOsVfQK0xxbtox/BGP 9 | 392Hwz2gjn9nEgwuE7wJD0c5zFrRcQlG1avF0CBgFPa1PuSyTrH8JJ+OFK5dO0Su 10 | W5RfaW/CAwp65mVYcGhWKvQ+D7alCvQ8VD50PMj/vw3Wdsry9TQ44VtAz5WUK/pd 11 | AeNbnyMRS4984o4ycUiGWI1hI3xgzFGmLrBEaSBMxTOrifpx1SnE8pRkX3iLO93E 12 | ec0QlNdUdc+mSOSEnEayANuxcQFegFIDajMs+jGVzCu0hDfQx9IfKSwhIc/Ay0v9 13 | ONyTdapqopgVAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAESihgqCRSt5v2aIcoUj 14 | BgvX4nZw0RP/rD8cGc3LA/kDLiRne/tZRzCNPPZrEjO3pyBwI1XzaFP6jxcFPVPS 15 | JefBg2KZVoY2sRNaoXru9x8QWVbrdwWaoLg+v6Oj9iwr9CqMMEa9xegEjje87Sga 16 | gSfYasgEWmx0g+l1rbLxkBeUfDKSGRMqi3r9MryV9udTao+4G7H8WFSHThActlxV 17 | BQAHYVMlr6+O16AMwbKwJWIJ5jT8F8pe4aWZWtd0+EzrmP0MxQvEgObD1gk28miQ 18 | 6MkIbx+9vkBytM9LlME1YUWvQfBy8lKt93+FiTDplpwgDau7pTGGqXJen/wYjq+w 19 | Bxo= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /pyas2/tests/fixtures/as2server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIBkTXi4mo7gUCAggA 3 | MB0GCWCGSAFlAwQBKgQQegRDZRY+TL4QgRAWcqdz7wSCBNCGs2pr91erMuGIN8P0 4 | BQPmi4ohcUmhI+q/jtSYIGhkdsV9HTnVncMdr77RO+8xVn9QGpJFxTs+zhOzdsqK 5 | SIcB1EbBjg2OXZ6tKID0Xc2L4ZBGLEV230m995IiiGqPkpF+JYqzcsbVTPFPgs/Y 6 | V4crs3BAJfPw3jgH92++7C5Kvn7hLy8JYbnpGb8mEBoM4QIZ0forKPwOQTQtWQ/W 7 | 82hnEiMEoYIRjdWMAxPIdBBZEsMd55b0jVNxIW/1JZWM+yp9FZNrE7XobzVXUQSo 8 | 6CRqEYvBzJ6+X223bMac8X100zl7NzXxCns8/JN9ts+6x89cqdhCxwjLRlixovvR 9 | tPla9JFFLvie94gd685D5WtKfg6srhNCqr2j8nSIC3FrXyAnOeLJavznxOstey5b 10 | jt1zK6RunZgO9SuBpq5qSr4huUiH7edbMw8WnNhY/ur51GBpjiE4XIVbsPVoeCjz 11 | CL4XgGoJExOSj7n3IvZCTXKxQ9G9M8nk3LYPmIuAEKFduErarwML3GtJsj1r6HbD 12 | BS+WD18BZv4YhhLqPIlwwPszVUNp6NX/AGhs8URGYTTV5iA37doKR+rN6GXVCwDA 13 | Us4xdIdNfVMs/PNDlV4qZ4VrnC2w/6n3N2/K1EwmDPxICaWAtnXBDWMQiXjXPsSW 14 | 8TUIjZMCFgzIqg7PSh4wtIlaz4xmV3EIjyw2oQVc8NRK01TEhW4ZvEi3WEQB16Un 15 | fu24OpNPSDYyeUBbnNQ1bF+Hg2d2d/OiGR8Fma/dW2obhFJVz7CDXt0LeazYR3wZ 16 | 4tIdec4t5cxRb+CTlpdv+4AcvPYC3y4nwDYxUAO1rKQthnFCkrWm/Uy6PxbF83NS 17 | 95/6YuMoKb3bYZQSe566F5t/SL6zEYOFNiLWRbYqtLE1ICoAKus7AhbaLQuLsVW0 18 | /0zYCDVuc5cNt3Lk1MlFc7m8h+jVRroQpipdG+5UslSNYZJIh5QhGPcly+c0vHpa 19 | mDIX3nv7o4SdJAOuEek4XLRb9Ov/2JC3ajkr2NLXiNyH2HUvDGVujLzOE2ZfUozE 20 | u8EjmYY1bTIJuq5+86IRt5QWchs1jWKklgo3PIpZGmUk2CxdgyoA9BHFR9TVQn+j 21 | BxeKDJFbYX5GG/pByFe2EMllF6yN4PQyeEUMFlo0Tv5o0vsh2nwlkUZxpvPfU188 22 | M+YIZ9wv1Wkcv+xjjHCSMuLDFS5Ajc+5as7eE0gwKabmEmj/z8/0b/cyLBfbpOt7 23 | 87lul9b5Se5UJd83rRZE+QjFUzRWxeGJcHrFh6s3eTJIJUlQLhlcbUSowq7hWjti 24 | 0j+YIkGmFdk5QpEXR/+3DYUwXAemoBWz3eXs4NF09mZ/qASpA67xU7tXKMxl+Aoh 25 | HHS89RiTUetdu4Y6GiLtp31D5VsEJvqel0beiS16KK1mayPJjW1FOLcH2X56Ew04 26 | d+2dsFEk/3gGTrHP8MXJqa3kHjc0erdVlIkJBpB91A5VQjUaYXA6V+kMeKKUAZFg 27 | 2bolAGt1i3aCpYtosGEOdrlP7LTcwBi6QgmJs6IBuELnT5F+kyGEdqgwyhToduHS 28 | yQ9e/pyExp8aK3YOqMCSP9yj49aPHkhmnyKNp6pjw1ar3EY3sUcWvhyDhq41sjq6 29 | hPQEpLerIScoJyTuDTg0WfIlIA== 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -----BEGIN CERTIFICATE----- 32 | MIIDLjCCAhYCCQD7SuhYur9VTTANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJJ 33 | TjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 34 | cyBQdHkgTHRkMRIwEAYDVQQDDAlhczJzZXJ2ZXIwHhcNMTcxMjIwMDkxNDU3WhcN 35 | MjIxMjE5MDkxNDU3WjBZMQswCQYDVQQGEwJJTjETMBEGA1UECAwKU29tZS1TdGF0 36 | ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlh 37 | czJzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNC0Vq/TJz 38 | Qasi8VqCvMhDRSN68C00J4GbDGxbbIjpXZ9+4wKd7JcPm6HOsVfQK0xxbtox/BGP 39 | 392Hwz2gjn9nEgwuE7wJD0c5zFrRcQlG1avF0CBgFPa1PuSyTrH8JJ+OFK5dO0Su 40 | W5RfaW/CAwp65mVYcGhWKvQ+D7alCvQ8VD50PMj/vw3Wdsry9TQ44VtAz5WUK/pd 41 | AeNbnyMRS4984o4ycUiGWI1hI3xgzFGmLrBEaSBMxTOrifpx1SnE8pRkX3iLO93E 42 | ec0QlNdUdc+mSOSEnEayANuxcQFegFIDajMs+jGVzCu0hDfQx9IfKSwhIc/Ay0v9 43 | ONyTdapqopgVAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAESihgqCRSt5v2aIcoUj 44 | BgvX4nZw0RP/rD8cGc3LA/kDLiRne/tZRzCNPPZrEjO3pyBwI1XzaFP6jxcFPVPS 45 | JefBg2KZVoY2sRNaoXru9x8QWVbrdwWaoLg+v6Oj9iwr9CqMMEa9xegEjje87Sga 46 | gSfYasgEWmx0g+l1rbLxkBeUfDKSGRMqi3r9MryV9udTao+4G7H8WFSHThActlxV 47 | BQAHYVMlr6+O16AMwbKwJWIJ5jT8F8pe4aWZWtd0+EzrmP0MxQvEgObD1gk28miQ 48 | 6MkIbx+9vkBytM9LlME1YUWvQfBy8lKt93+FiTDplpwgDau7pTGGqXJen/wYjq+w 49 | Bxo= 50 | -----END CERTIFICATE----- 51 | -------------------------------------------------------------------------------- /pyas2/tests/fixtures/si_public_key.ca: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC 3 | VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 4 | cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs 5 | IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz 6 | dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy 7 | NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu 8 | dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt 9 | dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 10 | aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj 11 | YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 12 | AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T 13 | RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN 14 | cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW 15 | wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 16 | U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 17 | jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP 18 | BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN 19 | BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ 20 | jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ 21 | Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 22 | 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R 23 | nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH 24 | VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== 25 | -----END CERTIFICATE----- 26 | -----BEGIN CERTIFICATE----- 27 | MIIFDjCCA/agAwIBAgIMDulMwwAAAABR03eFMA0GCSqGSIb3DQEBCwUAMIG+MQsw 28 | CQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2Vl 29 | IHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMDkg 30 | RW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MTIwMAYDVQQD 31 | EylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0x 32 | NTEwMDUxOTEzNTZaFw0zMDEyMDUxOTQzNTZaMIG6MQswCQYDVQQGEwJVUzEWMBQG 33 | A1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5l 34 | dC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTIgRW50cnVzdCwgSW5jLiAt 35 | IGZvciBhdXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENlcnRp 36 | ZmljYXRpb24gQXV0aG9yaXR5IC0gTDFLMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 37 | MIIBCgKCAQEA2j+W0E25L0Tn2zlem1DuXKVh2kFnUwmqAJqOV38pa9vH4SEkqjrQ 38 | jUcj0u1yFvCRIdJdt7hLqIOPt5EyaM/OJZMssn2XyP7BtBe6CZ4DkJN7fEmDImiK 39 | m95HwzGYei59QAvS7z7Tsoyqj0ip/wDoKVgG97aTWpRzJiatWA7lQrjV6nN5ZGhT 40 | JbiEz5R6rgZFDKNrTdDGvuoYpDbwkrK6HIiPOlJ/915tgxyd8B/lw9bdpXiSPbBt 41 | LOrJz5RBGXFEaLpHPATpXbo+8DX3Fbae8i4VHj9HyMg4p3NFXU2wO7GOFyk36t0F 42 | ASK7lDYqjVs1/lMZLwhGwSqzGmIdTivZGwIDAQABo4IBDDCCAQgwDgYDVR0PAQH/ 43 | BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsG 44 | AQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAwBgNVHR8EKTAnMCWgI6Ah 45 | hh9odHRwOi8vY3JsLmVudHJ1c3QubmV0L2cyY2EuY3JsMDsGA1UdIAQ0MDIwMAYE 46 | VR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAd 47 | BgNVHQ4EFgQUgqJwdN28Uz/Pe9T3zX+nYMYKTL8wHwYDVR0jBBgwFoAUanImetAe 48 | 733nO2lR1GyNn5ASZqswDQYJKoZIhvcNAQELBQADggEBADnVjpiDYcgsY9NwHRkw 49 | y/YJrMxp1cncN0HyMg/vdMNY9ngnCTQIlZIv19+4o/0OgemknNM/TWgrFTEKFcxS 50 | BJPok1DD2bHi4Wi3Ogl08TRYCj93mEC45mj/XeTIRsXsgdfJghhcg85x2Ly/rJkC 51 | k9uUmITSnKa1/ly78EqvIazCP0kkZ9Yujs+szGQVGHLlbHfTUqi53Y2sAEo1GdRv 52 | c6N172tkw+CNgxKhiucOhk3YtCAbvmqljEtoZuMrx1gL+1YQ1JH7HdMxWBCMRON1 53 | exCdtTix9qrKgWRs6PLigVWXUX/hwidQosk8WwBD9lu51aX8/wdQQGcHsFXwt35u 54 | Lcw= 55 | -----END CERTIFICATE----- 56 | -------------------------------------------------------------------------------- /pyas2/tests/fixtures/si_public_key.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFQzCCBCugAwIBAgIRAPyxGMfr4QFOAAAAAFDb+P8wDQYJKoZIhvcNAQELBQAw 3 | gboxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL 4 | Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg 5 | MjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAs 6 | BgNVBAMTJUVudHJ1c3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMUswHhcN 7 | MTcwMzI0MTgwODAzWhcNMjAwNjIzMTgzODAxWjBoMQswCQYDVQQGEwJVUzEOMAwG 8 | A1UECBMFVGV4YXMxDzANBgNVBAcTBlRlbXBsZTEdMBsGA1UEChMUTWNMYW5lIENv 9 | bXBhbnksIEluYy4xGTAXBgNVBAMTEGIyYi5tY2xhbmVjby5jb20wggEiMA0GCSqG 10 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDDv75fHPPyLdBRQkNlkQuk2sKO//abQ+L 11 | mp2xSrHWnnWpTAcuu9H6MQDKPkQKu0mUzNh1WexfmrnutuZeLOmJLTujTuYqp9Hc 12 | p6jKlsQeR9tBe1lVFRNI7L1uHdwiiBFOhViUwsBwWDO1fZ7aUfBXQJrduxeE6O42 13 | 8PaPtk9LP5vsFj6L8MKDskbNee8/v24MPje5e+EesLxmVRESSnC8xV651BQT6lzU 14 | m/bFEzGV8RQLo1Cv6/Qsdb56I2PZYWJyLVItB4h3WvCuZYkwZtzZCShaW4ZV1hGS 15 | IBlHyrvX7CARBTeBWsx0myu7Emvshrk1mSfRwxsm8jTMK/RVP7VVAgMBAAGjggGT 16 | MIIBjzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwMwYDVR0f 17 | BCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9sZXZlbDFrLmNybDBL 18 | BgNVHSAERDBCMDYGCmCGSAGG+mwKAQUwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3 19 | dy5lbnRydXN0Lm5ldC9ycGEwCAYGZ4EMAQICMGgGCCsGAQUFBwEBBFwwWjAjBggr 20 | BgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMwYIKwYBBQUHMAKGJ2h0 21 | dHA6Ly9haWEuZW50cnVzdC5uZXQvbDFrLWNoYWluMjU2LmNlcjAxBgNVHREEKjAo 22 | ghBiMmIubWNsYW5lY28uY29tghR3d3cuYjJiLm1jbGFuZWNvLmNvbTAfBgNVHSME 23 | GDAWgBSConB03bxTP8971PfNf6dgxgpMvzAdBgNVHQ4EFgQUiTGHatRioLvWttlv 24 | dXrAH6AKVbIwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEAAr7qLcJUTyYc 25 | 9COEI84PTLZx1tRbzZWBzVk3Xa3ucNJY+ifii9LmiU9IZS+Mn+ikN71u7Npj3PBq 26 | rutMS03P/ILObp1Ankil2jVxpQcy1d/VGKSis9IhMmQWzIUqOFfsbZ6SsirQA2Y4 27 | Vz5GGyR6VG37Gn5fZJXKXeottFVVLZkE+/FC+AJJWNGEgt3quo6GENz+3/LgtkUZ 28 | KGlIIBNCrB6/mTTR03MKYiNtxrMgnmcgVtc8W8g1zsXdaTKcpJzZwVKwNuqw6YfE 29 | teP7dKGOKPvqL/i23fHBBKx7DdHRlvVlL04FAK/YuXq06TFOf/AG626j3uxwmRQ2 30 | 7AL3IEu8sA== 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /pyas2/tests/fixtures/si_signed.mdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/tests/fixtures/si_signed.mdn -------------------------------------------------------------------------------- /pyas2/tests/fixtures/si_signed_cmp.msg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishek-ram/pyas2/e19cabae37d01be943e1fa041c1f4b74c5ca3012/pyas2/tests/fixtures/si_signed_cmp.msg -------------------------------------------------------------------------------- /pyas2/tests/fixtures/testmessage.edi: -------------------------------------------------------------------------------- 1 | UNB+UNOA:2+:14+:14+140407:0910+5++++1+EANCOM' 2 | UNH+1+ORDERS:D:96A:UN:EAN008' 3 | BGM+220+1AA1TEST+9' 4 | DTM+137:20140407:102' 5 | DTM+63:20140421:102' 6 | DTM+64:20140414:102' 7 | RFF+ADE:1234' 8 | RFF+PD:1704' 9 | NAD+BY+5450534000024::9' 10 | NAD+SU+::9' 11 | NAD+DP+5450534000109::9+++++++GB' 12 | NAD+IV+5450534000055::9++AMAZON EU SARL:5 RUE PLAETIS LUXEMBOURG+CO PO BOX 4558+SLOUGH++SL1 0TX+GB' 13 | RFF+VA:GB727255821' 14 | CUX+2:EUR:9' 15 | LIN+1++9783898307529:EN' 16 | QTY+21:5' 17 | PRI+AAA:27.5' 18 | LIN+2++390787706322:UP' 19 | QTY+21:1' 20 | PRI+AAA:10.87' 21 | LIN+3' 22 | PIA+5+3899408268X-39:SA' 23 | QTY+21:3' 24 | PRI+AAA:3.85' 25 | UNS+S' 26 | CNT+2:3' 27 | UNT+26+1' 28 | UNZ+1+5' 29 | -------------------------------------------------------------------------------- /pyas2/tests/urls.py: -------------------------------------------------------------------------------- 1 | """pyas2_dev URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.9/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | url(r'^pyas2/', include('pyas2.urls')), 22 | ] 23 | -------------------------------------------------------------------------------- /pyas2/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.contrib.auth.decorators import login_required, user_passes_test 3 | from django.contrib.auth import views as auth_views 4 | from pyas2 import views 5 | 6 | staff_required = user_passes_test(lambda u: u.is_staff) 7 | superuser_required = user_passes_test(lambda u: u.is_superuser) 8 | 9 | urlpatterns = [ 10 | url(r'^login.*', auth_views.login, {'template_name': 'admin/login.html'}, name='login'), 11 | url(r'^logout.*', auth_views.logout, {'next_page': 'home'}, name='logout'), 12 | url(r'^password_change/$', auth_views.password_change, name='password_change'), 13 | url(r'^password_change/done/$', auth_views.password_change_done, name='password_change_done'), 14 | url(r'^home.*', login_required(views.home, login_url='login'), name='home'), 15 | url(r'^msearch/$', login_required(views.MessageSearch.as_view(), login_url='login'), name='msearch'), 16 | url(r'^message/$', login_required(views.MessageList.as_view(), login_url='login'), name='messages'), 17 | url(r'^message/(?P.+)/$', login_required(views.MessageDetail.as_view(), login_url='login'), 18 | name='message_detail'), 19 | url(r'^payload/(?P.+)/$', login_required(views.PayloadView.as_view(), login_url='login'), name='payload_view'), 20 | url(r'^mdnsearch/$', login_required(views.MDNSearch.as_view(), login_url='login'), name='mdnsearch'), 21 | url(r'^mdn/$', login_required(views.MDNList.as_view(), login_url='login'), name='mdns'), 22 | url(r'^mdn/(?P.+)/$', login_required(views.MDNView.as_view(), login_url='login'), name='mdn_view'), 23 | url(r'^sendmessage/$', login_required(views.SendMessage.as_view(), login_url='login'), name='sendmessage'), 24 | url(r'^resendmessage/(?P.+)/$', login_required(views.resend_message, login_url='login'), name='resendmessage'), 25 | url(r'^sendasyncmdn/$', login_required(views.send_async_mdn, login_url='login'), name='sendasyncmdn'), 26 | url(r'^retryfailedcomms/$', login_required(views.retry_failed_comms, login_url='login'), name='retryfailedcomms'), 27 | url(r'^cancelretries/(?P.+)/$', login_required(views.cancel_retries, login_url='login'), name='cancelretries'), 28 | url(r'^certificates/(?P.+)$', login_required(views.download_cert, login_url='login'), name='download_cert'), 29 | # only superuser 30 | url(r'^sendtestmail$', superuser_required(views.send_test_mail_managers), name='sendtestmail'), 31 | # as2 asynchronous mdn and message receive url 32 | url(r'^as2receive$', views.as2receive, name="as2-receive"), 33 | # catch-all 34 | url(r'^.*', login_required(views.home, login_url='login'), name='home'), 35 | ] 36 | 37 | handler500 = 'pyas2.views.server_error' 38 | handler400 = 'pyas2.views.client_error' 39 | -------------------------------------------------------------------------------- /pyas2/viewlib.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import urllib 3 | import xml.dom.minidom 4 | import re 5 | 6 | 7 | def datetimefrom(): 8 | terug = datetime.datetime.today() - datetime.timedelta(days=30) 9 | return terug.strftime('%Y-%m-%d 00:00:00') 10 | 11 | 12 | def datetimeuntil(): 13 | terug = datetime.datetime.today() 14 | return terug.strftime('%Y-%m-%d 23:59:59') 15 | 16 | 17 | def url_with_querystring(path, **kwargs): 18 | return path + '?' + urllib.urlencode(kwargs) 19 | 20 | 21 | def indent_x12(content): 22 | if content.count('\n') > 6: 23 | return content 24 | count = 0 25 | for char in content[:200].lstrip(): 26 | if char in '\r\n' and count != 105: # pos 105: is record_sep, could be \r\n 27 | continue 28 | count += 1 29 | if count == 106: 30 | sep = char 31 | break 32 | else: 33 | return content 34 | if sep.isalnum() or sep.isspace(): 35 | return content 36 | return content.replace(sep, sep + '\n') 37 | 38 | EDIFACT_INDENT = re.compile(''' 39 | (?1.9, <=1.10.6', 43 | 'cherrypy>6, <=8.9.1', 44 | 'requests', 45 | 'm2crypto', 46 | 'pyasn1' 47 | ], 48 | ) 49 | --------------------------------------------------------------------------------