girder 5.0.19.dev74__tar.gz → 5.0.19.dev76__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {girder-5.0.19.dev74/girder.egg-info → girder-5.0.19.dev76}/PKG-INFO +1 -1
- girder-5.0.19.dev76/girder/utility/_hash_state.py +261 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76/girder.egg-info}/PKG-INFO +1 -1
- girder-5.0.19.dev76/girder.egg-info/scm_version.json +8 -0
- girder-5.0.19.dev74/girder/utility/_hash_state.py +0 -152
- girder-5.0.19.dev74/girder.egg-info/scm_version.json +0 -8
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/Dockerfile +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/build_plugins.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/config.yml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/generatePyEnvChecksum.sh +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/publish_npm.sh +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/publish_pypi.sh +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.circleci/rabbitmq.conf +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.codecov.yml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.dockerignore +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.editorconfig +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.git-blame-ignore-revs +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.github/workflows/codespell.yml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.gitignore +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.pre-commit-config.yaml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/.readthedocs.yml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/CHANGELOG.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/CMakeLists.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/CONTRIBUTING.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/Dockerfile +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/LICENSE +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/MANIFEST.in +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/README.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/clients/python/README.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/clients/python/girder_client/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/clients/python/girder_client/_jsonemitter.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/clients/python/girder_client/cli.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/clients/python/pyproject.toml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/clients/python/setup.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docker-compose.yml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/admin-docs.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/api-docs.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/build-docs.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/conf.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/configuration.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/dependencies.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/deployment.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/dev-installation.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/developer-cookbook.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/developer-docs.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/development.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/favicon.ico +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/images/dicom-viewer.png +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/index.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/license.png +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/list_env_settings.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/list_env_settings.yaml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/migration-guide.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/mount.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/plugin-development.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/plugins.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/python-client.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/requirements-docs.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/security.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/sftp.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/static/custom.css +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/user-docs.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/docs/user-guide.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/access.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/api_docs.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/api_main.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/describe.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/docs.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/filter_logging.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/rest.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/sftp.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/api_key.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/assetstore.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/collection.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/file.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/folder.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/group.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/item.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/resource.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/system.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/token.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/api/v1/user.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/asgi.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/cli/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/cli/mount.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/cli/serve.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/cli/sftpd.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/cli/shell.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/constants.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/events.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/exceptions.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/_footer.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/_header.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/accountApproval.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/accountApproved.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/emailVerification.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/groupInvite.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/mail_templates/temporaryAccess.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/api_key.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/assetstore.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/collection.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/file.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/folder.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/group.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/item.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/model_base.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/setting.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/token.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/upload.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/models/user.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/notification.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/plugin.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/settings.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/tasks.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/_cache.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/abstract_assetstore_adapter.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/acl_mixin.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/assetstore_utilities.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/config.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/error.mako +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/filesystem_assetstore_adapter.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/mail_utils.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/model_importer.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/path.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/progress.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/s3_assetstore_adapter.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/search.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/server.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/setting_utilities.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/system.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/webroot.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/utility/ziputil.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/.env.development +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/.gitignore +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/.prettierrc.json +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/README.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/Girder_Favicon.png +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/Girder_Mark.png +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/fontello-BGLM866c.svg +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/fontello-CMxI46LA.eot +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/fontello-Ddaw8Z2O.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/fontello-KuItqCW9.ttf +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/fontello-_lT35XxX.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/glyphicons-halflings-regular-BKjkU69z.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/glyphicons-halflings-regular-BUJKDMgK.eot +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/glyphicons-halflings-regular-CSehLiBc.svg +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/glyphicons-halflings-regular-DrwTMapi.ttf +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/glyphicons-halflings-regular-DzqM6ju8.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/index-C3KtNRrl.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/index-C3KtNRrl.js.map +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/index-DFhDyJFH.css +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/jsoneditor-icons-CIlYC0TY.svg +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-300-B6tDWRxp.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-300-DZbNTRe6.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-300italic-DLsXqxhU.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-300italic-Dfz31Up5.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-400-D5zbb_EN.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-400-DLgeRt71.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-400italic-DpGQ6Ktj.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-400italic-UJbezL8h.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-600-CCvT4JHQ.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-600-DHWfDY-G.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-600italic-X8kCjSq_.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-600italic-slqXzGub.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-700-CsbQbrjx.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-700-DNl7WOH5.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-700italic-BtE7VvhE.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-700italic-hc2P_kZo.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-800-CbJOM4_m.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-800-XaYTAPrv.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-800italic-DqvYew-K.woff +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/assets/open-sans-latin-800italic-JIGkTxpX.woff2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/index.html +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/auth.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/constants.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/dialog.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/events.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/index.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/main.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/misc.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/pluginUtils.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/rest.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/router.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/routes.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/version.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/src/src/vite-env.d.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/swagger-ui/swagger-ui-bundle.js +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/dist/swagger-ui/swagger-ui.css +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/env.d.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/playwright.config.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/coverage.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/playwright-setup.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/playwright-teardown.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/server.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/admin.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/browser.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/collection.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/collectionBaseClass.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/customWidgets.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/README.md +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/fake.jpg +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/nomime.dat +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/slicer_cli_web_multiple_test.xml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/slicer_cli_web_test.xml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/ten_byte_file.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/testFile.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data/testFile2 +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/data.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/emptyLayout.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/file_upload.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/folder.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/group.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/item.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/model.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_authorized_upload.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_autojoin.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_hashsum_download.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_homepage.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_item_licenses.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_jobs.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_readme.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_config_view.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_container_view.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_item_selector.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_panel_group.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_parser.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_task.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_widget_model.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_slicer_cli_web_widget_view.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_terms.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_thumbnails.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/plugin_user_quota.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/routing.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/setApi.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/setting_show_download.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/sortWidget.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/swagger.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/user.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/utilities.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/version.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/spec/widgets.spec.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/web/tests/util.ts +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/worker_plugin.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder/wsgi.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/SOURCES.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/dependency_links.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/entry_points.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/not-zip-safe +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/requires.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/scm_file_list.json +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/girder.egg-info/top_level.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/jsdoc.json +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/package-lock.json +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/package.json +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pyproject.toml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/LICENSE +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/MANIFEST.in +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pyproject.toml +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/__init__.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/assertions.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/fixtures.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/plugin.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/plugin_registry.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/utils.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/pytest_girder/web_client.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/pytest_girder/setup.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/requirements-dev.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/midas/README.rst +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/midas/migrate.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/midas/requirements.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/midas/walk_girder.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/midas/walk_midas.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/publicNames.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/publicNames.txt +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/scripts/test_names.sh +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/setup.cfg +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/setup.py +0 -0
- {girder-5.0.19.dev74 → girder-5.0.19.dev76}/tox.ini +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Utility for saving and restoring the internal state of a hash object
|
|
2
|
+
# so that checksums can be streamed without having to remain in memory.
|
|
3
|
+
# Inspired by http://code.activestate.com/recipes/
|
|
4
|
+
# 578479-save-and-restore-sha-512-internal-state/
|
|
5
|
+
|
|
6
|
+
import binascii
|
|
7
|
+
import ctypes
|
|
8
|
+
import hashlib
|
|
9
|
+
import ssl
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
_ver = sys.version_info
|
|
13
|
+
_free_threaded = hasattr(sys, '_is_gil_enabled') and not sys._is_gil_enabled()
|
|
14
|
+
_WORD = ctypes.sizeof(ctypes.c_void_p)
|
|
15
|
+
|
|
16
|
+
# This is the offset to the EVP_MD_CTX structure in CPython's _hashopenssl.c
|
|
17
|
+
# EVPObject. It changed for Python 3.8 in
|
|
18
|
+
# https://github.com/python/cpython/pull/16023 and again for the free-threaded
|
|
19
|
+
# builds in 3.14 (which add two words to the object header) and for all builds
|
|
20
|
+
# in 3.15 (which add one word). These values are only used as a fallback on
|
|
21
|
+
# platforms where we cannot safely auto-detect the layout.
|
|
22
|
+
if _free_threaded:
|
|
23
|
+
_HASHLIB_EVP_STRUCT_OFFSET = 5 if _ver >= (3, 15) else 4
|
|
24
|
+
else:
|
|
25
|
+
_HASHLIB_EVP_STRUCT_OFFSET = 3 if _ver >= (3, 15) else 2
|
|
26
|
+
|
|
27
|
+
# Number of pointer-sized words to scan when auto-detecting the layout of
|
|
28
|
+
# CPython's _hashlib.HASH object and the OpenSSL EVP_MD_CTX structure it
|
|
29
|
+
# references. The digest state has never been stored inline in the hash
|
|
30
|
+
# object (since CPython 2.7.13), so it is always reachable via two levels of
|
|
31
|
+
# pointers: the hash object points to an EVP_MD_CTX, which points to the
|
|
32
|
+
# state data.
|
|
33
|
+
_HASHLIB_OBJECT_SCAN_WORDS = 10
|
|
34
|
+
_EVP_MD_CTX_SCAN_WORDS = 16
|
|
35
|
+
|
|
36
|
+
# Minimum plausible heap address; anything smaller is not a real pointer.
|
|
37
|
+
_MIN_VALID_ADDRESS = 0x1000
|
|
38
|
+
|
|
39
|
+
# Auto-detected offsets, in units of words: (offset of the EVP_MD_CTX pointer
|
|
40
|
+
# within the hash object, offset of the state data pointer within the
|
|
41
|
+
# EVP_MD_CTX). Set once the first hash object has been inspected and reused
|
|
42
|
+
# for all subsequent objects, since the layout is the same for every hash
|
|
43
|
+
# algorithm within a single interpreter build.
|
|
44
|
+
_STATE_OFFSETS = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _readPointer(address):
|
|
48
|
+
return ctypes.cast(address, ctypes.POINTER(ctypes.c_void_p))[0]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _getReadableAddressRanges():
|
|
52
|
+
"""
|
|
53
|
+
Get the readable memory ranges of the current process, used to validate
|
|
54
|
+
candidate pointers before dereferencing them.
|
|
55
|
+
|
|
56
|
+
:returns: A list of (start, end) address tuples, or None if the platform
|
|
57
|
+
does not provide the information (in which case hardcoded offsets are
|
|
58
|
+
used instead).
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
with open('/proc/self/maps') as mapsFile:
|
|
62
|
+
ranges = []
|
|
63
|
+
for line in mapsFile:
|
|
64
|
+
fields = line.split()
|
|
65
|
+
if 'r' not in fields[1]:
|
|
66
|
+
continue
|
|
67
|
+
start, end = fields[0].split('-')
|
|
68
|
+
ranges.append((int(start, 16), int(end, 16)))
|
|
69
|
+
return ranges
|
|
70
|
+
except (OSError, IndexError, ValueError):
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _isValidAddress(ranges, address, size):
|
|
75
|
+
"""
|
|
76
|
+
Check that an address range is safe to read without segfaulting.
|
|
77
|
+
"""
|
|
78
|
+
if not address or address < _MIN_VALID_ADDRESS:
|
|
79
|
+
return False
|
|
80
|
+
return any(start <= address and address + size <= end for start, end in ranges)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _locateStateDataAddress(hashObject, initVectorFirstWord, stateSize):
|
|
84
|
+
"""
|
|
85
|
+
Find the address of the internal hash state of a hash object.
|
|
86
|
+
|
|
87
|
+
When possible, this is done by scanning the hash object for a pointer to
|
|
88
|
+
an OpenSSL EVP_MD_CTX and scanning that for a pointer to memory that
|
|
89
|
+
begins with the algorithm's initialization vector. This avoids depending
|
|
90
|
+
on hardcoded struct offsets, which CPython has repeatedly changed (see
|
|
91
|
+
the fallback offsets below the imports). On platforms where memory
|
|
92
|
+
ranges cannot be enumerated, the hardcoded offsets are used instead.
|
|
93
|
+
|
|
94
|
+
:param hashObject: A hashlib hash object backed by OpenSSL
|
|
95
|
+
(_hashlib.HASH).
|
|
96
|
+
:param initVectorFirstWord: The first eight bytes of the digest state of a
|
|
97
|
+
freshly initialized hash object of this algorithm.
|
|
98
|
+
:param stateSize: The size in bytes of the digest state.
|
|
99
|
+
:return: The address of the digest state, or None if it could not be
|
|
100
|
+
located.
|
|
101
|
+
"""
|
|
102
|
+
global _STATE_OFFSETS
|
|
103
|
+
objectAddress = id(hashObject)
|
|
104
|
+
|
|
105
|
+
if _STATE_OFFSETS is not None:
|
|
106
|
+
objectOffset, ctxOffset = _STATE_OFFSETS
|
|
107
|
+
ctxAddress = _readPointer(objectAddress + objectOffset * _WORD)
|
|
108
|
+
return _readPointer(ctxAddress + ctxOffset * _WORD)
|
|
109
|
+
|
|
110
|
+
ranges = _getReadableAddressRanges()
|
|
111
|
+
if ranges is None:
|
|
112
|
+
# Platforms without /proc/self/maps, such as macOS and Windows.
|
|
113
|
+
ctxAddress = _readPointer(objectAddress + _HASHLIB_EVP_STRUCT_OFFSET * _WORD)
|
|
114
|
+
if ssl._OPENSSL_API_VERSION < (3, 0):
|
|
115
|
+
# OpenSSL 1.x
|
|
116
|
+
return _readPointer(ctxAddress + 3 * _WORD)
|
|
117
|
+
# OpenSSL 3.x
|
|
118
|
+
return _readPointer(ctxAddress + 7 * _WORD)
|
|
119
|
+
|
|
120
|
+
for objectOffset in range(2, _HASHLIB_OBJECT_SCAN_WORDS):
|
|
121
|
+
ctxAddress = _readPointer(objectAddress + objectOffset * _WORD)
|
|
122
|
+
if not _isValidAddress(ranges, ctxAddress, _EVP_MD_CTX_SCAN_WORDS * _WORD):
|
|
123
|
+
continue
|
|
124
|
+
for ctxOffset in range(_EVP_MD_CTX_SCAN_WORDS):
|
|
125
|
+
stateAddress = _readPointer(ctxAddress + ctxOffset * _WORD)
|
|
126
|
+
if not _isValidAddress(ranges, stateAddress, stateSize):
|
|
127
|
+
continue
|
|
128
|
+
if ctypes.cast(
|
|
129
|
+
stateAddress, ctypes.POINTER(ctypes.c_char)
|
|
130
|
+
)[:8] == initVectorFirstWord:
|
|
131
|
+
_STATE_OFFSETS = (objectOffset, ctxOffset)
|
|
132
|
+
return stateAddress
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _getStateDataPointer(hashObject, hashInfo):
|
|
137
|
+
"""
|
|
138
|
+
Get a pointer to the internal hash state of a hash object.
|
|
139
|
+
|
|
140
|
+
:param hashObject: A hashlib hash object.
|
|
141
|
+
:param hashInfo: The _HashInfo instance describing the hash algorithm.
|
|
142
|
+
:return: A ctypes pointer to the internal hash state.
|
|
143
|
+
:rtype: ctypes.POINTER(ctypes.c_char)
|
|
144
|
+
"""
|
|
145
|
+
stateAddress = _locateStateDataAddress(
|
|
146
|
+
hashObject, hashInfo.initVectorFirstWord, hashInfo.stateSize)
|
|
147
|
+
if stateAddress is None:
|
|
148
|
+
raise RuntimeError(
|
|
149
|
+
'Could not locate the internal state of the %s hash object. This module '
|
|
150
|
+
'requires a CPython build with OpenSSL-backed hashlib.' % hashInfo.name)
|
|
151
|
+
return ctypes.cast(stateAddress, ctypes.POINTER(ctypes.c_char))
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
_HASH_INFOS = {}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class _HashInfo:
|
|
158
|
+
def __init__(self, type, stateSize, initVectorFirstWord):
|
|
159
|
+
self.type = type
|
|
160
|
+
self.stateSize = stateSize
|
|
161
|
+
self.initVectorFirstWord = initVectorFirstWord
|
|
162
|
+
|
|
163
|
+
# Instantiate to get the name and do a sanity check
|
|
164
|
+
instance = self.type()
|
|
165
|
+
self.name = instance.name
|
|
166
|
+
|
|
167
|
+
stateDataPointer = _getStateDataPointer(instance, self)
|
|
168
|
+
assert stateDataPointer[:8] == initVectorFirstWord
|
|
169
|
+
|
|
170
|
+
_HASH_INFOS[self.name] = self
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
_HashInfo(
|
|
174
|
+
type=hashlib.md5,
|
|
175
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/md5/md5.h#L100
|
|
176
|
+
stateSize=92,
|
|
177
|
+
# Found empirically
|
|
178
|
+
initVectorFirstWord=b'\x01\x23\x45\x67\x89\xab\xcd\xef'
|
|
179
|
+
)
|
|
180
|
+
_HashInfo(
|
|
181
|
+
type=hashlib.sha1,
|
|
182
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha.h#L100
|
|
183
|
+
stateSize=96,
|
|
184
|
+
# Found empirically
|
|
185
|
+
initVectorFirstWord=b'\x01\x23\x45\x67\x89\xab\xcd\xef'
|
|
186
|
+
)
|
|
187
|
+
_HashInfo(
|
|
188
|
+
type=hashlib.sha224,
|
|
189
|
+
# Uses the same struct as sha256
|
|
190
|
+
stateSize=112,
|
|
191
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha256.c#L22
|
|
192
|
+
initVectorFirstWord=b'\xd8\x9e\x05\xc1\x07\xd5\x7c\x36'
|
|
193
|
+
)
|
|
194
|
+
_HashInfo(
|
|
195
|
+
type=hashlib.sha256,
|
|
196
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha.h#L135
|
|
197
|
+
stateSize=112,
|
|
198
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha256.c#L33
|
|
199
|
+
initVectorFirstWord=b'\x67\xe6\x09\x6a\x85\xae\x67\xbb'
|
|
200
|
+
)
|
|
201
|
+
_HashInfo(
|
|
202
|
+
type=hashlib.sha384,
|
|
203
|
+
# Uses the same struct as sha512
|
|
204
|
+
stateSize=216,
|
|
205
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha512.c#L64
|
|
206
|
+
initVectorFirstWord=b'\xd8\x9e\x05\xc1\x5d\x9d\xbb\xcb'
|
|
207
|
+
)
|
|
208
|
+
_HashInfo(
|
|
209
|
+
type=hashlib.sha512,
|
|
210
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha.h#L182
|
|
211
|
+
stateSize=216,
|
|
212
|
+
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha512.c#L80
|
|
213
|
+
initVectorFirstWord=b'\x08\xc9\xbc\xf3\x67\xe6\x09\x6a'
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def serialize(hashObject):
|
|
218
|
+
"""
|
|
219
|
+
Serializes the internal state of the hash object passed in. Calling
|
|
220
|
+
restore() on the serialized value afterward will return an equivalent
|
|
221
|
+
hash object to the one passed.
|
|
222
|
+
|
|
223
|
+
:param hashObject: The hash object to serialize.
|
|
224
|
+
:type hashObject: _hashlib.HASH
|
|
225
|
+
:returns: A binary string representing the serialized state.
|
|
226
|
+
"""
|
|
227
|
+
hashInfo = _HASH_INFOS[hashObject.name]
|
|
228
|
+
stateDataPointer = _getStateDataPointer(hashObject, hashInfo)
|
|
229
|
+
return stateDataPointer[:hashInfo.stateSize]
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def restore(oldStateData, hashName):
|
|
233
|
+
"""
|
|
234
|
+
Unserializes a hash object from a binary string created by the
|
|
235
|
+
serialize() method in this module.
|
|
236
|
+
|
|
237
|
+
:param oldStateData: The serialized state.
|
|
238
|
+
:type oldStateData: binary string
|
|
239
|
+
:param hashName: The name of the hash algorithm type.
|
|
240
|
+
:type hashName: str
|
|
241
|
+
:returns: A hash object in the same state as the one that serialize()
|
|
242
|
+
was called on.
|
|
243
|
+
"""
|
|
244
|
+
hashInfo = _HASH_INFOS[hashName]
|
|
245
|
+
assert len(oldStateData) == hashInfo.stateSize
|
|
246
|
+
|
|
247
|
+
hashObject = hashInfo.type()
|
|
248
|
+
stateDataPointer = _getStateDataPointer(hashObject, hashInfo)
|
|
249
|
+
|
|
250
|
+
for i, byte in enumerate(oldStateData):
|
|
251
|
+
stateDataPointer[i] = byte
|
|
252
|
+
|
|
253
|
+
return hashObject
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def serializeHex(hashObject):
|
|
257
|
+
return binascii.b2a_hex(serialize(hashObject))
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def restoreHex(oldHexStateData, hashName):
|
|
261
|
+
return restore(binascii.a2b_hex(oldHexStateData), hashName)
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# Utility for saving and restoring the internal state of a hash object
|
|
2
|
-
# so that checksums can be streamed without having to remain in memory.
|
|
3
|
-
# Inspired by http://code.activestate.com/recipes/
|
|
4
|
-
# 578479-save-and-restore-sha-512-internal-state/
|
|
5
|
-
|
|
6
|
-
import binascii
|
|
7
|
-
import ctypes
|
|
8
|
-
import hashlib
|
|
9
|
-
import ssl
|
|
10
|
-
import sys
|
|
11
|
-
|
|
12
|
-
_ver = sys.version_info
|
|
13
|
-
_free_threaded = hasattr(sys, '_is_gil_enabled') and not sys._is_gil_enabled()
|
|
14
|
-
# This is the offset to the EVP_MD_CTX structure in CPython's _hashopenssl.c
|
|
15
|
-
# EVPObject. It changed for Python 3.8 in
|
|
16
|
-
# https://github.com/python/cpython/pull/16023
|
|
17
|
-
_HASHLIB_EVP_STRUCT_OFFSET = 2 if not _free_threaded else 4
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _getHashStateDataPointer(hashObject):
|
|
21
|
-
"""
|
|
22
|
-
Get a pointer to the internal hash state of a hash object.
|
|
23
|
-
|
|
24
|
-
:param hashObject: A hashlib hash object.
|
|
25
|
-
:return: A ctypes pointer to the internal hash state.
|
|
26
|
-
:rtype: ctypes.POINTER(ctypes.c_char)
|
|
27
|
-
"""
|
|
28
|
-
hashPointer = ctypes.cast(id(hashObject), ctypes.POINTER(ctypes.c_void_p))
|
|
29
|
-
|
|
30
|
-
# In cpython 2.7.13, hashlib changed to store a pointer to the OpenSSL hash
|
|
31
|
-
# object rather than inlining it in the struct, so we require an extra dereference. See
|
|
32
|
-
# https://github.com/python/cpython/commit/9d9615f6782be4b1f38b47d4d56cee208c26a970
|
|
33
|
-
evpStruct = ctypes.cast(hashPointer[_HASHLIB_EVP_STRUCT_OFFSET],
|
|
34
|
-
ctypes.POINTER(ctypes.c_void_p))
|
|
35
|
-
if ssl._OPENSSL_API_VERSION < (3, 0):
|
|
36
|
-
# OpenSSL 1.x
|
|
37
|
-
stateDataPointer = ctypes.cast(evpStruct[3], ctypes.POINTER(ctypes.c_char))
|
|
38
|
-
else:
|
|
39
|
-
# OpenSSL 3.x
|
|
40
|
-
stateDataPointer = ctypes.cast(evpStruct[7], ctypes.POINTER(ctypes.c_char))
|
|
41
|
-
|
|
42
|
-
assert stateDataPointer
|
|
43
|
-
return stateDataPointer
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
_HASH_INFOS = {}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class _HashInfo:
|
|
50
|
-
def __init__(self, type, stateSize, initVectorFirstWord):
|
|
51
|
-
self.type = type
|
|
52
|
-
self.stateSize = stateSize
|
|
53
|
-
|
|
54
|
-
# Instantiate to get the name and do a sanity check
|
|
55
|
-
instance = self.type()
|
|
56
|
-
self.name = instance.name
|
|
57
|
-
|
|
58
|
-
stateDataPointer = _getHashStateDataPointer(instance)
|
|
59
|
-
assert stateDataPointer[:8] == initVectorFirstWord
|
|
60
|
-
|
|
61
|
-
_HASH_INFOS[self.name] = self
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
_HashInfo(
|
|
65
|
-
type=hashlib.md5,
|
|
66
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/md5/md5.h#L100
|
|
67
|
-
stateSize=92,
|
|
68
|
-
# Found empirically
|
|
69
|
-
initVectorFirstWord=b'\x01\x23\x45\x67\x89\xab\xcd\xef'
|
|
70
|
-
)
|
|
71
|
-
_HashInfo(
|
|
72
|
-
type=hashlib.sha1,
|
|
73
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha.h#L100
|
|
74
|
-
stateSize=96,
|
|
75
|
-
# Found empirically
|
|
76
|
-
initVectorFirstWord=b'\x01\x23\x45\x67\x89\xab\xcd\xef'
|
|
77
|
-
)
|
|
78
|
-
_HashInfo(
|
|
79
|
-
type=hashlib.sha224,
|
|
80
|
-
# Uses the same struct as sha256
|
|
81
|
-
stateSize=112,
|
|
82
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha256.c#L22
|
|
83
|
-
initVectorFirstWord=b'\xd8\x9e\x05\xc1\x07\xd5\x7c\x36'
|
|
84
|
-
)
|
|
85
|
-
_HashInfo(
|
|
86
|
-
type=hashlib.sha256,
|
|
87
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha.h#L135
|
|
88
|
-
stateSize=112,
|
|
89
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha256.c#L33
|
|
90
|
-
initVectorFirstWord=b'\x67\xe6\x09\x6a\x85\xae\x67\xbb'
|
|
91
|
-
)
|
|
92
|
-
_HashInfo(
|
|
93
|
-
type=hashlib.sha384,
|
|
94
|
-
# Uses the same struct as sha512
|
|
95
|
-
stateSize=216,
|
|
96
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha512.c#L64
|
|
97
|
-
initVectorFirstWord=b'\xd8\x9e\x05\xc1\x5d\x9d\xbb\xcb'
|
|
98
|
-
)
|
|
99
|
-
_HashInfo(
|
|
100
|
-
type=hashlib.sha512,
|
|
101
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha.h#L182
|
|
102
|
-
stateSize=216,
|
|
103
|
-
# github.com/openssl/openssl/blob/OpenSSL_1_0_1f/crypto/sha/sha512.c#L80
|
|
104
|
-
initVectorFirstWord=b'\x08\xc9\xbc\xf3\x67\xe6\x09\x6a'
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def serialize(hashObject):
|
|
109
|
-
"""
|
|
110
|
-
Serializes the internal state of the hash object passed in. Calling
|
|
111
|
-
restore() on the serialized value afterward will return an equivalent
|
|
112
|
-
hash object to the one passed.
|
|
113
|
-
|
|
114
|
-
:param hashObject: The hash object to serialize.
|
|
115
|
-
:type hashObject: _hashlib.HASH
|
|
116
|
-
:returns: A binary string representing the serialized state.
|
|
117
|
-
"""
|
|
118
|
-
stateDataPointer = _getHashStateDataPointer(hashObject)
|
|
119
|
-
hashInfo = _HASH_INFOS[hashObject.name]
|
|
120
|
-
return stateDataPointer[:hashInfo.stateSize]
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def restore(oldStateData, hashName):
|
|
124
|
-
"""
|
|
125
|
-
Unserializes a hash object from a binary string created by the
|
|
126
|
-
serialize() method in this module.
|
|
127
|
-
|
|
128
|
-
:param oldStateData: The serialized state.
|
|
129
|
-
:type oldStateData: binary string
|
|
130
|
-
:param hashName: The name of the hash algorithm type.
|
|
131
|
-
:type hashName: str
|
|
132
|
-
:returns: A hash object in the same state as the one that serialize()
|
|
133
|
-
was called on.
|
|
134
|
-
"""
|
|
135
|
-
hashInfo = _HASH_INFOS[hashName]
|
|
136
|
-
assert len(oldStateData) == hashInfo.stateSize
|
|
137
|
-
|
|
138
|
-
hashObject = hashInfo.type()
|
|
139
|
-
stateDataPointer = _getHashStateDataPointer(hashObject)
|
|
140
|
-
|
|
141
|
-
for i, byte in enumerate(oldStateData):
|
|
142
|
-
stateDataPointer[i] = byte
|
|
143
|
-
|
|
144
|
-
return hashObject
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def serializeHex(hashObject):
|
|
148
|
-
return binascii.b2a_hex(serialize(hashObject))
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def restoreHex(oldHexStateData, hashName):
|
|
152
|
-
return restore(binascii.a2b_hex(oldHexStateData), hashName)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|