From e2bb10ad6253b739ed579b0d39355a3b59e073c4 Mon Sep 17 00:00:00 2001 From: nikili0n Date: Fri, 13 Oct 2023 03:17:21 +0300 Subject: [PATCH] Added tg_parser --- poetry.lock | 330 +- pyproject.toml | 13 +- src/core/master_service.py | 1 + .../telegram_media_downloader/.gitignore | 71 + .../CODE_OF_CONDUCT.md | 76 + .../telegram_media_downloader/CONTRIBUTING.md | 199 + .../telegram_media_downloader/Dockerfile | 25 + .../telegram_media_downloader/LICENSE | 21 + .../telegram_media_downloader/Makefile | 26 + .../telegram_media_downloader/README.md | 286 + .../telegram_media_downloader/README_CN.md | 286 + .../telegram_media_downloader/codecov.yml | 13 + .../dev-requirements.txt | 9 + .../docker-compose.yaml | 29 + .../gen_filter_cache.py | 3 + .../media_downloader.py | 628 ++ .../media_downloader.spec | 50 + .../module/__init__.py | 0 .../telegram_media_downloader/module/app.py | 730 ++ .../telegram_media_downloader/module/bot.py | 929 +++ .../module/cloud_drive.py | 229 + .../module/download_stat.py | 112 + .../module/filter.py | 372 + .../module/get_chat_history_v2.py | 86 + .../module/language.py | 271 + .../module/pyrogram_extension.py | 597 ++ .../aes/crypto-js-master/CONTRIBUTING.md | 28 + .../static/aes/crypto-js-master/LICENSE | 24 + .../static/aes/crypto-js-master/README.md | 259 + .../module/static/aes/crypto-js-master/aes.js | 234 + .../static/aes/crypto-js-master/bower.json | 39 + .../aes/crypto-js-master/cipher-core.js | 890 +++ .../static/aes/crypto-js-master/core.js | 807 +++ .../static/aes/crypto-js-master/crypto-js.js | 6191 +++++++++++++++++ .../docs/QuickStartGuide.wiki | 470 ++ .../static/aes/crypto-js-master/enc-base64.js | 136 + .../aes/crypto-js-master/enc-base64url.js | 140 + .../static/aes/crypto-js-master/enc-hex.js | 18 + .../static/aes/crypto-js-master/enc-latin1.js | 18 + .../static/aes/crypto-js-master/enc-utf16.js | 149 + .../static/aes/crypto-js-master/enc-utf8.js | 18 + .../static/aes/crypto-js-master/evpkdf.js | 134 + .../static/aes/crypto-js-master/format-hex.js | 66 + .../aes/crypto-js-master/format-openssl.js | 18 + .../static/aes/crypto-js-master/hmac-md5.js | 18 + .../aes/crypto-js-master/hmac-ripemd160.js | 18 + .../static/aes/crypto-js-master/hmac-sha1.js | 18 + .../aes/crypto-js-master/hmac-sha224.js | 18 + .../aes/crypto-js-master/hmac-sha256.js | 18 + .../static/aes/crypto-js-master/hmac-sha3.js | 18 + .../aes/crypto-js-master/hmac-sha384.js | 18 + .../aes/crypto-js-master/hmac-sha512.js | 18 + .../static/aes/crypto-js-master/hmac.js | 143 + .../static/aes/crypto-js-master/index.js | 18 + .../aes/crypto-js-master/lib-typedarrays.js | 76 + .../module/static/aes/crypto-js-master/md5.js | 268 + .../static/aes/crypto-js-master/mode-cfb.js | 80 + .../aes/crypto-js-master/mode-ctr-gladman.js | 116 + .../static/aes/crypto-js-master/mode-ctr.js | 58 + .../static/aes/crypto-js-master/mode-ecb.js | 40 + .../static/aes/crypto-js-master/mode-ofb.js | 54 + .../static/aes/crypto-js-master/package.json | 42 + .../aes/crypto-js-master/pad-ansix923.js | 49 + .../aes/crypto-js-master/pad-iso10126.js | 44 + .../aes/crypto-js-master/pad-iso97971.js | 40 + .../aes/crypto-js-master/pad-nopadding.js | 30 + .../static/aes/crypto-js-master/pad-pkcs7.js | 18 + .../aes/crypto-js-master/pad-zeropadding.js | 47 + .../static/aes/crypto-js-master/pbkdf2.js | 145 + .../aes/crypto-js-master/rabbit-legacy.js | 190 + .../static/aes/crypto-js-master/rabbit.js | 192 + .../module/static/aes/crypto-js-master/rc4.js | 139 + .../static/aes/crypto-js-master/ripemd160.js | 267 + .../static/aes/crypto-js-master/sha1.js | 150 + .../static/aes/crypto-js-master/sha224.js | 80 + .../static/aes/crypto-js-master/sha256.js | 199 + .../static/aes/crypto-js-master/sha3.js | 326 + .../static/aes/crypto-js-master/sha384.js | 83 + .../static/aes/crypto-js-master/sha512.js | 326 + .../static/aes/crypto-js-master/tripledes.js | 779 +++ .../static/aes/crypto-js-master/x64-core.js | 304 + .../module/static/css/index.css | 16 + .../module/static/layui/css/layui.css | 1 + .../module/static/layui/css/modules/code.css | 1 + .../css/modules/laydate/default/laydate.css | 1 + .../css/modules/layer/default/icon-ext.png | Bin 0 -> 5911 bytes .../layui/css/modules/layer/default/icon.png | Bin 0 -> 11493 bytes .../layui/css/modules/layer/default/layer.css | 1 + .../css/modules/layer/default/loading-0.gif | Bin 0 -> 5793 bytes .../css/modules/layer/default/loading-1.gif | Bin 0 -> 701 bytes .../css/modules/layer/default/loading-2.gif | Bin 0 -> 1787 bytes .../module/static/layui/font/iconfont.eot | Bin 0 -> 46684 bytes .../module/static/layui/font/iconfont.svg | 554 ++ .../module/static/layui/font/iconfont.ttf | Bin 0 -> 46508 bytes .../module/static/layui/font/iconfont.woff | Bin 0 -> 30628 bytes .../module/static/layui/font/iconfont.woff2 | Bin 0 -> 25964 bytes .../module/static/layui/layui.js | 1 + .../module/static/login/css/index.css | 97 + .../module/static/login/images/login.svg | 1 + .../module/static/request/index.js | 20 + .../module/templates/index.html | 313 + .../module/templates/login.html | 68 + .../telegram_media_downloader/module/web.py | 222 + .../telegram_media_downloader/mypy.ini | 8 + .../telegram_media_downloader/pylintrc | 509 ++ .../requirements.txt | 14 + .../screenshot/alipay.JPG | Bin 0 -> 226914 bytes .../screenshot/bot.gif | Bin 0 -> 73374 bytes .../screenshot/web_ui.gif | Bin 0 -> 129135 bytes .../screenshot/wechat.JPG | Bin 0 -> 114488 bytes .../telegram_media_downloader/setup.py | 42 + .../telegram_parser.py | 25 + .../tests/__init__.py | 0 .../tests/module/__init__.py | 0 .../tests/module/test_app.py | 63 + .../tests/test_common.py | 202 + .../tests/test_media_downloader.py | 1083 +++ .../tests/utils/__init__.py | 0 .../tests/utils/test_cypto.py | 55 + .../tests/utils/test_file_management.py | 40 + .../tests/utils/test_filter.py | 450 ++ .../tests/utils/test_format.py | 233 + .../tests/utils/test_log.py | 30 + .../tests/utils/test_meta.py | 23 + .../tests/utils/test_updates.py | 66 + .../utils/__init__.py | 5 + .../telegram_media_downloader/utils/crypto.py | 77 + .../utils/file_management.py | 78 + .../telegram_media_downloader/utils/format.py | 253 + .../telegram_media_downloader/utils/log.py | 16 + .../telegram_media_downloader/utils/meta.py | 23 + .../utils/meta_data.py | 98 + .../utils/platform.py | 35 + .../utils/updates.py | 41 + src/parsers/parser_mapping.py | 2 + 135 files changed, 24239 insertions(+), 6 deletions(-) create mode 100644 src/parsers/Telegram/telegram_media_downloader/.gitignore create mode 100644 src/parsers/Telegram/telegram_media_downloader/CODE_OF_CONDUCT.md create mode 100644 src/parsers/Telegram/telegram_media_downloader/CONTRIBUTING.md create mode 100644 src/parsers/Telegram/telegram_media_downloader/Dockerfile create mode 100644 src/parsers/Telegram/telegram_media_downloader/LICENSE create mode 100644 src/parsers/Telegram/telegram_media_downloader/Makefile create mode 100644 src/parsers/Telegram/telegram_media_downloader/README.md create mode 100644 src/parsers/Telegram/telegram_media_downloader/README_CN.md create mode 100644 src/parsers/Telegram/telegram_media_downloader/codecov.yml create mode 100644 src/parsers/Telegram/telegram_media_downloader/dev-requirements.txt create mode 100644 src/parsers/Telegram/telegram_media_downloader/docker-compose.yaml create mode 100644 src/parsers/Telegram/telegram_media_downloader/gen_filter_cache.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/media_downloader.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/media_downloader.spec create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/__init__.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/app.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/bot.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/cloud_drive.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/download_stat.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/filter.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/get_chat_history_v2.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/language.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/pyrogram_extension.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/CONTRIBUTING.md create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/LICENSE create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/README.md create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/aes.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/bower.json create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/cipher-core.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/core.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/crypto-js.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/docs/QuickStartGuide.wiki create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64url.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-hex.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-latin1.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf16.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf8.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/evpkdf.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-hex.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-openssl.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-md5.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-ripemd160.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha1.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha224.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha256.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha3.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha384.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha512.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/index.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/lib-typedarrays.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/md5.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-cfb.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr-gladman.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ecb.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ofb.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/package.json create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-ansix923.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso10126.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso97971.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-nopadding.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-pkcs7.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-zeropadding.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pbkdf2.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit-legacy.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rc4.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/ripemd160.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha1.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha224.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha256.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha3.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha384.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha512.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/tripledes.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/x64-core.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/css/index.css create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/layui.css create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/code.css create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/laydate/default/laydate.css create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/icon-ext.png create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/icon.png create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/layer.css create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/loading-0.gif create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/loading-1.gif create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/loading-2.gif create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.eot create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.svg create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.ttf create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.woff create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.woff2 create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/layui/layui.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/login/css/index.css create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/login/images/login.svg create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/static/request/index.js create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/templates/index.html create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/templates/login.html create mode 100644 src/parsers/Telegram/telegram_media_downloader/module/web.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/mypy.ini create mode 100644 src/parsers/Telegram/telegram_media_downloader/pylintrc create mode 100644 src/parsers/Telegram/telegram_media_downloader/requirements.txt create mode 100644 src/parsers/Telegram/telegram_media_downloader/screenshot/alipay.JPG create mode 100644 src/parsers/Telegram/telegram_media_downloader/screenshot/bot.gif create mode 100644 src/parsers/Telegram/telegram_media_downloader/screenshot/web_ui.gif create mode 100644 src/parsers/Telegram/telegram_media_downloader/screenshot/wechat.JPG create mode 100644 src/parsers/Telegram/telegram_media_downloader/setup.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/telegram_parser.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/__init__.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/module/__init__.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/module/test_app.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/test_common.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/test_media_downloader.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/__init__.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_cypto.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_file_management.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_filter.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_format.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_log.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_meta.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/tests/utils/test_updates.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/__init__.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/crypto.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/file_management.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/format.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/log.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/meta.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/meta_data.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/platform.py create mode 100644 src/parsers/Telegram/telegram_media_downloader/utils/updates.py diff --git a/poetry.lock b/poetry.lock index 426ec76..bc6e8d3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -637,6 +637,20 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "commonmark" +version = "0.9.1" +description = "Python parser for the CommonMark Markdown spec" +optional = false +python-versions = "*" +files = [ + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, +] + +[package.extras] +test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] + [[package]] name = "fastapi" version = "0.101.0" @@ -656,6 +670,42 @@ typing-extensions = ">=4.5.0" [package.extras] all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "flask" +version = "2.2.2" +description = "A simple framework for building complex web applications." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"}, + {file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"}, +] + +[package.dependencies] +click = ">=8.0" +itsdangerous = ">=2.0" +Jinja2 = ">=3.0" +Werkzeug = ">=2.2.2" + +[package.extras] +async = ["asgiref (>=3.2)"] +dotenv = ["python-dotenv"] + +[[package]] +name = "flask-login" +version = "0.6.2" +description = "User authentication and session management for Flask." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Flask-Login-0.6.2.tar.gz", hash = "sha256:c0a7baa9fdc448cdd3dd6f0939df72eec5177b2f7abe6cb82fc934d29caac9c3"}, + {file = "Flask_Login-0.6.2-py3-none-any.whl", hash = "sha256:1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f"}, +] + +[package.dependencies] +Flask = ">=1.0.4" +Werkzeug = ">=1.0.1" + [[package]] name = "frozenlist" version = "1.4.0" @@ -832,6 +882,17 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "itsdangerous" +version = "2.1.2" +description = "Safely pass data to untrusted environments and back." +optional = false +python-versions = ">=3.7" +files = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] + [[package]] name = "jinja2" version = "3.1.2" @@ -862,13 +923,13 @@ files = [ [[package]] name = "loguru" -version = "0.7.2" +version = "0.6.0" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" files = [ - {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, - {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, + {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, + {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, ] [package.dependencies] @@ -876,7 +937,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] +dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] [[package]] name = "lxml" @@ -1244,6 +1305,27 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + +[[package]] +name = "pyaes" +version = "1.6.1" +description = "Pure-Python Implementation of the AES block-cipher and common modes of operation" +optional = false +python-versions = "*" +files = [ + {file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"}, +] + [[package]] name = "pycparser" version = "2.21" @@ -1255,6 +1337,47 @@ files = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] +[[package]] +name = "pycryptodome" +version = "3.18.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:d1497a8cd4728db0e0da3c304856cb37c0c4e3d0b36fcbabcc1600f18504fc54"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:928078c530da78ff08e10eb6cada6e0dff386bf3d9fa9871b4bbc9fbc1efe024"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:157c9b5ba5e21b375f052ca78152dd309a09ed04703fd3721dce3ff8ecced148"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:d20082bdac9218649f6abe0b885927be25a917e29ae0502eaf2b53f1233ce0c2"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e8ad74044e5f5d2456c11ed4cfd3e34b8d4898c0cb201c4038fe41458a82ea27"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:62a1e8847fabb5213ccde38915563140a5b338f0d0a0d363f996b51e4a6165cf"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:16bfd98dbe472c263ed2821284118d899c76968db1a6665ade0c46805e6b29a4"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7a3d22c8ee63de22336679e021c7f2386f7fc465477d59675caa0e5706387944"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:78d863476e6bad2a592645072cc489bb90320972115d8995bcfbee2f8b209918"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b6a610f8bfe67eab980d6236fdc73bfcdae23c9ed5548192bb2d530e8a92780e"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:422c89fd8df8a3bee09fb8d52aaa1e996120eafa565437392b781abec2a56e14"}, + {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:9ad6f09f670c466aac94a40798e0e8d1ef2aa04589c29faa5b9b97566611d1d1"}, + {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:53aee6be8b9b6da25ccd9028caf17dcdce3604f2c7862f5167777b707fbfb6cb"}, + {file = "pycryptodome-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:10da29526a2a927c7d64b8f34592f461d92ae55fc97981aab5bbcde8cb465bb6"}, + {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f21efb8438971aa16924790e1c3dba3a33164eb4000106a55baaed522c261acf"}, + {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4944defabe2ace4803f99543445c27dd1edbe86d7d4edb87b256476a91e9ffa4"}, + {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:51eae079ddb9c5f10376b4131be9589a6554f6fd84f7f655180937f611cd99a2"}, + {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:83c75952dcf4a4cebaa850fa257d7a860644c70a7cd54262c237c9f2be26f76e"}, + {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:957b221d062d5752716923d14e0926f47670e95fead9d240fa4d4862214b9b2f"}, + {file = "pycryptodome-3.18.0-cp35-abi3-win32.whl", hash = "sha256:795bd1e4258a2c689c0b1f13ce9684fa0dd4c0e08680dcf597cf9516ed6bc0f3"}, + {file = "pycryptodome-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:b1d9701d10303eec8d0bd33fa54d44e67b8be74ab449052a8372f12a66f93fb9"}, + {file = "pycryptodome-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:cb1be4d5af7f355e7d41d36d8eec156ef1382a88638e8032215c215b82a4b8ec"}, + {file = "pycryptodome-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:fc0a73f4db1e31d4a6d71b672a48f3af458f548059aa05e83022d5f61aac9c08"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f022a4fd2a5263a5c483a2bb165f9cb27f2be06f2f477113783efe3fe2ad887b"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:363dd6f21f848301c2dcdeb3c8ae5f0dee2286a5e952a0f04954b82076f23825"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12600268763e6fec3cefe4c2dcdf79bde08d0b6dc1813887e789e495cb9f3403"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4604816adebd4faf8810782f137f8426bf45fee97d8427fa8e1e49ea78a52e2c"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:01489bbdf709d993f3058e2996f8f40fee3f0ea4d995002e5968965fa2fe89fb"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3811e31e1ac3069988f7a1c9ee7331b942e605dfc0f27330a9ea5997e965efb2"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4b967bb11baea9128ec88c3d02f55a3e338361f5e4934f5240afcb667fdaec"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9c8eda4f260072f7dbe42f473906c659dcbadd5ae6159dfb49af4da1293ae380"}, + {file = "pycryptodome-3.18.0.tar.gz", hash = "sha256:c9adee653fc882d98956e33ca2c1fb582e23a8af7ac82fee75bd6113c55a0413"}, +] + [[package]] name = "pycryptodomex" version = "3.18.0" @@ -1447,6 +1570,50 @@ files = [ [package.dependencies] typing-extensions = "*" +[[package]] +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "Pyrogram" +version = "2.0.106" +description = "Elegant, modern and asynchronous Telegram MTProto API framework in Python for users and bots" +optional = false +python-versions = "~=3.7" +files = [ + {file = "master.zip", hash = "sha256:722a4be0edc5002dcd05b462f333c860a790b67a1f62466b322377acd3985f77"}, +] + +[package.dependencies] +pyaes = "1.6.1" +pysocks = "1.7.1" + +[package.source] +type = "url" +url = "https://github.com/Dineshkarthik/pyrogram/archive/refs/heads/master.zip" + +[[package]] +name = "pysocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, + {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, + {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, +] + [[package]] name = "pytest" version = "7.4.0" @@ -1544,6 +1711,28 @@ text-unidecode = ">=1.3" [package.extras] unidecode = ["Unidecode (>=1.1.1)"] +[[package]] +name = "pyyaml" +version = "5.3.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = "*" +files = [ + {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, + {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, + {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, + {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, + {file = "PyYAML-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a"}, + {file = "PyYAML-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e"}, + {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, +] + [[package]] name = "redis" version = "5.0.0" @@ -1583,6 +1772,39 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "rich" +version = "12.5.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.6.3,<4.0.0" +files = [ + {file = "rich-12.5.1-py3-none-any.whl", hash = "sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb"}, + {file = "rich-12.5.1.tar.gz", hash = "sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca"}, +] + +[package.dependencies] +commonmark = ">=0.9.0,<0.10.0" +pygments = ">=2.6.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] + +[[package]] +name = "ruamel-yaml" +version = "0.17.21" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = false +python-versions = ">=3" +files = [ + {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"}, + {file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"}, +] + +[package.extras] +docs = ["ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + [[package]] name = "s3transfer" version = "0.6.2" @@ -1684,6 +1906,22 @@ files = [ [package.extras] test = ["pytest"] +[[package]] +name = "setuptools" +version = "68.2.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" @@ -1745,6 +1983,71 @@ files = [ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, ] +[[package]] +name = "tgcrypto" +version = "1.2.5" +description = "Fast and Portable Cryptography Extension Library for Pyrogram" +optional = false +python-versions = "~=3.7" +files = [ + {file = "TgCrypto-1.2.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4507102377002966f35f2481830b7529e00c9bbff8c7d1e09634f984af801675"}, + {file = "TgCrypto-1.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:38fe25c0d79b41d7a89caba2a78dea0358e17ca73b033cefd16abed680685829"}, + {file = "TgCrypto-1.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c035bf8ef89846f67e77e82ea85c089b6ea30631b32e8ac1a6511b9be52ab065"}, + {file = "TgCrypto-1.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f594e2680daf20dbac6bf56862f567ddc3cc8d6a19757ed07faa8320ff7acee4"}, + {file = "TgCrypto-1.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8723a16076e229ffdf537fdb5e638227d10f44ca43e6939db1eab524de6eaed7"}, + {file = "TgCrypto-1.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c1c8d974b8b2d7132364b6f0f6712b92bfe47ab9c5dcee25c70327ff68d22d95"}, + {file = "TgCrypto-1.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:89d9c143a1fcdb2562a4aa887152abbe9253e1979d7bebef2b489148e0bbe086"}, + {file = "TgCrypto-1.2.5-cp310-cp310-win32.whl", hash = "sha256:aa4bc1d11d4a90811c162abd45a5981f171679d1b5bd0322cd7ccd16447366a2"}, + {file = "TgCrypto-1.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:39145103614c5e38fe938549742d355920f4a0778fa8259eb69c0c85ba4b1d28"}, + {file = "TgCrypto-1.2.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:59597cdb1c87eb1184088563d20b42a8f2e431e9334fed64926079044ad2a4af"}, + {file = "TgCrypto-1.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1283337ae75b02406dd700377b8b783e70033b548492517df6e6c4156b0ed69c"}, + {file = "TgCrypto-1.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1735437df0023a40e5fdd95e6b09ce806ec8f2cd2f8879023818840dfae60cab"}, + {file = "TgCrypto-1.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfa17a20206532c6d2442c9d7a7f6434120bd75896ad9a3e9b9277477afa084f"}, + {file = "TgCrypto-1.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48da3674474839e5619e7430ff1f98aed9f55369f3cfaef7f65511852869572e"}, + {file = "TgCrypto-1.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b49e982e5b156be821a5235bd9102c00dc506a58607e2c8bd50ac872724a951f"}, + {file = "TgCrypto-1.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9d9f13586065a6d86d05c16409054033a84be208acee29b49f6f194e27b08642"}, + {file = "TgCrypto-1.2.5-cp311-cp311-win32.whl", hash = "sha256:10dd3870aecb1a783c6eafd3b164b2149dbc93a9ee13feb7e6f5c58f87c24cd0"}, + {file = "TgCrypto-1.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:a1beec47d6af8b509af7cf266e30f7703208076076594714005b42d2c25225b3"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c133ddc95ae9c6cd6ad742c4b8c30191214db8dc724268bee59a339e22b2028b"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6537f6af3d80be67bd2625a0990ee88c6ae58d33bdb88d99591bd6e97ee7a0"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdebbd9cffd10c42a2f60886dcab0272ddd38330d0cf7ccf026230b826573f59"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:45683659ec6475ee8ff60e12167ec19aacfd7527decafe446434fa1a7e6760a7"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:eafad246fd9aa63ff709a6e8c905c24fd7520ef96e33a2c3e1ccdb4fb2b2f331"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-win32.whl", hash = "sha256:1445217d22101946d38ee7d628cdb3de92db4eb130183a22030c07d7888f21b0"}, + {file = "TgCrypto-1.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:b7e8402fe4023dc9666c0bc1b30fcf0d98a294e48d35f311a3eadfe105af04d4"}, + {file = "TgCrypto-1.2.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:56e1ec34e75fa2e3dcf7f74f1017d8e16c1eb8a8e031eaaa06c57f836e0d3bcc"}, + {file = "TgCrypto-1.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca8814d6cc412775a43a021fce2d23e83a5336e9e9f38d0998d821cdf55c1d50"}, + {file = "TgCrypto-1.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bb82e53f20ce5653573832f3c05fa525cc1769bdd685408b19f26d82d5e9001b"}, + {file = "TgCrypto-1.2.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0133936eac63cc9529b497d759b7d0ca21e491bb42481b40b603ee63bb8c10b7"}, + {file = "TgCrypto-1.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76fe0a3ad838dcf300ac88233cbffc2ad63478eb0ae9fa671694e184d88ec1cd"}, + {file = "TgCrypto-1.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7070c6e063befb6d04eab46e8b1ffbee47a497971be11496d23837fc007e7685"}, + {file = "TgCrypto-1.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed53d0c4a5e6f75d4b1cab17535afe210cd3120fb88f44a8c4562d43c2a3bb16"}, + {file = "TgCrypto-1.2.5-cp38-cp38-win32.whl", hash = "sha256:f7ec9f0a571fcc38fbee224943ed9918123f752ac19bae5c195d8322f5b20fab"}, + {file = "TgCrypto-1.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:362ab28fc75e6b066e5bb15fb5296f75f4238d6c1cbcaaa1e5756cd5c168b74b"}, + {file = "TgCrypto-1.2.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7885a75db09ce8bdba42d2c332085bfe314f232541a729808c7507ffa261ff9a"}, + {file = "TgCrypto-1.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0d28aa317364a5c27317fe97a48267aa1c65c9aaf589909e97489ebe82a714e3"}, + {file = "TgCrypto-1.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:940974e19044dc65bcf7b9c5255173b896dff010142f3833047dc55d59cde21c"}, + {file = "TgCrypto-1.2.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:457c657dd10ffb4bbbb007132a0f6a7bee5080176a98c51f285fedf636b624cb"}, + {file = "TgCrypto-1.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:539bdc6b9239fb6a6b134591a998dc7f50d4dcc4fed861f80540682acc0c3802"}, + {file = "TgCrypto-1.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d70d5517d64ca952896b726d22c8a66594e6f6259ee2cb4fa134c02d0e8c3e0"}, + {file = "TgCrypto-1.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:90b6337d3ae4348ed14f89dd2ebf7011fa63d67a48c8a98d955a1e392176c60a"}, + {file = "TgCrypto-1.2.5-cp39-cp39-win32.whl", hash = "sha256:37c4b9be82716fbc6d2b123caef448eee28683888803db075d842327766f7624"}, + {file = "TgCrypto-1.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:6e96b3a478fae977228c5750194c20a18cde402bbbea6593de424f84d4a8893b"}, + {file = "TgCrypto-1.2.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4d93686e6254eb0a32a0a60e849b41a867a2770b27b48f978fd391dce2b83aeb"}, + {file = "TgCrypto-1.2.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b7fe81fad7c64479c83f31fc10e79fb20a114bca414e5e17f5e0c8b363153f8"}, + {file = "TgCrypto-1.2.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ace308f5842a0d6c04fc1ae92cb4320b4b13bfc711031c1c18d9124697685ba0"}, + {file = "TgCrypto-1.2.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:36a570ecd12a428222b10ea8b5a8e0d83ea8750e4de1d5ea53d068b84341b450"}, + {file = "TgCrypto-1.2.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba9e067fd9751b3bbd7c979210431000e44f70001d921237e9c4672bf30f07bc"}, + {file = "TgCrypto-1.2.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80e2414f1a95087d7e46fb54cb387df66424c4ec156fb1a8d8e1d4aa38eb65cf"}, + {file = "TgCrypto-1.2.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66c5b5bf701b5efc3e4c5d83439d767a3dd48f17a1d840eda6b4d1918844a8f9"}, + {file = "TgCrypto-1.2.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5d27d6c414eb4775022b05fdd571090bfd92854115e86184ac1832060fbaa510"}, + {file = "TgCrypto-1.2.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9b0a088ff2e05b6bbe891da936f62b99bd85202b2b9f4f57f71a408490dd518c"}, + {file = "TgCrypto-1.2.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f245895c7d518342089d15b5dca3cee9ffa5a0f3534db9d5a930f6a27dff4adf"}, + {file = "TgCrypto-1.2.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7dbf607d645c39a577a0f8571039d11ddd2dcdf9656465be75f9e0f540472444"}, + {file = "TgCrypto-1.2.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6b0c2dc84e632ce7b3d0b767cfe20967e557ad7d71ea5dbd7df2dd544323181"}, + {file = "TgCrypto-1.2.5.tar.gz", hash = "sha256:9bc2cac6fb9a12ef5b08f3dd500174fe374d89b660cce981f57e3138559cb682"}, +] + [[package]] name = "typing-extensions" version = "4.7.1" @@ -1869,6 +2172,23 @@ files = [ {file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"}, ] +[[package]] +name = "werkzeug" +version = "2.2.2" +description = "The comprehensive WSGI web application library." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, + {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog"] + [[package]] name = "win32-setctime" version = "1.1.0" @@ -2007,4 +2327,4 @@ websockets = "*" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "1b704294868cb5a6ebb4ce3b9ffb373899bec9ce312ad94810bc1fe0d21ffb7d" +content-hash = "272fe31fba150b0b0fcca1b7d60f706dc2a05ea730ef19e34ccb8e5524f47d66" diff --git a/pyproject.toml b/pyproject.toml index 4bc532f..a9365e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,18 @@ lxml = "^4.9.3" minio = "^7.1.16" aiogram = "3.0" pydantic = "^2.3.0" -loguru = "^0.7.2" +loguru = "0.6.0" +setuptools = "^68.2.2" +pyrogram = {url = "https://github.com/Dineshkarthik/pyrogram/archive/refs/heads/master.zip"} +pyyaml = "5.3.1" +rich = "12.5.1" +tgcrypto = "1.2.5" +werkzeug = "2.2.2" +flask = "2.2.2" +ply = "3.11" +ruamel-yaml = "0.17.21" +flask-login = "0.6.2" +pycryptodome = "3.18.0" [build-system] diff --git a/src/core/master_service.py b/src/core/master_service.py index 162785b..64b1ef3 100644 --- a/src/core/master_service.py +++ b/src/core/master_service.py @@ -21,6 +21,7 @@ from src.parsers.parser_mapping import get_parser class MasterService: def __init__(self): self.loop = asyncio.get_event_loop() + # self.tg_client = self.MAX_EXECUTOR_WORKERS = 8 self.executor = pool.ProcessPoolExecutor(max_workers=self.MAX_EXECUTOR_WORKERS, initializer=executor_initializer) diff --git a/src/parsers/Telegram/telegram_media_downloader/.gitignore b/src/parsers/Telegram/telegram_media_downloader/.gitignore new file mode 100644 index 0000000..2226749 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/.gitignore @@ -0,0 +1,71 @@ +.idea/ +*.pyc +*.pid +*.cfg +*.db +*.env +.DS_Store +.cache/ +.mypy_cache/ +.coverage +settings.json + +# Distribution / packaging +.Python +.pytest_cache +.python-version +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +logs/ +parts/ +sdist/ +share/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + + +# Jupyter Notebook +.ipynb_checkpoints +*.ipynb + +# virtualenv +.venv +venv/ +ENV/ +bin/ +include/ +pip-selfcheck.json +lib64 + +#Telegram Sessions +*.session +*.session-journal + +#Downloaded documents +documents/ +audio/ +document/ +photo/ +voice/ +video/ +video_note/ +parser.out +parsetab.py +local_test/ +.vscode +TODO.md +log/ +temp/ +data.yaml +*.scss +*.css.map diff --git a/src/parsers/Telegram/telegram_media_downloader/CODE_OF_CONDUCT.md b/src/parsers/Telegram/telegram_media_downloader/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..dc429ea --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at tangyoha@outlook.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/src/parsers/Telegram/telegram_media_downloader/CONTRIBUTING.md b/src/parsers/Telegram/telegram_media_downloader/CONTRIBUTING.md new file mode 100644 index 0000000..4cc2c7e --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/CONTRIBUTING.md @@ -0,0 +1,199 @@ +## Contributing + +First off, thank you for considering contributing to Telegram Media Downloader. It's people like you that make telegram-media-downloader such a great tool. +Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. + +### Where do I go from here? + +If you've noticed a bug or have a feature request, [make one](https://github.com/tangyoha/telegram_media_downloader/issues)! It's generally best if you get confirmation of your bug or approval for your feature request this way before starting to code. + +If you have a general question about telegram-media-downloader, you can ask it on [Discussion](https://github.com/tangyoha/telegram_media_downloader/discussions) under `Q&A` category and any ideas/suggestions goes under `Ideas` category, the issue tracker is only for bugs and feature requests. + +### Fork & create a branch + +If this is something you think you can fix, then [fork telegram-media-downloader](https://help.github.com/articles/fork-a-repo) and create a branch with a descriptive name. + +A good branch name would be (where issue #52 is the ticket you're working on): + +```sh + git checkout -b 52-fix-expired-file-reference +``` + +### For new Contributors + +If you never created a pull request before, welcome [Here is a great tutorial](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github) on how to send one :) + +1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: +```sh + # Clone your fork of the repo into the current directory + git clone https://github.com// + # Navigate to the newly cloned directory + cd + # Install dependencies + make dev_install + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/Dineshkkarthik/ +``` + +2. If you cloned a while ago, get the latest changes from upstream: +```sh + git checkout master + git pull upstream master +``` + +3. Create a new branch (off the main project master branch) to contain your feature, change, or fix based on the branch name convention described above: +```sh + git checkout -b +``` + +4. Make sure to update, or add to the tests when appropriate. Patches and features will not be accepted without tests. Run `make test` to check that all tests pass after you've made changes. + +5. If you added or changed a feature, make sure to document it accordingly in the `README.md` file. + +6. Push your branch up to your fork: +```sh + git push origin +``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description. + + +### Coding Standards + +#### Python style + +Please follow these coding standards when writing code for inclusion in telegram-media-downloader. + +Telegram-media-downloader follows the [PEP8](https://www.python.org/dev/peps/pep-0008/) standard and uses [Black](https://black.readthedocs.io/en/stable/) and [Pylint](https://pylint.pycqa.org/en/latest/) to ensure a consistent code format throughout the project. + +[Continuous Integration](https://github.com/tangyoha/telegram_media_downloader/actions) using GitHub Actions will run those tools and report any stylistic errors in your code. Therefore, it is helpful before submitting code to run the check yourself: +```sh +black media_downloader.py utils +``` +to auto-format your code. Additionally, many editors have plugins that will apply `black` as you edit files. + +Writing good code is not just about what you write. It is also about _how_ you write it. During [Continuous Integration](https://github.com/tangyoha/telegram_media_downloader/actions) testing, several tools will be run to check your code for stylistic errors. Generating any warnings will cause the test to fail. Thus, good style is a requirement for submitting code to telegram-media-downloader. + +This is already added in the repo to help contributors verify their changes before contributing them to the project: +```sh +make style_check +``` + +#### Type hints + +Telegram-media-downloader strongly encourages the use of [**PEP 484**](https://www.python.org/dev/peps/pep-0484) style type hints. New development should contain type hints and pull requests to annotate existing code are accepted as well! + +Types imports should follow the `from typing import ...` convention. So rather than +```py +import typing + +primes: typing.List[int] = [] +``` +You should write +```py +from typing import List, Optional, Union + +primes: List[int] = [] +``` + +`Optional` should be used where applicable, so instead of +```py +maybe_primes: List[Union[int, None]] = [] +``` +You should write +```py +maybe_primes: List[Optional[int]] = [] +``` + +#### Validating type hints + +telegram-media-downloader uses [mypy](http://mypy-lang.org/) to statically analyze the code base and type hints. After making any change you can ensure your type hints are correct by running +```sh +make static_type_check +``` + +#### Docstrings and standards + +A Python docstring is a string used to document a Python module, class, function or method, so programmers can understand what it does without having to read the details of the implementation. + +The next example gives an idea of what a docstring looks like: +```py +def add(num1: int, num2: int) -> int: + """ + Add up two integer numbers. + + This function simply wraps the ``+`` operator, and does not + do anything interesting, except for illustrating what + the docstring of a very simple function looks like. + + Parameters + ---------- + num1: int + First number to add. + num2: int + Second number to add. + + Returns + ------- + int + The sum of ``num1`` and ``num2``. + + See Also + -------- + subtract : Subtract one integer from another. + + Examples + -------- + >>> add(2, 2) + 4 + >>> add(25, 0) + 25 + >>> add(10, -10) + 0 + """ + return num1 + num2 +``` +Some standards regarding docstrings exist, which make them easier to read, and allow them be easily exported to other formats such as html or pdf. + +### Commit Message + +telegram-media-downloader uses a convention for commit message prefixes and layout. Here are some common prefixes along with general guidelines for when to use them: +``` +: +<-- OPTIONAL --> + + +``` + +#### Prefix: + +Must be one of the following: +- **add**: Adding a new file +- **ci**: Changes to CI configuration files and scripts (example: files inside `.github` folder) +- **clean**: Code cleanup +- **docs**: Additions/updates to documentation +- **enh**: Enhancement, new functionality +- **fix**: Bug fix +- **perf**: A code change that improves performance +- **refactor**: A code change that neither fixes a bug nor adds a feature +- **style**: Changes that do not affect the meaning of the code (white-space, formatting, etc) +- **test**: Additions/updates to tests +- **type**: Type annotations + +#### Subject: + +Please reference the relevant GitHub issues in your commit message using #1234. +- a subject line with `< 80` chars. +- summary in present tense. +- not capitalized. +- no period at the end. + +#### Commit Message Body + +Just as in the summary, use the imperative, present tense. + +Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change. You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change. + +### Code of Conduct + +As a contributor, you can help us keep the community open and inclusive. Please read and follow our [Code of Conduct](https://github.com/tangyoha/telegram_media_downloader/blob/master/CODE_OF_CONDUCT.md). diff --git a/src/parsers/Telegram/telegram_media_downloader/Dockerfile b/src/parsers/Telegram/telegram_media_downloader/Dockerfile new file mode 100644 index 0000000..0d21d42 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.11.2-alpine As compile-image + +WORKDIR /app + +COPY requirements.txt /app/ + +RUN apk add --no-cache --virtual .build-deps gcc musl-dev \ + && pip install --trusted-host pypi.python.org -r requirements.txt \ + && apk del .build-deps && rm -rf requirements.txt + +RUN apk add --no-cache rclone + +FROM python:3.11.2-alpine As runtime-image + +WORKDIR /app + +COPY --from=tangyoha/telegram_media_downloader_compile:latest /usr/bin/rclone /app/rclone/rclone + +COPY --from=tangyoha/telegram_media_downloader_compile:latest /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages + +COPY config.yaml data.yaml setup.py media_downloader.py /app/ +COPY module /app/module +COPY utils /app/utils + +CMD ["python", "media_downloader.py"] diff --git a/src/parsers/Telegram/telegram_media_downloader/LICENSE b/src/parsers/Telegram/telegram_media_downloader/LICENSE new file mode 100644 index 0000000..4bef804 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Dineshkarthik R + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/parsers/Telegram/telegram_media_downloader/Makefile b/src/parsers/Telegram/telegram_media_downloader/Makefile new file mode 100644 index 0000000..44d3589 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/Makefile @@ -0,0 +1,26 @@ +TEST_ARTIFACTS ?= /tmp/coverage + +.PHONY: install dev_install static_type_check pylint style_check test + +install: + python3 -m pip install --upgrade pip setuptools + python3 -m pip install -r requirements.txt + +dev_install: install + python3 -m pip install -r dev-requirements.txt + +static_type_check: + mypy media_downloader.py utils module --ignore-missing-imports + +pylint: + pylint media_downloader.py utils module -r y + +style_check: static_type_check pylint + +test: + py.test --cov media_downloader --doctest-modules \ + --cov utils \ + --cov-report term-missing \ + --cov-report html:${TEST_ARTIFACTS} \ + --junit-xml=${TEST_ARTIFACTS}/media-downloader.xml \ + tests/ diff --git a/src/parsers/Telegram/telegram_media_downloader/README.md b/src/parsers/Telegram/telegram_media_downloader/README.md new file mode 100644 index 0000000..d0eeee6 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/README.md @@ -0,0 +1,286 @@ + +

Telegram Media Downloader

+ +

+Unittest +Coverage Status +License: MIT +Code style: black + +Code style: black +

+ +

+ 中文 · + Feature request + · + Report a bug + · + Support: Discussions + & + Telegram Community +

+ +## Overview +> Support two default running + +* The robot is running, and the command `download` or `forward` is issued from the robot + +* Download as a one-time download tool + +### UI + +#### Web page + +> After running, open a browser and visit `localhost:5000` +> If it is a remote machine, you need to configure web_host: 0.0.0.0 + + +Code style: black + +### Robot + +> Need to configure bot_token, please refer to [Documentation](https://github.com/tangyoha/telegram_media_downloader/wiki/How-to-Download-Using-Robots) + +Code style: black + +### Support + +| Category | Support | +| -------------------- | ------------------------------------------------ | +| Language | `Python 3.7` and above | +| Download media types | audio, document, photo, video, video_note, voice | + +### Version release plan + +* [v2.2.0](https://github.com/tangyoha/telegram_media_downloader/issues/2) + +## Installation + +For *nix os distributions with `make` availability + +```sh +git clone https://github.com/tangyoha/telegram_media_downloader.git +cd telegram_media_downloader +make install +``` + +For Windows which doesn't have `make` inbuilt + +```sh +git clone https://github.com/tangyoha/telegram_media_downloader.git +cd telegram_media_downloader +pip3 install -r requirements.txt +``` + +## Docker +> For more detailed installation tutorial, please check the wiki + +Make sure you have **docker** and **docker-compose** installed +```sh +docker pull tangyoha/telegram_media_downloader:latest +mkdir -p ~/app && mkdir -p ~/app/log/ && cd ~/app +wget https://raw.githubusercontent.com/tangyoha/telegram_media_downloader/master/docker-compose.yaml -O docker-compose.yaml +wget https://raw.githubusercontent.com/tangyoha/telegram_media_downloader/master/config.yaml -O config.yaml +wget https://raw.githubusercontent.com/tangyoha/telegram_media_downloader/master/data.yaml -O data.yaml +# vi config.yaml and docker-compose.yaml +vi config.yaml + +# The first time you need to start the foreground +# enter your phone number and code, then exit(ctrl + c) +docker-compose run --rm telegram_media_downloader + +# After performing the above operations, all subsequent startups will start in the background +docker-compose up -d + +# Upgrade +docker pull tangyoha/telegram_media_downloader:latest +cd ~/app +docker-compose down +docker-compose up -d +``` + +## Upgrade installation + +```sh +cd telegram_media_downloader +pip3 install -r requirements.txt +``` + +## Configuration + +All the configurations are passed to the Telegram Media Downloader via `config.yaml` file. + +**Getting your API Keys:** +The very first step requires you to obtain a valid Telegram API key (API id/hash pair): + +1. Visit [https://my.telegram.org/apps](https://my.telegram.org/apps) and log in with your Telegram Account. +2. Fill out the form to register a new Telegram application. +3. Done! The API key consists of two parts: **api_id** and **api_hash**. + +**Getting chat id:** + +**1. Using web telegram:** + +1. Open + +2. Now go to the chat/channel and you will see the URL as something like + - `https://web.telegram.org/?legacy=1#/im?p=u853521067_2449618633394` here `853521067` is the chat id. + - `https://web.telegram.org/?legacy=1#/im?p=@somename` here `somename` is the chat id. + - `https://web.telegram.org/?legacy=1#/im?p=s1301254321_6925449697188775560` here take `1301254321` and add `-100` to the start of the id => `-1001301254321`. + - `https://web.telegram.org/?legacy=1#/im?p=c1301254321_6925449697188775560` here take `1301254321` and add `-100` to the start of the id => `-1001301254321`. + +**2. Using bot:** + +1. Use [@username_to_id_bot](https://t.me/username_to_id_bot) to get the chat_id of + - almost any telegram user: send username to the bot or just forward their message to the bot + - any chat: send chat username or copy and send its joinchat link to the bot + - public or private channel: same as chats, just copy and send to the bot + - id of any telegram bot + +### config.yaml + +```yaml +api_hash: your_api_hash +api_id: your_api_id +chat: +- chat_id: telegram_chat_id + last_read_message_id: 0 + download_filter: message_date >= 2022-12-01 00:00:00 and message_date <= 2023-01-17 00:00:00 +- chat_id: telegram_chat_id_2 + last_read_message_id: 0 +# note we remove ids_to_retry to data.yaml +ids_to_retry: [] +media_types: +- audio +- document +- photo +- video +- voice +- animation #gif +file_formats: + audio: + - all + document: + - pdf + - epub + video: + - mp4 +save_path: D:\telegram_media_downloader +file_path_prefix: +- chat_title +- media_datetime +disable_syslog: +- INFO +upload_drive: + # required + enable_upload_file: true + # required + remote_dir: drive:/telegram + # required + upload_adapter: rclone + # option,when config upload_adapter rclone then this config are required + rclone_path: D:\rclone\rclone.exe + # option + before_upload_file_zip: True + # option + after_upload_file_delete: True +hide_file_name: true +file_name_prefix: +- message_id +- file_name +file_name_prefix_split: ' - ' +max_download_task: 5 +web_host: 127.0.0.1 +web_port: 5000 +language: EN +web_login_secret: 123 +``` + +- **api_hash** - The api_hash you got from telegram apps +- **api_id** - The api_id you got from telegram apps +- **bot_token** - Your bot token +- **chat** - Chat list + - `chat_id` - The id of the chat/channel you want to download media. Which you get from the above-mentioned steps. + - `download_filter` - Download filter, see [How to use Filter](https://github.com/tangyoha/telegram_media_downloader/wiki/How-to-use-Filter) + - `last_read_message_id` - If it is the first time you are going to read the channel let it be `0` or if you have already used this script to download media it will have some numbers which are auto-updated after the scripts successful execution. Don't change it. + - `ids_to_retry` - `Leave it as it is.` This is used by the downloader script to keep track of all skipped downloads so that it can be downloaded during the next execution of the script. +- **media_types** - Type of media to download, you can update which type of media you want to download it can be one or any of the available types. +- **file_formats** - File types to download for supported media types which are `audio`, `document` and `video`. Default format is `all`, downloads all files. +- **save_path** - The root directory where you want to store downloaded files. +- **file_path_prefix** - Store file subfolders, the order of the list is not fixed, can be randomly combined. + - `chat_title` - Channel or group title, it will be chat id if not exist title. + - `media_datetime` - Media date, also see pyrogram.types.Message.date.strftime("%Y_%m"). + - `media_type` - Media type, also see `media_types`. +- **disable_syslog** - You can choose which types of logs to disable,see `logging._nameToLevel`. +- **upload_drive** - You can upload file to cloud drive. + - `enable_upload_file` - Enable upload file, default `false`. + - `remote_dir` - Where you upload, like `drive_id/drive_name`. + - `upload_adapter` - Upload file adapter, which can be `rclone`, `aligo`. If it is `rclone`, it supports all `rclone` servers that support uploading. If it is `aligo`, it supports uploading `Ali cloud disk`. + - `rclone_path` - RClone exe path, see [How to use rclone](https://github.com/tangyoha/telegram_media_downloader/wiki/Rclone) + - `before_upload_file_zip` - Zip file before upload, default `false`. + - `after_upload_file_delete` - Delete file after upload success, default `false`. +- **file_name_prefix** - Custom file name, use the same as **file_path_prefix** + - `message_id` - Message id + - `file_name` - File name (may be empty) + - `caption` - The title of the message (may be empty) +- **file_name_prefix_split** - Custom file name prefix symbol, the default is `-` +- **max_download_task** - The maximum number of task download tasks, the default is 5. +- **hide_file_name** - Whether to hide the web interface file name, default `false` +- **web_host** - Web host +- **web_port** - Web port +- **language** - Application language, the default is English (`EN`), optional `ZH`(Chinese),`RU`,`UA` +- **web_login_secret** - Web page login password, if not configured, no login is required to access the web page + + +## Execution + +```sh +python3 media_downloader.py +``` + +All downloaded media will be stored at the root of `save_path`. +The specific location reference is as follows: + +The complete directory of video download is: `save_path`/`chat_title`/`media_datetime`/`media_type`. +The order of the list is not fixed and can be randomly combined. +If the configuration is empty, all files are saved under `save_path`. + +## Proxy + +`socks4, socks5, http` proxies are supported in this project currently. To use it, add the following to the bottom of your `config.yaml` file + +```yaml +proxy: + scheme: socks5 + hostname: 127.0.0.1 + port: 1234 + username: your_username(delete the line if none) + password: your_password(delete the line if none) +``` + +If your proxy doesn’t require authorization you can omit username and password. Then the proxy will automatically be enabled. + +## Contributing + +### Contributing Guidelines + +Read through our [contributing guidelines](https://github.com/tangyoha/telegram_media_downloader/blob/master/CONTRIBUTING.md) to learn about our submission process, coding rules and more. + +### Want to Help? + +Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing](https://github.com/tangyoha/telegram_media_downloader/blob/master/CONTRIBUTING.md). + +### Code of Conduct + +Help us keep Telegram Media Downloader open and inclusive. Please read and follow our [Code of Conduct](https://github.com/tangyoha/telegram_media_downloader/blob/master/CODE_OF_CONDUCT.md). + + +### Sponsor + +[PayPal](https://paypal.me/tangyoha?country.x=C2&locale.x=zh_XC) + +

+Code style: black +Code style: black +

diff --git a/src/parsers/Telegram/telegram_media_downloader/README_CN.md b/src/parsers/Telegram/telegram_media_downloader/README_CN.md new file mode 100644 index 0000000..48e666f --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/README_CN.md @@ -0,0 +1,286 @@ + +

电报资源下载

+ +

+Unittest +Coverage Status +License: MIT +Code style: black + +Code style: black + +

+ +

+ English · + 新功能请求 + · + 报告bug + · + 帮助: 讨论 + & + 电报讨论群 +

+ +## 概述 + +> 支持两种默认运行 + +* 机器人运行,从机器人下发命令`下载`或者`转发` + +* 作为一个一次性的下载工具下载 + +### 界面 + +#### 网页 + +> 运行后打开浏览器访问`localhost:5000` +> 如果是远程机器需要配置web_host: 0.0.0.0 + + +Code style: black + +### 机器人 + +> 需要配置bot_token,具体参考[文档](https://github.com/tangyoha/telegram_media_downloader/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E6%9C%BA%E5%99%A8%E4%BA%BA%E4%B8%8B%E8%BD%BD) + + +Code style: black + +### 支持 + +| 类别 | 支持 | +| ------------ | ---------------------------------------- | +| 语言 | `Python 3.7` 及以上 | +| 下载媒体类型 | 音频、文档、照片、视频、video_note、语音 | + +### 版本发布计划 + +* [v2.2.0](https://github.com/tangyoha/telegram_media_downloader/issues/2) + +## 安装 + +对于具有 `make` 可用性的 *nix 操作系统发行版 + +```sh +git clone https://github.com/tangyoha/telegram_media_downloader.git +cd telegram_media_downloader +make install +``` + +对于没有内置 `make` 的 Windows + +```sh +git clone https://github.com/tangyoha/telegram_media_downloader.git +cd telegram_media_downloader +pip3 install -r requirements.txt +``` +## Docker容器 +> 更详细安装教程请查看wiki + +确保安装了 **docker** 和 **docker-compose** +```sh +docker pull tangyoha/telegram_media_downloader:latest +mkdir -p ~/app && mkdir -p ~/app/log/ && cd ~/app +wget https://raw.githubusercontent.com/tangyoha/telegram_media_downloader/blob/master/docker-compose.yaml -O docker-compose.yaml +wget https://raw.githubusercontent.com/tangyoha/telegram_media_downloader/blob/master/config.yaml -O config.yaml +wget https://raw.githubusercontent.com/tangyoha/telegram_media_downloader/blob/master/data.yaml -O data.yaml +# vi config.yaml and docker-compose.yaml +vi config.yaml + +# 第一次需要前台启动 +# 输入你的电话号码和密码,然后退出(ctrl + c) +docker-compose run --rm telegram_media_downloader + +# 执行完以上操作后,后面的所有启动都在后台启动 +docker-compose up -d + +# 升级 +docker pull tangyoha/telegram_media_downloader:latest +cd ~/app +docker-compose down +docker-compose up -d +``` + +## 升级安装 + +```sh +cd telegram_media_downloader +pip3 install -r requirements.txt +``` + +## 配置 + +所有配置都通过 config.yaml 文件传递​​给 `Telegram Media Downloader`。 + +**获取您的 API 密钥:** +第一步需要您获得有效的 Telegram API 密钥(API id/hash pair): + +1. 访问 [https://my.telegram.org/apps](https://my.telegram.org/apps) 并使用您的 Telegram 帐户登录。 +2. 填写表格以注册新的 Telegram 应用程序。 +3. 完成! API 密钥由两部分组成:**api_id** 和**api_hash**。 + +**获取聊天ID:** +> 如果你需要下载收藏夹的内容请填`me` + +**1。使用网络电报:** + +1. 打开 +2. 现在转到聊天/频道,您将看到 URL 类似 + +- `https://web.telegram.org/?legacy=1#/im?p=u853521067_2449618633394` 这里 `853521067` 是聊天 ID。 +- `https://web.telegram.org/?legacy=1#/im?p=@somename` 这里的 `somename` 是聊天 ID。 +- `https://web.telegram.org/?legacy=1#/im?p=s1301254321_6925449697188775560` 此处取 `1301254321` 并将 `-100` 添加到 id => `-1001301254321` 的开头。 +- `https://web.telegram.org/?legacy=1#/im?p=c1301254321_6925449697188775560` 此处取 `1301254321` 并将 `-100` 添加到 id => `-1001301254321` 的开头。 + +**2。使用机器人:** +1.使用[@username_to_id_bot](https://t.me/username_to_id_bot)获取chat_id + - 几乎所有电报用户:将用户名发送给机器人或将他们的消息转发给机器人 + - 任何聊天:发送聊天用户名或复制并发送其加入聊天链接到机器人 + - 公共或私人频道:与聊天相同,只需复制并发送给机器人 + - 任何电报机器人的 ID + +### 配置文件 + +```yaml +api_hash: your_api_hash +api_id: your_api_id +bot_token: your_bot_token +chat: +- chat_id: telegram_chat_id + last_read_message_id: 0 + download_filter: message_date >= 2022-12-01 00:00:00 and message_date <= 2023-01-17 00:00:00 +- chat_id: telegram_chat_id_2 + last_read_message_id: 0 +# 我们将ids_to_retry移到data.yaml +ids_to_retry: [] +media_types: +- audio +- document +- photo +- video +- voice +- animation #gif +file_formats: + audio: + - all + document: + - pdf + - epub + video: + - mp4 +save_path: D:\telegram_media_downloader +file_path_prefix: +- chat_title +- media_datetime +disable_syslog: +- INFO +upload_drive: + enable_upload_file: true + remote_dir: drive:/telegram + before_upload_file_zip: True + after_upload_file_delete: True +hide_file_name: true +file_name_prefix: +- message_id +- file_name +file_name_prefix_split: ' - ' +max_download_task: 5 +web_host: 127.0.0.1 +web_port: 5000 +web_login_secret: 123 +``` + +- **api_hash** - 你从电报应用程序获得的 api_hash +- **api_id** - 您从电报应用程序获得的 api_id +- **bot_token** - 你的机器人凭证 +- **chat** - 多频道 + - `chat_id` - 您要下载媒体的聊天/频道的 ID。你从上述步骤中得到的。 + - `download_filter` - 下载过滤器, 查阅 [如何使用过滤器](https://github.com/tangyoha/telegram_media_downloader/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E8%BF%87%E6%BB%A4%E5%99%A8) + - `last_read_message_id` -如果这是您第一次阅读频道,请将其设置为“0”,或者如果您已经使用此脚本下载媒体,它将有一些数字,这些数字会在脚本成功执行后自动更新。不要改变它。 +- **chat_id** - 您要下载媒体的聊天/频道的 ID。你从上述步骤中得到的。 +- **last_read_message_id** - 如果这是您第一次阅读频道,请将其设置为“0”,或者如果您已经使用此脚本下载媒体,它将有一些数字,这些数字会在脚本成功执行后自动更新。不要改变它。 +- **ids_to_retry** - `保持原样。`下载器脚本使用它来跟踪所有跳过的下载,以便在下次执行脚本时可以下载它。 +- **media_types** - 要下载的媒体类型,您可以更新要下载的媒体类型,它可以是一种或任何可用类型。 +- **file_formats** - 为支持的媒体类型(“音频”、“文档”和“视频”)下载的文件类型。默认格式为“all”,下载所有文件。 +- **save_path** - 你想存储下载文件的根目录 +- **file_path_prefix** - 存储文件子文件夹,列表的顺序不定,可以随机组合 + - `chat_title` - 聊天频道或者群组标题, 如果找不到标题则为配置文件中的`chat_id` + - `media_datetime` - 资源的发布时间 + - `media_type` - 资源类型,类型查阅 `media_types` +- **disable_syslog** - 您可以选择要禁用的日志类型,请参阅 `logging._nameToLevel` +- **upload_drive** - 您可以将文件上传到云盘 + - `enable_upload_file` - [必填]启用上传文件,默认为`false` + - `remote_dir` - [必填]你上传的地方 + - `upload_adapter` - [必填]上传文件适配器,可以为`rclone`,`aligo`。如果为`rclone`,则支持rclone所有支持上传的服务器,如果为aligo,则支持上传阿里云盘 + - `rclone_path`,如果配置`upload_adapter`为`rclone`则为必填,`rclone`的可执行目录,查阅 [如何使用rclone](https://github.com/tangyoha/telegram_media_downloader/wiki/Rclone) + - `before_upload_file_zip` - 上传前压缩文件,默认为`false` + - `after_upload_file_delete` - 上传成功后删除文件,默认为`false` +- **file_name_prefix** - 自定义文件名称,使用和 **file_path_prefix** 一样 + - `message_id` - 消息id + - `file_name` - 文件名称(可能为空) + - `caption` - 消息的标题(可能为空) +- **file_name_prefix_split** - 自定义文件名称分割符号,默认为` - ` +- **max_download_task** - 最大任务下载任务个数,默认为5个。 +- **hide_file_name** - 是否隐藏web界面文件名称,默认`false` +- **web_host** - web界面地址 +- **web_port** - web界面端口 +- **language** - 应用语言,默认为英文(`EN`),可选`ZH`(中文),`RU`,`UA` +- **web_login_secret** - 网页登录密码,如果不配置则访问网页不需要登录 + +## 执行 + +```sh +python3 media_downloader.py +``` + +所有下载的媒体都将存储在`save_path`根目录下。 +具体位置参考如下: + +```yaml +file_path_prefix: + - chat_title + - media_datetime + - media_type +``` + +视频下载完整目录为:`save_path`/`chat_title`/`media_datetime`/`media_type`。 +列表的顺序不定,可以随机组合。 +如果配置为空,则所有文件保存在`save_path`下。 + +## 代理 + +该项目目前支持 socks4、socks5、http 代理。要使用它,请将以下内容添加到`config.yaml`文件的底部 + +```yaml +proxy: + scheme: socks5 + hostname: 127.0.0.1 + port: 1234 + username: 你的用户名(无则删除该行) + password: 你的密码(无则删除该行) +``` + +如果您的代理不需要授权,您可以省略用户名和密码。然后代理将自动启用。 + +## 贡献 + +### 贡献指南 + +通读我们的[贡献指南](CONTRIBUTING.md),了解我们的提交流程、编码规则等。 + +### 想帮忙? + +想要提交错误、贡献一些代码或改进文档?出色的!阅读我们的 [贡献指南](CONTRIBUTING.md)。 + +### 行为守则 + +帮助我们保持 Telegram Media Downloader 的开放性和包容性。请阅读并遵守我们的[行为准则](CODE_OF_CONDUCT.md)。 + + +### 赞助 + +

+Code style: black +Code style: black +

diff --git a/src/parsers/Telegram/telegram_media_downloader/codecov.yml b/src/parsers/Telegram/telegram_media_downloader/codecov.yml new file mode 100644 index 0000000..1fbaabe --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/codecov.yml @@ -0,0 +1,13 @@ +coverage: + status: + project: + default: + target: auto + threshold: 1% + if_no_uploads: error + if_not_found: success + if_ci_failed: error + patch: no + +comment: + require_changes: true diff --git a/src/parsers/Telegram/telegram_media_downloader/dev-requirements.txt b/src/parsers/Telegram/telegram_media_downloader/dev-requirements.txt new file mode 100644 index 0000000..c0d7c62 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/dev-requirements.txt @@ -0,0 +1,9 @@ +black==22.6.0 +isort==5.10.1 +mock==4.0.3 +mypy==0.971 +pre-commit==2.20.0 +pylint==2.14.5 +pytest==7.2.1 +pytest-cov==3.0.0 +types-PyYAML==6.0.11 diff --git a/src/parsers/Telegram/telegram_media_downloader/docker-compose.yaml b/src/parsers/Telegram/telegram_media_downloader/docker-compose.yaml new file mode 100644 index 0000000..8552299 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/docker-compose.yaml @@ -0,0 +1,29 @@ +version: "3.3" + +services: + telegram_media_downloader: + image: tangyoha/telegram_media_downloader:latest + build: . + ports: + # Here is what you need to edit + - "5000:5000" + #environment: + # - http_proxy=http://192.168.101.30:10811 + # - https_proxy=http://192.168.101.30:10811 + volumes: + # Here is what you need to edit + - "./downloads/:/app/downloads/" + + # Rclone + - "$HOME/.config/rclone/:$HOME/.config/rclone/" + + # The following is what you don't need to edit + - "./config.yaml:/app/config.yaml" + - "./data.yaml:/app/data.yaml" + - "./log/:/app/log/" + - "./sessions/:/app/sessions" + - "./temp/:/app/temp" + #restart: "unless-stopped" +# volumes: +# sessions: +# temp: diff --git a/src/parsers/Telegram/telegram_media_downloader/gen_filter_cache.py b/src/parsers/Telegram/telegram_media_downloader/gen_filter_cache.py new file mode 100644 index 0000000..903c084 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/gen_filter_cache.py @@ -0,0 +1,3 @@ +from module.filter import Filter + +Filter() diff --git a/src/parsers/Telegram/telegram_media_downloader/media_downloader.py b/src/parsers/Telegram/telegram_media_downloader/media_downloader.py new file mode 100644 index 0000000..5b78883 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/media_downloader.py @@ -0,0 +1,628 @@ +"""Downloads media from telegram.""" +import asyncio +import logging +import os +import shutil +import time +from typing import List, Optional, Tuple, Union + +import pyrogram +from loguru import logger +from pyrogram.types import Audio, Document, Photo, Video, VideoNote, Voice +from rich.logging import RichHandler + +from module.app import Application, ChatDownloadConfig, DownloadStatus, TaskNode +from module.bot import start_download_bot, stop_download_bot +from module.download_stat import update_download_status +from module.get_chat_history_v2 import get_chat_history_v2 +from module.language import _t +from module.pyrogram_extension import ( + fetch_message, + get_extension, + record_download_status, + report_bot_download_status, + set_max_concurrent_transmissions, + set_meta_data, + upload_telegram_chat, +) +from module.web import init_web +from utils.format import truncate_filename, validate_title +from utils.log import LogFilter +from utils.meta import print_meta +from utils.meta_data import MetaData +from utils.updates import check_for_updates + +logging.basicConfig( + level=logging.INFO, + format="%(message)s", + datefmt="[%X]", + handlers=[RichHandler()], +) + +CONFIG_NAME = "config.yaml" +DATA_FILE_NAME = "data.yaml" +APPLICATION_NAME = "media_downloader" +app = Application(CONFIG_NAME, DATA_FILE_NAME, APPLICATION_NAME) + +logger.add( + os.path.join(app.log_file_path, "tdl.log"), + rotation="10 MB", + retention="10 days", + level="DEBUG", +) + +queue: asyncio.Queue = asyncio.Queue() +RETRY_TIME_OUT = 3 + +logging.getLogger("pyrogram.session.session").addFilter(LogFilter()) +logging.getLogger("pyrogram.client").addFilter(LogFilter()) + +logging.getLogger("pyrogram").setLevel(logging.WARNING) + + +def _check_download_finish(media_size: int, download_path: str, ui_file_name: str): + """Check download task if finish + + Parameters + ---------- + media_size: int + The size of the downloaded resource + download_path: str + Resource download hold path + ui_file_name: str + Really show file name + + """ + download_size = os.path.getsize(download_path) + if media_size == download_size: + logger.success(f"{_t('Successfully downloaded')} - {ui_file_name}") + else: + logger.warning( + f"{_t('Media downloaded with wrong size')}: " + f"{download_size}, {_t('actual')}: " + f"{media_size}, {_t('file name')}: {ui_file_name}" + ) + os.remove(download_path) + raise pyrogram.errors.exceptions.bad_request_400.BadRequest() + + +def _move_to_download_path(temp_download_path: str, download_path: str): + """Move file to download path + + Parameters + ---------- + temp_download_path: str + Temporary download path + + download_path: str + Download path + + """ + + directory, _ = os.path.split(download_path) + os.makedirs(directory, exist_ok=True) + shutil.move(temp_download_path, download_path) + + +def _check_timeout(retry: int, _: int): + """Check if message download timeout, then add message id into failed_ids + + Parameters + ---------- + retry: int + Retry download message times + + message_id: int + Try to download message 's id + + """ + if retry == 2: + return True + return False + + +def _can_download(_type: str, file_formats: dict, file_format: Optional[str]) -> bool: + """ + Check if the given file format can be downloaded. + + Parameters + ---------- + _type: str + Type of media object. + file_formats: dict + Dictionary containing the list of file_formats + to be downloaded for `audio`, `document` & `video` + media types + file_format: str + Format of the current file to be downloaded. + + Returns + ------- + bool + True if the file format can be downloaded else False. + """ + if _type in ["audio", "document", "video"]: + allowed_formats: list = file_formats[_type] + if not file_format in allowed_formats and allowed_formats[0] != "all": + return False + return True + + +def _is_exist(file_path: str) -> bool: + """ + Check if a file exists and it is not a directory. + + Parameters + ---------- + file_path: str + Absolute path of the file to be checked. + + Returns + ------- + bool + True if the file exists else False. + """ + return not os.path.isdir(file_path) and os.path.exists(file_path) + + +# pylint: disable = R0912 + + +async def _get_media_meta( + chat_id: Union[int, str], + message: pyrogram.types.Message, + media_obj: Union[Audio, Document, Photo, Video, VideoNote, Voice], + _type: str, +) -> Tuple[str, str, Optional[str]]: + """Extract file name and file id from media object. + + Parameters + ---------- + media_obj: Union[Audio, Document, Photo, Video, VideoNote, Voice] + Media object to be extracted. + _type: str + Type of media object. + + Returns + ------- + Tuple[str, str, Optional[str]] + file_name, file_format + """ + if _type in ["audio", "document", "video"]: + # pylint: disable = C0301 + file_format: Optional[str] = media_obj.mime_type.split("/")[-1] # type: ignore + else: + file_format = None + + file_name = None + temp_file_name = None + dirname = validate_title(f"{chat_id}") + if message.chat and message.chat.title: + dirname = validate_title(f"{message.chat.title}") + + if message.date: + datetime_dir_name = message.date.strftime("%Y_%m") + else: + datetime_dir_name = "0" + + if _type in ["voice", "video_note"]: + # pylint: disable = C0209 + file_format = media_obj.mime_type.split("/")[-1] # type: ignore + file_save_path = app.get_file_save_path(_type, dirname, datetime_dir_name) + file_name = "{} - {}_{}.{}".format( + message.id, + _type, + media_obj.date.isoformat(), # type: ignore + file_format, + ) + file_name = validate_title(file_name) + temp_file_name = os.path.join(app.temp_save_path, dirname, file_name) + + file_name = os.path.join(file_save_path, file_name) + else: + file_name = getattr(media_obj, "file_name", None) + caption = getattr(message, "caption", None) + + file_name_suffix = ".unknown" + if not file_name: + file_name_suffix = get_extension( + media_obj.file_id, getattr(media_obj, "mime_type", "") + ) + else: + # file_name = file_name.split(".")[0] + _, file_name_without_suffix = os.path.split(os.path.normpath(file_name)) + file_name, file_name_suffix = os.path.splitext(file_name_without_suffix) + if not file_name_suffix: + file_name_suffix = get_extension( + media_obj.file_id, getattr(media_obj, "mime_type", "") + ) + + if caption: + caption = validate_title(caption) + app.set_caption_name(chat_id, message.media_group_id, caption) + else: + caption = app.get_caption_name(chat_id, message.media_group_id) + + if not file_name and message.photo: + file_name = f"{message.photo.file_unique_id}" + + gen_file_name = ( + app.get_file_name(message.id, file_name, caption) + file_name_suffix + ) + + file_save_path = app.get_file_save_path(_type, dirname, datetime_dir_name) + + temp_file_name = os.path.join(app.temp_save_path, dirname, gen_file_name) + + file_name = os.path.join(file_save_path, gen_file_name) + return truncate_filename(file_name), truncate_filename(temp_file_name), file_format + + +async def add_download_task(message: pyrogram.types.Message, node: TaskNode): + """Add Download task""" + if message.empty: + return False + await queue.put((message, node)) + node.total_task += 1 + return True + + +async def download_task( + client: pyrogram.Client, message: pyrogram.types.Message, node: TaskNode +): + """Download and Forward media""" + + download_status, file_name = await download_media( + client, message, app.media_types, app.file_formats, node.chat_id, node.task_id + ) + + if not node.bot: + app.set_download_id(node.chat_id, message.id, download_status) + + file_size = os.path.getsize(file_name) if file_name else 0 + + await upload_telegram_chat( + client, + node.upload_user if node.upload_user else client, + app, + node, + message, + file_name, + download_status, + ) + + # rclone upload + if ( + not node.upload_telegram_chat_id + and download_status is DownloadStatus.SuccessDownload + ): + if await app.upload_file(file_name): + node.upload_success_count += 1 + + await report_bot_download_status( + node.bot, + node, + download_status, + file_size, + ) + + +# pylint: disable = R0915,R0914 + + +@record_download_status +async def download_media( + client: pyrogram.client.Client, + message: pyrogram.types.Message, + media_types: List[str], + file_formats: dict, + chat_id: Union[int, str], + task_id: int = 0, +): + """ + Download media from Telegram. + + Each of the files to download are retried 3 times with a + delay of 5 seconds each. + + Parameters + ---------- + client: pyrogram.client.Client + Client to interact with Telegram APIs. + message: pyrogram.types.Message + Message object retrieved from telegram. + media_types: list + List of strings of media types to be downloaded. + Ex : `["audio", "photo"]` + Supported formats: + * audio + * document + * photo + * video + * voice + file_formats: dict + Dictionary containing the list of file_formats + to be downloaded for `audio`, `document` & `video` + media types. + + Returns + ------- + int + Current message id. + """ + + # pylint: disable = R0912 + + file_name: str = "" + ui_file_name: str = "" + task_start_time: float = time.time() + media_size = 0 + _media = None + message = await fetch_message(client, message) + try: + for _type in media_types: + _media = getattr(message, _type, None) + if _media is None: + continue + file_name, temp_file_name, file_format = await _get_media_meta( + chat_id, message, _media, _type + ) + media_size = getattr(_media, "file_size", 0) + + ui_file_name = file_name + if app.hide_file_name: + ui_file_name = f"****{os.path.splitext(file_name)[-1]}" + + if _can_download(_type, file_formats, file_format): + if _is_exist(file_name): + file_size = os.path.getsize(file_name) + if file_size or file_size == media_size: + logger.info( + f"id={message.id} {ui_file_name} " + f"{_t('already download,download skipped')}.\n" + ) + + return DownloadStatus.SkipDownload, None + else: + return DownloadStatus.SkipDownload, None + + break + except Exception as e: + logger.error( + f"Message[{message.id}]: " + f"{_t('could not be downloaded due to following exception')}:\n[{e}].", + exc_info=True, + ) + return DownloadStatus.FailedDownload, None + if _media is None: + return DownloadStatus.SkipDownload, None + + message_id = message.id + + for retry in range(3): + try: + temp_download_path = await client.download_media( + message, + file_name=temp_file_name, + progress=update_download_status, + progress_args=( + chat_id, + message_id, + ui_file_name, + task_start_time, + task_id, + ), + ) + + if temp_download_path and isinstance(temp_download_path, str): + _check_download_finish(media_size, temp_download_path, ui_file_name) + await asyncio.sleep(0.5) + _move_to_download_path(temp_download_path, file_name) + # TODO: if not exist file size or media + return DownloadStatus.SuccessDownload, file_name + except pyrogram.errors.exceptions.bad_request_400.BadRequest: + logger.warning( + f"Message[{message.id}]: {_t('file reference expired, refetching')}..." + ) + await asyncio.sleep(RETRY_TIME_OUT) + message = await fetch_message(client, message) + if _check_timeout(retry, message.id): + # pylint: disable = C0301 + logger.error( + f"Message[{message.id}]: " + f"{_t('file reference expired for 3 retries, download skipped.')}" + ) + except pyrogram.errors.exceptions.flood_420.FloodWait as wait_err: + await asyncio.sleep(wait_err.value) + logger.warning("Message[{}]: FlowWait {}", message.id, wait_err.value) + _check_timeout(retry, message.id) + except TypeError: + # pylint: disable = C0301 + logger.warning( + f"{_t('Timeout Error occurred when downloading Message')}[{message.id}], " + f"{_t('retrying after')} {RETRY_TIME_OUT} {_t('seconds')}" + ) + await asyncio.sleep(RETRY_TIME_OUT) + if _check_timeout(retry, message.id): + logger.error( + f"Message[{message.id}]: {_t('Timing out after 3 reties, download skipped.')}" + ) + except Exception as e: + # pylint: disable = C0301 + logger.error( + f"Message[{message.id}]: " + f"{_t('could not be downloaded due to following exception')}:\n[{e}].", + exc_info=True, + ) + break + + return DownloadStatus.FailedDownload, None + + +def _load_config(): + """Load config""" + app.load_config() + + +def _check_config() -> bool: + """Check config""" + print_meta(logger) + try: + _load_config() + except Exception as e: + logger.exception(f"load config error: {e}") + return False + + return True + + +async def worker(client: pyrogram.client.Client): + """Work for download task""" + while app.is_running: + try: + item = await queue.get() + message = item[0] + node: TaskNode = item[1] + + if node.client: + await download_task(node.client, message, node) + else: + await download_task(client, message, node) + except Exception as e: + logger.exception(f"{e}") + + +async def download_chat_task( + client: pyrogram.Client, + chat_download_config: ChatDownloadConfig, + node: TaskNode, +): + """Download all task""" + messages_iter = get_chat_history_v2( + client, + node.chat_id, + limit=node.limit, + offset_id=chat_download_config.last_read_message_id, + reverse=True, + ) + if chat_download_config.ids_to_retry: + logger.info(f"{_t('Downloading files failed during last run')}...") + skipped_messages: list = await client.get_messages( # type: ignore + chat_id=node.chat_id, message_ids=chat_download_config.ids_to_retry + ) + + for message in skipped_messages: + if not await add_download_task(message, node): + chat_download_config.downloaded_ids.append(message.id) + + async for message in messages_iter: # type: ignore + meta_data = MetaData() + + caption = message.caption + if caption: + caption = validate_title(caption) + app.set_caption_name(node.chat_id, message.media_group_id, caption) + else: + caption = app.get_caption_name(node.chat_id, message.media_group_id) + set_meta_data(meta_data, message, caption) + + if not app.need_skip_message( + chat_download_config, message.id, meta_data + ) and await add_download_task(message, node): + chat_download_config.downloaded_ids.append(message.id) + + chat_download_config.need_check = True + chat_download_config.total_task = node.total_task + node.is_running = True + + +async def download_all_chat(client: pyrogram.Client): + """Download All chat""" + for key, value in app.chat_download_config.items(): + node = TaskNode(chat_id=key) + try: + await download_chat_task(client, value, node) + except Exception as e: + logger.warning(f"Download {key} error: {e}") + finally: + value.need_check = True + + +async def run_until_all_task_finish(): + """Normal download""" + while True: + finish: bool = True + for _, value in app.chat_download_config.items(): + if not value.need_check or value.total_task != value.finish_task: + finish = False + + if finish: + break + + await asyncio.sleep(1) + + +def _exec_loop(): + """Exec loop""" + + if app.bot_token: + app.loop.run_forever() + else: + app.loop.run_until_complete(run_until_all_task_finish()) + + +def main(): + """Main function of the downloader.""" + tasks = [] + client = pyrogram.Client( + "media_downloader", + api_id=app.api_id, + api_hash=app.api_hash, + proxy=app.proxy, + workdir=app.session_file_path, + ) + try: + app.pre_run() + init_web(app) + + set_max_concurrent_transmissions(client, app.max_concurrent_transmissions) + + client.start() + logger.success(_t("Successfully started (Press Ctrl+C to stop)")) + + app.loop.create_task(download_all_chat(client)) + for _ in range(app.max_download_task): + task = app.loop.create_task(worker(client)) + tasks.append(task) + + if app.bot_token: + app.loop.create_task( + start_download_bot(app, client, add_download_task, download_chat_task) + ) + _exec_loop() + except KeyboardInterrupt: + logger.info(_t("KeyboardInterrupt")) + except Exception as e: + logger.exception("{}", e) + finally: + client.stop() + app.is_running = False + for task in tasks: + task.cancel() + logger.info(_t("Stopped!")) + check_for_updates() + logger.info(f"{_t('update config')}......") + app.update_config() + if app.bot_token: + stop_download_bot() + logger.success( + f"{_t('Updated last read message_id to config file')}," + f"{_t('total download')} {app.total_download_task}, " + f"{_t('total upload file')} " + f"{app.cloud_drive_config.total_upload_success_file_count}" + ) + + +if __name__ == "__main__": + if _check_config(): + main() diff --git a/src/parsers/Telegram/telegram_media_downloader/media_downloader.spec b/src/parsers/Telegram/telegram_media_downloader/media_downloader.spec new file mode 100644 index 0000000..d49b744 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/media_downloader.spec @@ -0,0 +1,50 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['media_downloader.py'], + pathex=[], + binaries=[], + datas=[('./module/templates','./module/templates'),('./module/static/','./module/static'), ('./module/parsetab.py','./module/'),('./module/parser.out','./module/'),('./config.yaml','./'),('./data.yaml','./')], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='tdl', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) +coll = COLLECT( + exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='tdl', +) diff --git a/src/parsers/Telegram/telegram_media_downloader/module/__init__.py b/src/parsers/Telegram/telegram_media_downloader/module/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/parsers/Telegram/telegram_media_downloader/module/app.py b/src/parsers/Telegram/telegram_media_downloader/module/app.py new file mode 100644 index 0000000..a864a18 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/app.py @@ -0,0 +1,730 @@ +"""Application module""" + +import asyncio +import os +import time +from concurrent.futures import ThreadPoolExecutor +from enum import Enum +from typing import List, Optional, Union + +import loguru +from ruamel import yaml + +from module.cloud_drive import CloudDrive, CloudDriveConfig +from module.filter import Filter +from module.language import Language, set_language +from utils.format import replace_date_time, validate_title +from utils.meta_data import MetaData + +_yaml = yaml.YAML() +# pylint: disable = R0902 + + +class DownloadStatus(Enum): + """Download status""" + + SkipDownload = 1 + SuccessDownload = 2 + FailedDownload = 3 + Downloading = 4 + + +class ForwardStatus(Enum): + """Forward status""" + + SkipForward = 1 + SuccessForward = 2 + FailedForward = 3 + Forwarding = 4 + + +class TaskType(Enum): + """Task Type""" + + Download = 1 + Forward = 2 + ListenForward = 3 + + +class TaskNode: + """Task node""" + + # pylint: disable = R0913 + def __init__( + self, + chat_id: Union[int, str], + from_user_id: Union[int, str] = None, + reply_message_id: int = 0, + replay_message: str = None, + upload_telegram_chat_id: Union[int, str] = None, + has_protected_content: bool = False, + download_filter: str = "", + limit: int = 0, + bot=None, + task_type: TaskType = TaskType.Download, + task_id: int = 0, + ): + self.chat_id = chat_id + self.from_user_id = from_user_id + self.upload_telegram_chat_id = upload_telegram_chat_id + self.reply_message_id = reply_message_id + self.reply_message = replay_message + self.has_protected_content = has_protected_content + self.download_filter = download_filter + self.limit = limit + self.bot = bot + self.task_id = task_id + self.task_type = task_type + self.total_task = 0 + self.total_download_task = 0 + self.failed_download_task = 0 + self.success_download_task = 0 + self.skip_download_task = 0 + self.last_reply_time = time.time() + self.last_edit_msg: str = "" + self.total_download_byte = 0 + self.forward_msg_detail_str: str = "" + self.upload_user = None + self.total_forward_task: int = 0 + self.success_forward_task: int = 0 + self.failed_forward_task: int = 0 + self.skip_forward_task: int = 0 + self.is_running: bool = False + self.client = None + self.upload_success_count: int = 0 + + def is_finish(self): + """If is finish""" + return ( + self.task_type != TaskType.ListenForward + and self.total_task == self.total_download_task + ) + + def stat(self, status: DownloadStatus): + """ + Updates the download status of the task. + + Args: + status (DownloadStatus): The status of the download task. + + Returns: + None + """ + self.total_download_task += 1 + if status is DownloadStatus.SuccessDownload: + self.success_download_task += 1 + elif status is DownloadStatus.SkipDownload: + self.skip_download_task += 1 + else: + self.failed_download_task += 1 + + def stat_forward(self, status: ForwardStatus): + """Stat upload""" + self.total_forward_task += 1 + if status is ForwardStatus.SuccessForward: + self.success_forward_task += 1 + elif status is ForwardStatus.SkipForward: + self.skip_forward_task += 1 + else: + self.failed_forward_task += 1 + + def can_reply(self): + """ + Checks if the bot can reply to a message + based on the time elapsed since the last reply. + + Returns: + True if the time elapsed since + the last reply is greater than 1 second, False otherwise. + """ + cur_time = time.time() + if cur_time - self.last_reply_time > 1.0: + self.last_reply_time = cur_time + return True + + return False + + +class ChatDownloadConfig: + """Chat Message Download Status""" + + def __init__(self): + self.downloaded_ids: list = [] + self.failed_ids: list = [] + self.ids_to_retry_dict: dict = {} + + # need storage + self.download_filter: str = None + self.ids_to_retry: list = [] + self.last_read_message_id = 0 + self.total_task: int = 0 + self.finish_task: int = 0 + self.need_check: bool = False + self.upload_telegram_chat_id: Union[int, str] = None + + +class Application: + """Application load config and update config.""" + + def __init__( + self, + config_file: str, + app_data_file: str, + application_name: str = "UndefineApp", + ): + """ + Init and update telegram media downloader config + + Parameters + ---------- + config_file: str + Config file name + + app_data_file: str + App data file + + application_name: str + Application Name + + """ + self.config_file: str = config_file + self.app_data_file: str = app_data_file + self.application_name: str = application_name + self.download_filter = Filter() + self.is_running = True + + self.total_download_task = 0 + + self.chat_download_config: dict = {} + + self.disable_syslog: list = [] + self.save_path = os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader", "downloads") + self.temp_save_path = os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader", "temp") + self.api_id: str = "" + self.api_hash: str = "" + self.bot_token: str = "" + self._chat_id: str = "" + self.media_types: List[str] = [] + self.file_formats: dict = {} + self.proxy: dict = {} + self.restart_program = False + self.config: dict = {} + self.app_data: dict = {} + self.file_path_prefix: List[str] = ["chat_title", "media_datetime"] + self.file_name_prefix: List[str] = ["message_id", "file_name"] + self.file_name_prefix_split: str = " - " + self.log_file_path = os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader", "log") + self.session_file_path = os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader", "sessions") + self.cloud_drive_config = CloudDriveConfig() + self.hide_file_name = False + self.caption_name_dict: dict = {} + self.max_concurrent_transmissions: int = 1 + self.web_host: str = "0.0.0.0" + self.web_port: int = 5000 + self.max_download_task: int = 5 + self.language = Language.EN + self.after_upload_telegram_delete: bool = True + self.web_login_secret: str = "" + self.debug_web: bool = False + + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + self.executor = ThreadPoolExecutor( + min(32, (os.cpu_count() or 0) + 4), thread_name_prefix="multi_task" + ) + + # pylint: disable = R0915 + def assign_config(self, _config: dict) -> bool: + """assign config from str. + + Parameters + ---------- + _config: dict + application config dict + + Returns + ------- + bool + """ + # pylint: disable = R0912 + # TODO: judge the storage if enough,and provide more path + if _config.get("save_path") is not None: + self.save_path = _config["save_path"] + + if _config.get("disable_syslog") is not None: + self.disable_syslog = _config["disable_syslog"] + + self.api_id = _config["api_id"] + self.api_hash = _config["api_hash"] + self.bot_token = _config.get("bot_token", "") + + self.media_types = _config["media_types"] + self.file_formats = _config["file_formats"] + + self.hide_file_name = _config.get("hide_file_name", False) + + # option + if _config.get("proxy"): + self.proxy = _config["proxy"] + if _config.get("restart_program"): + self.restart_program = _config["restart_program"] + if _config.get("file_path_prefix"): + self.file_path_prefix = _config["file_path_prefix"] + if _config.get("file_name_prefix"): + self.file_name_prefix = _config["file_name_prefix"] + + if _config.get("upload_drive"): + upload_drive_config = _config["upload_drive"] + if upload_drive_config.get("enable_upload_file"): + self.cloud_drive_config.enable_upload_file = upload_drive_config[ + "enable_upload_file" + ] + + if upload_drive_config.get("rclone_path"): + self.cloud_drive_config.rclone_path = upload_drive_config["rclone_path"] + + if upload_drive_config.get("remote_dir"): + self.cloud_drive_config.remote_dir = upload_drive_config["remote_dir"] + + if upload_drive_config.get("before_upload_file_zip"): + self.cloud_drive_config.before_upload_file_zip = upload_drive_config[ + "before_upload_file_zip" + ] + + if upload_drive_config.get("after_upload_file_delete"): + self.cloud_drive_config.after_upload_file_delete = upload_drive_config[ + "after_upload_file_delete" + ] + + if upload_drive_config.get("upload_adapter"): + self.cloud_drive_config.upload_adapter = upload_drive_config[ + "upload_adapter" + ] + + self.file_name_prefix_split = _config.get( + "file_name_prefix_split", self.file_name_prefix_split + ) + self.web_host = _config.get("web_host", self.web_host) + self.web_port = _config.get("web_port", self.web_port) + + # TODO: add check if expression exist syntax error + + self.max_concurrent_transmissions = _config.get( + "max_concurrent_transmissions", self.max_concurrent_transmissions + ) + + self.max_download_task = _config.get( + "max_download_task", self.max_download_task + ) + + language = _config.get("language", "EN") + + try: + self.language = Language[language.upper()] + except KeyError: + pass + + self.after_upload_telegram_delete = _config.get( + "after_upload_telegram_delete", self.after_upload_telegram_delete + ) + + self.web_login_secret = str( + _config.get("web_login_secret", self.web_login_secret) + ) + self.debug_web = _config.get("debug_web", self.debug_web) + + if _config.get("chat"): + chat = _config["chat"] + for item in chat: + if "chat_id" in item: + self.chat_download_config[item["chat_id"]] = ChatDownloadConfig() + self.chat_download_config[ + item["chat_id"] + ].last_read_message_id = item.get("last_read_message_id", 0) + self.chat_download_config[ + item["chat_id"] + ].download_filter = item.get("download_filter", "") + self.chat_download_config[ + item["chat_id"] + ].upload_telegram_chat_id = item.get( + "upload_telegram_chat_id", None + ) + elif _config.get("chat_id"): + # Compatible with lower versions + self._chat_id = _config["chat_id"] + + self.chat_download_config[self._chat_id] = ChatDownloadConfig() + + if _config.get("ids_to_retry"): + self.chat_download_config[self._chat_id].ids_to_retry = _config[ + "ids_to_retry" + ] + for it in self.chat_download_config[self._chat_id].ids_to_retry: + self.chat_download_config[self._chat_id].ids_to_retry_dict[ + it + ] = True + + self.chat_download_config[self._chat_id].last_read_message_id = _config[ + "last_read_message_id" + ] + download_filter_dict = _config.get("download_filter", None) + + self.config["chat"] = [ + { + "chat_id": self._chat_id, + "last_read_message_id": self.chat_download_config[ + self._chat_id + ].last_read_message_id, + } + ] + + if download_filter_dict and self._chat_id in download_filter_dict: + self.chat_download_config[ + self._chat_id + ].download_filter = download_filter_dict[self._chat_id] + self.config["chat"][0]["download_filter"] = download_filter_dict[ + self._chat_id + ] + + # pylint: disable = R1733 + for key, value in self.chat_download_config.items(): + self.chat_download_config[key].download_filter = replace_date_time( + value.download_filter + ) + + return True + + def assign_app_data(self, app_data: dict) -> bool: + """Assign config from str. + + Parameters + ---------- + app_data: dict + application data dict + + Returns + ------- + bool + """ + if app_data.get("ids_to_retry"): + if self._chat_id: + self.chat_download_config[self._chat_id].ids_to_retry = app_data[ + "ids_to_retry" + ] + for it in self.chat_download_config[self._chat_id].ids_to_retry: + self.chat_download_config[self._chat_id].ids_to_retry_dict[ + it + ] = True + self.app_data.pop("ids_to_retry") + else: + if app_data.get("chat"): + chats = app_data["chat"] + for chat in chats: + if ( + "chat_id" in chat + and chat["chat_id"] in self.chat_download_config + ): + chat_id = chat["chat_id"] + self.chat_download_config[chat_id].ids_to_retry = chat.get( + "ids_to_retry", [] + ) + for it in self.chat_download_config[chat_id].ids_to_retry: + self.chat_download_config[chat_id].ids_to_retry_dict[ + it + ] = True + return True + + async def upload_file(self, local_file_path: str) -> bool: + """Upload file""" + + if not self.cloud_drive_config.enable_upload_file: + return False + + ret: bool = False + if self.cloud_drive_config.upload_adapter == "rclone": + ret = await CloudDrive.rclone_upload_file( + self.cloud_drive_config, self.save_path, local_file_path + ) + elif self.cloud_drive_config.upload_adapter == "aligo": + ret = await self.loop.run_in_executor( + self.executor, + CloudDrive.aligo_upload_file( + self.cloud_drive_config, self.save_path, local_file_path + ), + ) + + return ret + + def get_file_save_path( + self, media_type: str, chat_title: str, media_datetime: str + ) -> str: + """Get file save path prefix. + + Parameters + ---------- + media_type: str + see config.yaml media_types + + chat_title: str + see channel or group title + + media_datetime: str + media datetime + + Returns + ------- + str + file save path prefix + """ + + res: str = self.save_path + for prefix in self.file_path_prefix: + if prefix == "chat_title": + res = os.path.join(res, chat_title) + elif prefix == "media_datetime": + res = os.path.join(res, media_datetime) + elif prefix == "media_type": + res = os.path.join(res, media_type) + return res + + def get_file_name( + self, message_id: int, file_name: Optional[str], caption: Optional[str] + ) -> str: + """Get file save path prefix. + + Parameters + ---------- + message_id: int + Message id + + file_name: Optional[str] + File name + + caption: Optional[str] + Message caption + + Returns + ------- + str + File name + """ + + res: str = "" + for prefix in self.file_name_prefix: + if prefix == "message_id": + if res != "": + res += self.file_name_prefix_split + res += f"{message_id}" + elif prefix == "file_name" and file_name: + if res != "": + res += self.file_name_prefix_split + res += f"{file_name}" + elif prefix == "caption" and caption: + if res != "": + res += self.file_name_prefix_split + res += f"{caption}" + if res == "": + res = f"{message_id}" + + return validate_title(res) + + def need_skip_message( + self, download_config: ChatDownloadConfig, message_id: int, meta_data: MetaData + ) -> bool: + """if need skip download message. + + Parameters + ---------- + chat_id: str + Config.yaml defined + + message_id: int + Readily to download message id + + meta_data: MetaData + Ready to match filter + + Returns + ------- + bool + """ + if message_id in download_config.ids_to_retry_dict: + return True + + if download_config.download_filter: + self.download_filter.set_meta_data(meta_data) + exec_res = not self.download_filter.exec(download_config.download_filter) + return exec_res + + return False + + def update_config(self, immediate: bool = True): + """update config + + Parameters + ---------- + immediate: bool + If update config immediate,default True + """ + # TODO: fix this not exist chat + if not self.app_data.get("chat") and self.config.get("chat"): + self.app_data["chat"] = [ + {"chat_id": i} for i in range(0, len(self.config["chat"])) + ] + idx = 0 + # pylint: disable = R1733 + for key, value in self.chat_download_config.items(): + # pylint: disable = W0201 + before_last_read_message_id = self.config["chat"][idx].get( + "last_read_message_id", 0 + ) + + unfinished_ids = set(value.ids_to_retry) + if before_last_read_message_id != value.last_read_message_id: + unfinished_ids = unfinished_ids | set( + range(before_last_read_message_id, value.last_read_message_id + 1) + ) + unfinished_ids -= set(value.downloaded_ids) + unfinished_ids -= set({0}) + + self.chat_download_config[key].ids_to_retry = list(unfinished_ids) + + if idx >= len(self.app_data["chat"]): + self.app_data["chat"].append({}) + + if value.finish_task: + self.config["chat"][idx]["last_read_message_id"] = ( + value.last_read_message_id + 1 + ) + + self.app_data["chat"][idx]["chat_id"] = key + self.app_data["chat"][idx]["ids_to_retry"] = value.ids_to_retry + idx += 1 + + self.config["disable_syslog"] = self.disable_syslog + self.config["save_path"] = self.save_path + self.config["file_path_prefix"] = self.file_path_prefix + + if self.config.get("ids_to_retry"): + self.config.pop("ids_to_retry") + + if self.config.get("chat_id"): + self.config.pop("chat_id") + + if self.config.get("download_filter"): + self.config.pop("download_filter") + + if self.config.get("last_read_message_id"): + self.config.pop("last_read_message_id") + + self.config["language"] = self.language.name + # for it in self.downloaded_ids: + # self.already_download_ids_set.add(it) + + # self.app_data["already_download_ids"] = list(self.already_download_ids_set) + + if immediate: + with open(self.config_file, "w", encoding="utf-8") as yaml_file: + _yaml.dump(self.config, yaml_file) + + if immediate: + with open(self.app_data_file, "w", encoding="utf-8") as yaml_file: + _yaml.dump(self.app_data, yaml_file) + + def set_language(self, language: Language): + """Set Language""" + self.language = language + set_language(language) + + def load_config(self): + """Load user config""" + loguru.logger.info(os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader", self.config_file)) + with open( + os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader", self.config_file), encoding="utf-8" + ) as f: + config = _yaml.load(f.read()) + if config: + self.config = config + self.assign_config(self.config) + + if os.path.exists(os.path.join(os.path.abspath(""), self.app_data_file)): + with open( + os.path.join(os.path.abspath(""), self.app_data_file), + encoding="utf-8", + ) as f: + app_data = _yaml.load(f.read()) + if app_data: + self.app_data = app_data + self.assign_app_data(self.app_data) + + def pre_run(self): + """before run application do""" + self.cloud_drive_config.pre_run() + if not os.path.exists(self.session_file_path): + os.makedirs(self.session_file_path) + set_language(self.language) + + def set_caption_name( + self, chat_id: Union[int, str], media_group_id: Optional[str], caption: str + ): + """set caption name map + + Parameters + ---------- + chat_id: str + Unique identifier for this chat. + + media_group_id: Optional[str] + The unique identifier of a media message group this message belongs to. + + caption: str + Caption for the audio, document, photo, video or voice, 0-1024 characters. + """ + if not media_group_id: + return + + if chat_id in self.caption_name_dict: + self.caption_name_dict[chat_id][media_group_id] = caption + else: + self.caption_name_dict[chat_id] = {media_group_id: caption} + + def get_caption_name( + self, chat_id: Union[int, str], media_group_id: Optional[str] + ) -> Optional[str]: + """set caption name map + media_group_id: Optional[str] + The unique identifier of a media message group this message belongs to. + + caption: str + Caption for the audio, document, photo, video or voice, 0-1024 characters. + """ + + if ( + not media_group_id + or chat_id not in self.caption_name_dict + or media_group_id not in self.caption_name_dict[chat_id] + ): + return None + + return str(self.caption_name_dict[chat_id][media_group_id]) + + def set_download_id( + self, chat_id: Union[int, str], message_id: int, download_status: DownloadStatus + ): + """Set Download status""" + if download_status is DownloadStatus.SuccessDownload: + self.total_download_task += 1 + + if chat_id not in self.chat_download_config: + return + + self.chat_download_config[chat_id].finish_task += 1 + + self.chat_download_config[chat_id].last_read_message_id = max( + self.chat_download_config[chat_id].last_read_message_id, message_id + ) + if download_status is not DownloadStatus.FailedDownload: + self.chat_download_config[chat_id].downloaded_ids.append(message_id) + else: + self.chat_download_config[chat_id].failed_ids.append(message_id) diff --git a/src/parsers/Telegram/telegram_media_downloader/module/bot.py b/src/parsers/Telegram/telegram_media_downloader/module/bot.py new file mode 100644 index 0000000..da68be7 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/bot.py @@ -0,0 +1,929 @@ +"""Bot for media downloader""" + +import asyncio +import os +from datetime import datetime +from typing import Callable, List, Union + +import pyrogram +from loguru import logger +from pyrogram import types +from pyrogram.handlers import MessageHandler +from ruamel import yaml + +import utils +from module.app import ( + Application, + ChatDownloadConfig, + ForwardStatus, + TaskNode, + TaskType, +) +from module.filter import Filter +from module.language import Language, _t +from module.pyrogram_extension import ( + check_user_permission, + get_message_with_retry, + report_bot_forward_status, + report_bot_status, + set_meta_data, +) +from utils.format import extract_info_from_link, replace_date_time, validate_title +from utils.meta_data import MetaData + +# from pyrogram.types import (ReplyKeyboardMarkup, InlineKeyboardMarkup, +# InlineKeyboardButton) + +# pylint: disable = C0301, R0902 + + +class DownloadBot: + """Download bot""" + + def __init__(self): + self.bot = None + self.client = None + self.add_download_task: Callable = None + self.download_chat_task: Callable = None + self.app = None + self.listen_forward_chat: dict = {} + self.config: dict = {} + self._yaml = yaml.YAML() + self.config_path = os.path.join(os.path.abspath(""), "bot.yaml") + self.download_command: dict = {} + self.filter = Filter() + self.bot_info = None + self.task_node: dict = {} + self.is_running = True + + meta = MetaData(datetime(2022, 8, 5, 14, 35, 12), 0, "", 0, 0, 0, "", 0) + self.filter.set_meta_data(meta) + + self.download_filter: List[str] = [] + self.task_id: int = 0 + + def gen_task_id(self) -> int: + """Gen task id""" + self.task_id += 1 + return self.task_id + + def add_task_node(self, node: TaskNode): + """Add task node""" + self.task_node[node.task_id] = node + + def remove_task_node(self, task_id: int): + """Remove task node""" + self.task_node.pop(task_id) + + async def update_reply_message(self): + """Update reply message""" + while self.is_running: + for key, value in self.task_node.copy().items(): + if value.is_running: + await report_bot_status(self.bot, value) + + for key, value in self.task_node.copy().items(): + if value.is_running and value.is_finish(): + self.task_node.pop(key) + await asyncio.sleep(3) + + def assign_config(self, _config: dict): + """assign config from str. + + Parameters + ---------- + _config: dict + application config dict + + Returns + ------- + bool + """ + + self.download_filter = _config.get("download_filter", self.download_filter) + + return True + + def update_config(self): + """Update config from str.""" + self.config["download_filter"] = self.download_filter + + with open("d", "w", encoding="utf-8") as yaml_file: + self._yaml.dump(self.config, yaml_file) + + async def start( + self, + app: Application, + client: pyrogram.Client, + add_download_task: Callable, + download_chat_task: Callable, + ): + """Start bot""" + self.bot = pyrogram.Client( + app.application_name + "_bot", + api_hash=app.api_hash, + api_id=app.api_id, + bot_token=app.bot_token, + workdir=app.session_file_path, + proxy=app.proxy, + ) + + # 命令列表 + commands = [ + types.BotCommand("help", _t("Help")), + types.BotCommand( + "get_info", _t("Get group and user info from message link") + ), + types.BotCommand( + "download", + _t( + "To download the video, use the method to directly enter /download to view" + ), + ), + types.BotCommand( + "forward", + _t("Forward video, use the method to directly enter /forward to view"), + ), + types.BotCommand( + "listen_forward", + _t( + "Listen forward, use the method to directly enter /listen_forward to view" + ), + ), + types.BotCommand( + "add_filter", + _t( + "Add download filter, use the method to directly enter /add_filter to view" + ), + ), + types.BotCommand("set_language", _t("Set language")), + ] + + self.bot.add_handler( + MessageHandler( + download_from_bot, filters=pyrogram.filters.command(["download"]) + ) + ) + self.bot.add_handler( + MessageHandler( + forward_messages, filters=pyrogram.filters.command(["forward"]) + ) + ) + self.bot.add_handler( + MessageHandler(download_forward_media, filters=pyrogram.filters.media) + ) + self.bot.add_handler( + MessageHandler( + download_from_link, filters=pyrogram.filters.regex(r"^https://t.me.*") + ) + ) + self.bot.add_handler( + MessageHandler( + set_listen_forward_msg, + filters=pyrogram.filters.command(["listen_forward"]), + ) + ) + self.bot.add_handler( + MessageHandler(help_command, filters=pyrogram.filters.command(["help"])) + ) + self.bot.add_handler( + MessageHandler(get_info, filters=pyrogram.filters.command(["get_info"])) + ) + self.bot.add_handler( + MessageHandler(help_command, filters=pyrogram.filters.command(["start"])) + ) + self.bot.add_handler( + MessageHandler( + set_language, filters=pyrogram.filters.command(["set_language"]) + ) + ) + self.bot.add_handler( + MessageHandler(add_filter, filters=pyrogram.filters.command(["add_filter"])) + ) + self.client = client + + self.client.add_handler(MessageHandler(listen_forward_msg)) + + self.add_download_task = add_download_task + self.download_chat_task = download_chat_task + + self.app = app + + # load config + if os.path.exists(self.config_path): + with open(self.config_path, encoding="utf-8") as f: + config = self._yaml.load(f.read()) + if config: + self.config = config + self.assign_config(self.config) + + await self.bot.start() + + self.bot_info = self.bot.get_me() + + # 添加命令列表 + await self.bot.set_bot_commands(commands) + + admin = await self.client.get_me() + + try: + await send_help_str(self.bot, admin.id) + except Exception: + pass + # TODO: add admin + # self.bot.set_my_commands(commands, scope=types.BotCommandScopeChatAdministrators(self.app.)) + + _bot.app.loop.create_task(_bot.update_reply_message()) + + +_bot = DownloadBot() + + +async def start_download_bot( + app: Application, + client: pyrogram.Client, + add_download_task: Callable, + download_chat_task: Callable, +): + """Start download bot""" + await _bot.start(app, client, add_download_task, download_chat_task) + + +def stop_download_bot(): + """Stop download bot""" + _bot.update_config() + _bot.is_running = False + + +async def send_help_str(client: pyrogram.Client, chat_id): + """ + Sends a help string to the specified chat ID using the provided client. + + Parameters: + client (pyrogram.Client): The Pyrogram client used to send the message. + chat_id: The ID of the chat to which the message will be sent. + + Returns: + str: The help string that was sent. + + Note: + The help string includes information about the Telegram Media Downloader bot, + its version, and the available commands. + """ + msg = ( + f"```\n🤖 {_t('Telegram Media Downloader')}\n" + f"🌐 {_t('Version')}: {utils.__version__}```\n\n" + f"{_t('Available commands:')}\n" + f"/help - {_t('Show available commands')}\n" + f"/get_info - {_t('Get group and user info from message link')}\n" + # f"/add_filter - {_t('Add download filter')}\n" + f"/download - {_t('Download messages')}\n" + f"/forward - {_t('Forward messages')}\n" + f"/listen_forward - {_t('Listen for forwarded messages')}\n" + f"/set_language - {_t('Set language')}\n\n" + f"{_t('**Note**: 1 means the start of the entire chat')}," + f"{_t('0 means the end of the entire chat')}\n" + f"`[` `]` {_t('means optional, not required')}\n" + ) + + await client.send_message(chat_id, msg) + + +async def help_command(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Sends a message with the available commands and their usage. + + Parameters: + client (pyrogram.Client): The client instance. + message (pyrogram.types.Message): The message object. + + Returns: + None + """ + + await send_help_str(client, message.chat.id) + + +async def set_language(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Set the language of the bot. + + Parameters: + client (pyrogram.Client): The pyrogram client. + message (pyrogram.types.Message): The message containing the command. + + Returns: + None + """ + + if len(message.text.split()) != 2: + await client.send_message( + message.from_user.id, + _t("Invalid command format. Please use /set_language en/ru/zh/ua"), + ) + return + + language = message.text.split()[1] + + try: + language = Language[language.upper()] + _bot.app.set_language(language) + await client.send_message( + message.from_user.id, f"{_t('Language set to')} {language.name}" + ) + except KeyError: + await client.send_message( + message.from_user.id, + _t("Invalid command format. Please use /set_language en/ru/zh/ua"), + ) + + +async def get_info(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Async function that retrieves information from a group message link. + """ + + msg = _t("Invalid command format. Please use /get_info group_message_link") + + args = message.text.split() + if len(args) != 2: + await client.send_message( + message.from_user.id, + msg, + ) + return + + chat_id, message_id = extract_info_from_link(args[1]) + + entity = None + if chat_id: + entity = await _bot.client.get_chat(chat_id) + + if entity: + if message_id: + _message = await get_message_with_retry(_bot.client, chat_id, message_id) + if _message: + meta_data = MetaData() + set_meta_data(meta_data, _message) + msg = ( + f"```\n" + f"{_t('Group/Channel')}\n" + f"├─ {_t('id')}: {entity.id}\n" + f"├─ {_t('first name')}: {entity.first_name}\n" + f"├─ {_t('last name')}: {entity.last_name}\n" + f"└─ {_t('name')}: {entity.username}\n" + f"{_t('Message')}\n" + ) + + for key, value in meta_data.data().items(): + if key == "send_name": + msg += f"└─ {key}: {value or None}\n" + else: + msg += f"├─ {key}: {value or None}\n" + + msg += "```" + await client.send_message( + message.from_user.id, + msg, + ) + + +async def add_filter(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Set the download filter of the bot. + + Parameters: + client (pyrogram.Client): The pyrogram client. + message (pyrogram.types.Message): The message containing the command. + + Returns: + None + """ + + args = message.text.split(maxsplit=1) + if len(args) != 2: + await client.send_message( + message.from_user.id, + _t("Invalid command format. Please use /add_filter your filter"), + ) + return + + filter_str = replace_date_time(args[1]) + res, err = _bot.filter.check_filter(filter_str) + if res: + _bot.app.down = args[1] + await client.send_message( + message.from_user.id, f"{_t('Add download filter')} : {args[1]}" + ) + else: + await client.send_message( + message.from_user.id, f"{err}\n{_t('Check error, please add again!')}" + ) + return + + +async def direct_download( + download_bot: DownloadBot, + chat_id: Union[str, int], + message: pyrogram.types.Message, + download_message: pyrogram.types.Message, + client: pyrogram.Client = None, +): + """Direct Download""" + + replay_message = "Direct download..." + last_reply_message = await download_bot.bot.send_message( + message.from_user.id, replay_message, reply_to_message_id=message.id + ) + + node = TaskNode( + chat_id=chat_id, + from_user_id=message.from_user.id, + reply_message_id=last_reply_message.id, + replay_message=replay_message, + limit=1, + bot=download_bot.bot, + task_id=_bot.gen_task_id(), + ) + + node.client = client + + _bot.add_task_node(node) + + await _bot.add_download_task( + download_message, + node, + ) + + node.is_running = True + + +async def download_forward_media( + client: pyrogram.Client, message: pyrogram.types.Message +): + """ + Downloads the media from a forwarded message. + + Parameters: + client (pyrogram.Client): The client instance. + message (pyrogram.types.Message): The message object. + + Returns: + None + """ + + if message.media and getattr(message, message.media.value): + await direct_download(_bot, message.from_user.id, message, message, client) + return + + await client.send_message( + message.from_user.id, + f"1. {_t('Direct download, directly forward the message to your robot')}\n\n", + parse_mode=pyrogram.enums.ParseMode.HTML, + ) + + +async def download_from_link(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Downloads a single message from a Telegram link. + + Parameters: + client (pyrogram.Client): The pyrogram client. + message (pyrogram.types.Message): The message containing the Telegram link. + + Returns: + None + """ + + if not message.text or not message.text.startswith("https://t.me"): + return + + msg = ( + f"1. {_t('Directly download a single message')}\n" + "https://t.me/12000000/1\n\n" + ) + + text = message.text.split() + if len(text) != 1: + await client.send_message( + message.from_user.id, msg, parse_mode=pyrogram.enums.ParseMode.HTML + ) + + chat_id, message_id = extract_info_from_link(text[0]) + + entity = None + if chat_id: + entity = await _bot.client.get_chat(chat_id) + if entity: + if message_id: + download_message = await get_message_with_retry( + _bot.client, chat_id, message_id + ) + if download_message: + await direct_download(_bot, entity.id, message, download_message) + else: + client.send_message( + message.from_user.id, + f"{_t('From')} {entity.title} {_t('download')} {message_id} {_t('error')}!", + reply_to_message_id=message.id, + ) + return + + await client.send_message( + message.from_user.id, msg, parse_mode=pyrogram.enums.ParseMode.HTML + ) + + +# pylint: disable = R0912, R0915,R0914 + + +async def download_from_bot(client: pyrogram.Client, message: pyrogram.types.Message): + """Download from bot""" + + msg = ( + f"{_t('Parameter error, please enter according to the reference format')}:\n\n" + f"1. {_t('Download all messages of common group')}\n" + "/download https://t.me/fkdhlg 1 0\n\n" + f"{_t('The private group (channel) link is a random group message link')}\n\n" + f"2. {_t('The download starts from the N message to the end of the M message')}. " + f"{_t('When M is 0, it means the last message. The filter is optional')}\n" + f"/download https://t.me/12000000 N M [filter]\n\n" + ) + + args = message.text.split(maxsplit=4) + if not message.text or len(args) < 4: + await client.send_message( + message.from_user.id, msg, parse_mode=pyrogram.enums.ParseMode.HTML + ) + return + + url = args[1] + try: + offset_id = int(args[2]) + limit = int(args[3]) + except Exception: + await client.send_message( + message.from_user.id, msg, parse_mode=pyrogram.enums.ParseMode.HTML + ) + return + + if limit: + if limit < offset_id: + raise ValueError("M > N") + + limit = limit - offset_id + 1 + + download_filter = args[4] if len(args) > 4 else None + + if download_filter: + download_filter = replace_date_time(download_filter) + res, err = _bot.filter.check_filter(download_filter) + if not res: + await client.send_message( + message.from_user.id, err, reply_to_message_id=message.id + ) + return + try: + chat_id, _ = extract_info_from_link(url) + if chat_id: + entity = await _bot.client.get_chat(chat_id) + if entity: + chat_title = entity.title + reply_message = f"from {chat_title} " + chat_download_config = ChatDownloadConfig() + chat_download_config.last_read_message_id = offset_id + chat_download_config.download_filter = download_filter + reply_message += f"download message id = {offset_id} limit = {limit} !" + last_reply_message = await client.send_message( + message.from_user.id, reply_message, reply_to_message_id=message.id + ) + node = TaskNode( + chat_id=entity.id, + from_user_id=message.from_user.id, + reply_message_id=last_reply_message.id, + replay_message=reply_message, + limit=limit, + bot=_bot.bot, + task_id=_bot.gen_task_id(), + ) + _bot.add_task_node(node) + await _bot.download_chat_task(_bot.client, chat_download_config, node) + except Exception as e: + await client.send_message( + message.from_user.id, + f"{_t('chat input error, please enter the channel or group link')}\n\n" + f"{_t('Error type')}: {e.__class__}" + f"{_t('Exception message')}: {e}", + ) + return + + +async def get_forward_task_node( + client: pyrogram.Client, + message: pyrogram.types.Message, + src_chat_link: str, + dst_chat_link: str, + offset_id: int, + limit: int, + download_filter: str, + task_type: TaskType, +): + """Get task node""" + + if limit: + if limit < offset_id: + await client.send_message( + message.from_user.id, + f"{limit} > {offset_id}", + ) + return None + + limit = limit - offset_id + 1 + + src_chat_id, _ = extract_info_from_link(src_chat_link) + dst_chat_id, _ = extract_info_from_link(dst_chat_link) + + if not src_chat_id or not dst_chat_id: + await client.send_message( + message.from_user.id, + _t("Invalid chat link"), + reply_to_message_id=message.id, + ) + return None + + try: + src_chat = await _bot.client.get_chat(src_chat_id) + dst_chat = await _bot.client.get_chat(dst_chat_id) + except Exception: + await client.send_message( + message.from_user.id, + _t("Invalid chat link"), + reply_to_message_id=message.id, + ) + return None + + me = await client.get_me() + if dst_chat.id == me.id: + # TODO: when bot receive message judge if download + await client.send_message( + message.from_user.id, + _t("Cannot be forwarded to this bot, will cause an infinite loop"), + reply_to_message_id=message.id, + ) + return None + + if download_filter: + download_filter = replace_date_time(download_filter) + res, err = _bot.filter.check_filter(download_filter) + if not res: + await client.send_message( + message.from_user.id, err, reply_to_message_id=message.id + ) + + last_reply_message = await client.send_message( + message.from_user.id, + "Forwarding message, please wait...", + reply_to_message_id=message.id, + ) + + node = TaskNode( + chat_id=src_chat.id, + from_user_id=message.from_user.id, + upload_telegram_chat_id=dst_chat_id, + reply_message_id=last_reply_message.id, + replay_message=last_reply_message.text, + has_protected_content=src_chat.has_protected_content, + download_filter=download_filter, + limit=limit, + bot=_bot.bot, + task_id=_bot.gen_task_id(), + task_type=task_type, + ) + _bot.add_task_node(node) + + node.upload_user = _bot.client + if not dst_chat.type is pyrogram.enums.ChatType.BOT: + has_permission = await check_user_permission(_bot.client, me.id, dst_chat.id) + if has_permission: + node.upload_user = _bot.bot + + if node.upload_user is _bot.client: + await client.edit_message_text( + message.from_user.id, + last_reply_message.id, + "Note that the robot may not be in the target group," + " use the user account to forward", + ) + + return node + + +# pylint: disable = R0914 + + +async def forward_messages(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Forwards messages from one chat to another. + + Parameters: + client (pyrogram.Client): The pyrogram client. + message (pyrogram.types.Message): The message containing the command. + + Returns: + None + """ + + async def report_error(client: pyrogram.Client, message: pyrogram.types.Message): + """Report error""" + + await client.send_message( + message.from_user.id, + f"{_t('Invalid command format')}." + f"{_t('Please use')} " + "/forward https://t.me/c/src_chat https://t.me/c/dst_chat " + f"1 400 `[`{_t('Filter')}`]`\n", + ) + + args = message.text.split(maxsplit=5) + if len(args) < 5: + await report_error(client, message) + return + + src_chat_link = args[1] + dst_chat_link = args[2] + + try: + offset_id = int(args[3]) + limit = int(args[4]) + except Exception: + await report_error(client, message) + return + + download_filter = args[5] if len(args) > 5 else None + + node = await get_forward_task_node( + client, + message, + src_chat_link, + dst_chat_link, + offset_id, + limit, + download_filter, + TaskType.Forward, + ) + + if not node: + return + + if not node.has_protected_content: + last_read_message_id = offset_id + try: + async for item in _bot.client.get_chat_history( + node.chat_id, + limit=limit, + offset_id=offset_id, + reverse=True, + ): + if ( + await forward_normal_content(client, node, item) + is ForwardStatus.SuccessForward + ): + last_read_message_id = item.id + except Exception as e: + await client.edit_message_text( + message.from_user.id, + node.reply_message_id, + f"{_t('Error forwarding message')} {last_read_message_id}" + f" - {offset_id + limit} {e}", + ) + + await report_bot_status(client, node, immediate_reply=True) + else: + await forward_msg(node, offset_id) + + +async def forward_normal_content( + client: pyrogram.Client, node: TaskNode, message: pyrogram.types.Message +): + """Forward normal content""" + + forward_ret = ForwardStatus.FailedForward + if node.download_filter: + meta_data = MetaData() + caption = message.caption + if caption: + caption = validate_title(caption) + _bot.app.set_caption_name(node.chat_id, message.media_group_id, caption) + else: + caption = _bot.app.get_caption_name(node.chat_id, message.media_group_id) + set_meta_data(meta_data, message, caption) + if not _bot.filter.exec(node.download_filter): + forward_ret = ForwardStatus.SkipForward + await report_bot_forward_status(client, node, forward_ret) + return + + timeout_count = 0 + while timeout_count < 3: + timeout_count += 1 + try: + await _bot.client.forward_messages( + node.upload_telegram_chat_id, node.chat_id, message.id + ) + forward_ret = ForwardStatus.SuccessForward + break + except pyrogram.errors.exceptions.bad_request_400.MessageIdInvalid: + pass + except pyrogram.errors.exceptions.flood_420.FloodWait as wait_err: + logger.warning( + "bot task: forward message[{}]: FlowWait {}", message.id, wait_err.value + ) + await asyncio.sleep(wait_err.value) + except Exception as e: + logger.warning("bot task: forward message[{}]: exception {}", message.id, e) + break + + await report_bot_forward_status(client, node, forward_ret) + return forward_ret + + +async def forward_msg(node: TaskNode, message_id: int): + """Forward normal message""" + + chat_download_config = ChatDownloadConfig() + chat_download_config.last_read_message_id = message_id + chat_download_config.download_filter = node.download_filter + + await _bot.download_chat_task(_bot.client, chat_download_config, node) + + +async def set_listen_forward_msg( + client: pyrogram.Client, message: pyrogram.types.Message +): + """ + Set the chat to listen for forwarded messages. + + Args: + client (pyrogram.Client): The pyrogram client. + message (pyrogram.types.Message): The message sent by the user. + + Returns: + None + """ + args = message.text.split(maxsplit=3) + + if len(args) < 3: + await client.send_message( + message.from_user.id, + f"{_t('Invalid command format')}. {_t('Please use')} /listen_forward " + f"https://t.me/c/src_chat https://t.me/c/dst_chat [{_t('Filter')}]\n", + ) + return + + src_chat_link = args[1] + dst_chat_link = args[2] + + download_filter = args[3] if len(args) > 3 else None + + node = await get_forward_task_node( + client, + message, + src_chat_link, + dst_chat_link, + 0, + 1, + download_filter, + task_type=TaskType.ListenForward, + ) + + if not node: + return + + if node.chat_id in _bot.listen_forward_chat: + _bot.remove_task_node(_bot.listen_forward_chat[node.chat_id].task_id) + + node.is_running = True + _bot.listen_forward_chat[node.chat_id] = node + + +async def listen_forward_msg(client: pyrogram.Client, message: pyrogram.types.Message): + """ + Forwards messages from a chat to another chat if the message does not contain protected content. + If the message contains protected content, it will be downloaded and forwarded to the other chat. + + Parameters: + client (pyrogram.Client): The pyrogram client. + message (pyrogram.types.Message): The message to be forwarded. + """ + + if message.chat and message.chat.id in _bot.listen_forward_chat: + node = _bot.listen_forward_chat[message.chat.id] + + # TODO(tangyoha):fix run time change protected content + if not node.has_protected_content: + await forward_normal_content(client, node, message) + await report_bot_status(client, node, immediate_reply=True) + else: + await _bot.add_download_task( + message, + node, + ) diff --git a/src/parsers/Telegram/telegram_media_downloader/module/cloud_drive.py b/src/parsers/Telegram/telegram_media_downloader/module/cloud_drive.py new file mode 100644 index 0000000..c91926f --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/cloud_drive.py @@ -0,0 +1,229 @@ +"""provide upload cloud drive""" +import asyncio +import importlib +import os +from asyncio import subprocess +from subprocess import Popen +from zipfile import ZipFile + +from loguru import logger + +from utils import platform + + +# pylint: disable = R0902 +class CloudDriveConfig: + """Rclone Config""" + + def __init__( + self, + enable_upload_file: bool = False, + before_upload_file_zip: bool = False, + after_upload_file_delete: bool = True, + rclone_path: str = os.path.join( + os.path.abspath(""), "rclone", f"rclone{platform.get_exe_ext()}" + ), + remote_dir: str = "", + upload_adapter: str = "rclone", + ): + self.enable_upload_file = enable_upload_file + self.before_upload_file_zip = before_upload_file_zip + self.after_upload_file_delete = after_upload_file_delete + self.rclone_path = rclone_path + self.remote_dir = remote_dir + self.upload_adapter = upload_adapter + self.dir_cache: dict = {} # for remote mkdir + self.total_upload_success_file_count = 0 + self.aligo = None + + def pre_run(self): + """pre run init aligo""" + if self.enable_upload_file and self.upload_adapter == "aligo": + CloudDrive.init_upload_adapter(self) + + +class CloudDrive: + """rclone support""" + + @staticmethod + def init_upload_adapter(drive_config: CloudDriveConfig): + """Initialize the upload adapter.""" + if drive_config.upload_adapter == "aligo": + Aligo = importlib.import_module("aligo").Aligo + drive_config.aligo = Aligo() + + @staticmethod + def rclone_mkdir(drive_config: CloudDriveConfig, remote_dir: str): + """mkdir in remote""" + with Popen( + f'"{drive_config.rclone_path}" mkdir {remote_dir}/', + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ): + pass + + @staticmethod + def aligo_mkdir(drive_config: CloudDriveConfig, remote_dir: str): + """mkdir in remote by aligo""" + if drive_config.aligo and not drive_config.aligo.get_folder_by_path(remote_dir): + drive_config.aligo.create_folder(name=remote_dir, check_name_mode="refuse") + + @staticmethod + def zip_file(local_file_path: str) -> str: + """ + Zip local file + """ + + file_path_without_extension = os.path.splitext(local_file_path)[0] + zip_file_name = file_path_without_extension + ".zip" + + with ZipFile(zip_file_name, "w") as zip_writer: + zip_writer.write(local_file_path) + + return zip_file_name + + @staticmethod + async def rclone_upload_file( + drive_config: CloudDriveConfig, save_path: str, local_file_path: str + ) -> bool: + """Use Rclone upload file""" + upload_status: bool = False + try: + remote_dir = ( + drive_config.remote_dir + + "/" + + os.path.dirname(local_file_path).replace(save_path, "") + + "/" + ).replace("\\", "/") + + remote_dir = remote_dir.replace(" ", "\ ") + + + if not drive_config.dir_cache.get(remote_dir): + CloudDrive.rclone_mkdir(drive_config, remote_dir) + drive_config.dir_cache[remote_dir] = True + + zip_file_path: str = "" + file_path = local_file_path + if drive_config.before_upload_file_zip: + zip_file_path = CloudDrive.zip_file(local_file_path) + file_path = zip_file_path + else: + file_path = local_file_path + + cmd = ( + f'"{drive_config.rclone_path}" copy "{file_path}" ' + f"{remote_dir}/ --create-empty-src-dirs --ignore-existing --progress" + ) + proc = await asyncio.create_subprocess_shell( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) + if proc.stdout: + async for output in proc.stdout: + s = output.decode(errors="replace") + print(s) + if "Transferred" in s and "100%" in s and "1 / 1" in s: + logger.info(f"upload file {local_file_path} success") + drive_config.total_upload_success_file_count += 1 + if drive_config.after_upload_file_delete: + os.remove(local_file_path) + if drive_config.before_upload_file_zip: + os.remove(zip_file_path) + upload_status = True + + await proc.wait() + except Exception as e: + logger.error(f"{e.__class__} {e}") + return False + + return upload_status + + @staticmethod + def aligo_upload_file( + drive_config: CloudDriveConfig, save_path: str, local_file_path: str + ): + """aliyun upload file""" + upload_status: bool = False + if not drive_config.aligo: + logger.warning("please config aligo! see README.md") + return False + + try: + remote_dir = ( + drive_config.remote_dir + + "/" + + os.path.dirname(local_file_path).replace(save_path, "") + + "/" + ).replace("\\", "/") + + remote_dir = remote_dir.replace(" ", "\ ") + if not drive_config.dir_cache.get(remote_dir): + CloudDrive.aligo_mkdir(drive_config, remote_dir) + aligo_dir = drive_config.aligo.get_folder_by_path(remote_dir) + if aligo_dir: + drive_config.dir_cache[remote_dir] = aligo_dir.file_id + + zip_file_path: str = "" + file_paths = [] + if drive_config.before_upload_file_zip: + zip_file_path = CloudDrive.zip_file(local_file_path) + file_paths.append(zip_file_path) + else: + file_paths.append(local_file_path) + + res = drive_config.aligo.upload_files( + file_paths=file_paths, + parent_file_id=drive_config.dir_cache[remote_dir], + check_name_mode="refuse", + ) + + if len(res) > 0: + drive_config.total_upload_success_file_count += len(res) + if drive_config.after_upload_file_delete: + os.remove(local_file_path) + + if drive_config.before_upload_file_zip: + os.remove(zip_file_path) + + upload_status = True + + except Exception as e: + logger.error(f"{e.__class__} {e}") + return False + + return upload_status + + @staticmethod + async def upload_file( + drive_config: CloudDriveConfig, save_path: str, local_file_path: str + ) -> bool: + """Upload file + Parameters + ---------- + drive_config: CloudDriveConfig + see @CloudDriveConfig + + save_path: str + Local file save path config + + local_file_path: str + Local file path + + Returns + ------- + bool + True or False + """ + if not drive_config.enable_upload_file: + return False + + ret: bool = False + if drive_config.upload_adapter == "rclone": + ret = await CloudDrive.rclone_upload_file( + drive_config, save_path, local_file_path + ) + elif drive_config.upload_adapter == "aligo": + ret = CloudDrive.aligo_upload_file(drive_config, save_path, local_file_path) + + return ret diff --git a/src/parsers/Telegram/telegram_media_downloader/module/download_stat.py b/src/parsers/Telegram/telegram_media_downloader/module/download_stat.py new file mode 100644 index 0000000..50975a0 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/download_stat.py @@ -0,0 +1,112 @@ +"""Download Stat""" +import asyncio +import time +from enum import Enum +from typing import Union + + +class DownloadState(Enum): + """Download state""" + + Downloading = 1 + StopDownload = 2 + + +_download_result: dict = {} +_total_download_speed: int = 0 +_total_download_size: int = 0 +_last_download_time: float = time.time() +_download_state: DownloadState = DownloadState.Downloading + + +def get_download_result() -> dict: + """get global download result""" + return _download_result + + +def get_total_download_speed() -> int: + """get total download speed""" + return _total_download_speed + + +def get_download_state() -> DownloadState: + """get download state""" + return _download_state + + +# pylint: disable = W0603 +def set_download_state(state: DownloadState): + """set download state""" + global _download_state + _download_state = state + + +async def update_download_status( + down_byte: int, + total_size: int, + chat_id: Union[int, str], + message_id: int, + file_name: str, + start_time: float, + task_id: int, +): + """update_download_status""" + cur_time = time.time() + # pylint: disable = W0603 + global _total_download_speed + global _total_download_size + global _last_download_time + + while get_download_state() == DownloadState.StopDownload: + await asyncio.sleep(1) + + if not _download_result.get(chat_id): + _download_result[chat_id] = {} + + if _download_result[chat_id].get(message_id): + last_download_byte = _download_result[chat_id][message_id]["down_byte"] + last_time = _download_result[chat_id][message_id]["end_time"] + download_speed = _download_result[chat_id][message_id]["download_speed"] + each_second_total_download = _download_result[chat_id][message_id][ + "each_second_total_download" + ] + end_time = _download_result[chat_id][message_id]["end_time"] + + _total_download_size += down_byte - last_download_byte + each_second_total_download += down_byte - last_download_byte + + if cur_time - last_time >= 1.0: + download_speed = int(each_second_total_download / (cur_time - last_time)) + end_time = cur_time + each_second_total_download = 0 + + download_speed = max(download_speed, 0) + + _download_result[chat_id][message_id]["down_byte"] = down_byte + _download_result[chat_id][message_id]["end_time"] = end_time + _download_result[chat_id][message_id]["download_speed"] = download_speed + _download_result[chat_id][message_id][ + "each_second_total_download" + ] = each_second_total_download + else: + each_second_total_download = down_byte + _download_result[chat_id][message_id] = { + "down_byte": down_byte, + "total_size": total_size, + "file_name": file_name, + "start_time": start_time, + "end_time": cur_time, + "download_speed": down_byte / (cur_time - start_time), + "each_second_total_download": each_second_total_download, + "task_id": task_id, + } + _total_download_size += down_byte + + if cur_time - _last_download_time >= 1.0: + # update speed + _total_download_speed = int( + _total_download_size / (cur_time - _last_download_time) + ) + _total_download_speed = max(_total_download_speed, 0) + _total_download_size = 0 + _last_download_time = cur_time diff --git a/src/parsers/Telegram/telegram_media_downloader/module/filter.py b/src/parsers/Telegram/telegram_media_downloader/module/filter.py new file mode 100644 index 0000000..08e30e6 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/filter.py @@ -0,0 +1,372 @@ +"""Filter for download""" + +import re +from datetime import datetime +from typing import Any, Optional, Tuple + +from ply import lex, yacc + +from utils.format import get_byte_from_str +from utils.meta_data import MetaData, NoneObj, ReString + + +# pylint: disable = R0904 +class BaseFilter: + """for normal filter""" + + def __init__(self, debug: bool = False): + """ + Parameters + ---------- + debug: bool + If output debug info + + """ + self.names: dict = {} + self.debug = debug + # Build the lexer and parser + # lex.lex(module=self) + self.lexer = lex.lex(module=self) + self.yacc = yacc.yacc(module=self) + + def reset(self): + """Reset all symbol""" + self.names.clear() + + def exec(self, filter_str: str) -> Any: + """Exec filter str""" + # ) # + # return yacc.parse(filter_str, debug=self.debug) + return self.yacc.parse(filter_str, debug=self.debug) + + def _output(self, output_str: str): + """For print debug info""" + if self.debug: + print(output_str) + + reserved = { + "and": "AND", + "or": "OR", + } + + tokens = ( + "NAME", + "NUMBER", + "GE", + "LE", + "LOR", + "LAND", + "STRING", + "RESTRING", + "BYTE", + "EQ", + "NE", + "TIME", + "AND", + "OR", + ) + + literals = ["=", "+", "-", "*", "/", "(", ")", ">", "<"] + + # t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + t_GE = r">=" + t_LE = r"<=" + t_LOR = r"\|\|" + t_LAND = r"&&" + t_EQ = r"==" + t_NE = r"!=" + + def t_BYTE(self, t): + r"\d{1,}(B|KB|MB|GB|TB)" + t.value = get_byte_from_str(t.value) + t.type = "NUMBER" + return t + + def t_TIME(self, t): + r"\d{4}-\d{1,2}-\d{1,2}[ ]{1,}\d{1,2}:\d{1,2}:\d{1,2}" + t.value = datetime.strptime(t.value, "%Y-%m-%d %H:%M:%S") + return t + + def t_STRING(self, t): + r"'.*?'" + # r"'([^\\']+|\\'|\\\\)*'" + t.value = t.value[1:-1] + return t + + def t_RESTRING(self, t): + r"r'.*?'" + # r"r'([^\\']+|\\'|\\\\)*'" + t.value = t.value[2:-1] + return t + + def t_NAME(self, t): + r"[a-zA-Z_][a-zA-Z0-9_]*" + t.type = BaseFilter.reserved.get(t.value, "NAME") + return t + + def t_NUMBER(self, t): + r"\d+" + t.value = int(t.value) + return t + + t_ignore = " \t" + + def t_newline(self, t): + r"\n+" + t.lexer.lineno += t.value.count("\n") + + def t_error(self, t): + """print error""" + print(f"Illegal character '{t.value[0]}'") + t.lexer.skip(1) + + precedence = ( + ("left", "LOR", "OR"), + ("left", "LAND", "AND"), + ("left", "EQ", "NE"), + ("nonassoc", ">", "<", "GE", "LE"), + ("left", "+", "-"), + ("left", "*", "/"), + ("right", "UMINUS"), + ) + + def p_statement_assign(self, p): + 'statement : NAME "=" expression' + return self.p_expression_eq(p) + # self.names[p[1]] = p[3] + + def p_statement_expr(self, p): + "statement : expression" + self._output(p[1]) + p[0] = p[1] + + def p_expression_binop(self, p): + """expression : expression '+' expression + | expression '-' expression + | expression '*' expression + | expression '/' expression""" + self.check_type(p) + if isinstance(p[1], NoneObj): + p[1] = 0 + if isinstance(p[3], NoneObj): + p[3] = 0 + + if p[2] == "+": + p[0] = p[1] + p[3] + elif p[2] == "-": + p[0] = p[1] - p[3] + elif p[2] == "*": + p[0] = p[1] * p[3] + elif p[2] == "/": + p[0] = p[1] / p[3] + + self._output(f"binop {p[1]} {p[2]} {p[3]} = {p[0]}") + + def p_expression_comp(self, p): + """expression : expression '>' expression + | expression '<' expression""" + self.check_type(p) + if isinstance(p[1], NoneObj) or isinstance(p[3], NoneObj): + p[0] = True + return + + if p[1] is None or p[3] is None: + p[0] = False + return + if p[2] == ">": + p[0] = p[1] > p[3] + elif p[2] == "<": + p[0] = p[1] < p[3] + + def p_expression_uminus(self, p): + "expression : '-' expression %prec UMINUS" + p[0] = -p[2] + + def p_expression_ge(self, p): + "expression : expression GE expression" + self.check_type(p) + if isinstance(p[1], NoneObj) or isinstance(p[3], NoneObj): + p[0] = True + return + + if p[1] is None or p[3] is None: + p[0] = False + return + + p[0] = p[1] >= p[3] + self._output(f"{p[1]} {p[2]} {p[3]} {p[0]}") + + def p_expression_le(self, p): + "expression : expression LE expression" + self.check_type(p) + if isinstance(p[1], NoneObj) or isinstance(p[3], NoneObj): + p[0] = True + return + + if p[1] is None or p[3] is None: + p[0] = False + return + + p[0] = p[1] <= p[3] + self._output(f"{p[1]} {p[2]} {p[3]} = {p[0]}") + + def p_expression_eq(self, p): + "expression : expression EQ expression" + self.check_type(p) + if isinstance(p[1], NoneObj) or isinstance(p[3], NoneObj): + p[0] = True + return + + if p[1] is None or p[3] is None: + p[0] = False + return + + if isinstance(p[3], ReString): + if not isinstance(p[1], str): + p[0] = 0 + return + p[0] = re.fullmatch(p[3].re_string, p[1], re.MULTILINE) is not None + self._output(f"{p[1]} {p[2]} {p[3].re_string} {p[0]}") + elif isinstance(p[1], ReString): + if not isinstance(p[3], str): + p[0] = 0 + return + p[0] = re.fullmatch(p[1].re_string, p[3], re.MULTILINE) is not None + self._output(f"{p[1]} {p[2]} {p[3].re_string} {p[0]}") + else: + p[0] = p[1] == p[3] + self._output(f"{p[1]} {p[2]} {p[3]} {p[0]}") + + def p_expression_ne(self, p): + "expression : expression NE expression" + self.check_type(p) + if isinstance(p[1], NoneObj) or isinstance(p[3], NoneObj): + p[0] = True + return + + if p[1] is None or p[3] is None: + p[0] = False + return + if isinstance(p[3], ReString): + if not isinstance(p[1], str): + p[0] = 0 + return + p[0] = re.fullmatch(p[3].re_string, p[1], re.MULTILINE) is None + self._output(f"{p[1]} {p[2]} {p[3].re_string} {p[0]}") + elif isinstance(p[1], ReString): + if not isinstance(p[3], str): + p[0] = 0 + return + p[0] = re.fullmatch(p[1].re_string, p[3], re.MULTILINE) is None + self._output(f"{p[1]} {p[2]} {p[3].re_string} {p[0]}") + else: + p[0] = p[1] != p[3] + self._output(f"{p[1]} {p[2]} {p[3]} = {p[0]}") + + def p_expression_group(self, p): + "expression : '(' expression ')'" + p[0] = p[2] + + def p_expression_number(self, p): + "expression : NUMBER" + p[0] = p[1] + + def p_expression_time(self, p): + "expression : TIME" + p[0] = p[1] + + def p_expression_byte(self, p): + "expression : BYTE" + p[0] = p[1] + + def p_expression_name(self, p): + "expression : NAME" + try: + p[0] = self.names[p[1]] + except Exception as e: + self._output(f"Undefined name '{p[1]}'") + raise ValueError(f"Undefined name {p[1]}") from e + # FIXME: not support not exist name + # p[0] = NoneObj() + + def p_expression_lor(self, p): + "expression : expression LOR expression" + p[0] = p[1] or p[3] + + def p_expression_land(self, p): + "expression : expression LAND expression" + p[0] = p[1] and p[3] + + def p_expression_or(self, p): + "expression : expression OR expression" + p[0] = p[1] or p[3] + + def p_expression_and(self, p): + "expression : expression AND expression" + p[0] = p[1] and p[3] + + def p_expression_string(self, p): + "expression : STRING" + p[0] = p[1] + + def p_expression_restring(self, p): + "expression : RESTRING" + p[0] = ReString(p[1]) + self._output("RESTRING : " + p[0].re_string) + + # pylint: disable = C0116 + def p_error(self, p): + if p: + raise ValueError(f"Syntax error at '{p.value}'") + + raise ValueError("Syntax error at EOF") + + def check_type(self, p): + """Check filter type if is right""" + if p[1] is None or p[1] is NoneObj or p[3] is None or p[3] is NoneObj: + return + if isinstance(p[1], str): + if not isinstance(p[3], str) and not isinstance(p[3], ReString): + raise ValueError(f"{p[1]} is str but {p[3]} is not") + elif isinstance(p[1], int): + if not isinstance(p[3], int): + raise ValueError(f"{p[1]} is int but {p[3]} is not") + elif isinstance(p[1], bool): + if not isinstance(p[3], bool): + raise ValueError(f"{p[1]} is bool but {p[3]} is not") + elif isinstance(p[1], datetime): + if not isinstance(p[3], datetime): + raise ValueError(f"{p[1]} is datetime but {p[3]} is not") + + +class Filter: + """filter for telegram download""" + + def __init__(self): + self.filter = BaseFilter() + + def set_meta_data(self, meta_data: MetaData): + """Set meta data for filter""" + self.filter.reset() + self.filter.names = meta_data.data() + + def set_debug(self, debug: bool): + """Set Filter Debug Model""" + self.filter.debug = debug + + def exec(self, filter_str: str) -> bool: + """Exec filter str""" + + if self.filter.names: + res = self.filter.exec(filter_str) + if isinstance(res, bool): + return res + return False + raise ValueError("meta data cannot be empty!") + + def check_filter(self, filter_str: str) -> Tuple[bool, Optional[str]]: + """check filter str""" + try: + return not self.exec(filter_str) is None, None + except Exception as e: + return False, str(e) diff --git a/src/parsers/Telegram/telegram_media_downloader/module/get_chat_history_v2.py b/src/parsers/Telegram/telegram_media_downloader/module/get_chat_history_v2.py new file mode 100644 index 0000000..9ef0ca0 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/get_chat_history_v2.py @@ -0,0 +1,86 @@ +"""Rewrite pyrogram.get_chat_history""" + +from datetime import datetime +from typing import AsyncGenerator, Optional, Union + +import pyrogram + +# pylint: disable = W0611 +from pyrogram import raw, types, utils + + +async def get_chunk_v2( + *, + client: pyrogram.Client, + chat_id: Union[int, str], + limit: int = 0, + offset: int = 0, + from_message_id: int = 0, + from_date: datetime = utils.zero_datetime(), + reverse: bool = False +): + """get chunk""" + from_message_id = from_message_id or (1 if reverse else 0) + + messages = await utils.parse_messages( + client, + await client.invoke( + raw.functions.messages.GetHistory( + peer=await client.resolve_peer(chat_id), + offset_id=from_message_id, + offset_date=utils.datetime_to_timestamp(from_date), + add_offset=offset * (-1 if reverse else 1) - (limit if reverse else 0), + limit=limit, + max_id=0, + min_id=0, + hash=0, + ), + sleep_threshold=60, + ), + replies=0, + ) + + if reverse: + messages.reverse() + + return messages + + +# pylint: disable = C0301 +async def get_chat_history_v2( + self: pyrogram.Client, + chat_id: Union[int, str], + limit: int = 0, + offset: int = 0, + offset_id: int = 0, + offset_date: datetime = utils.zero_datetime(), + reverse: bool = False, +) -> Optional[AsyncGenerator["types.Message", None]]: + """Get messages from a chat history.""" + current = 0 + total = limit or (1 << 31) - 1 + limit = min(100, total) + + while True: + messages = await get_chunk_v2( + client=self, + chat_id=chat_id, + limit=limit, + offset=offset, + from_message_id=offset_id, + from_date=offset_date, + reverse=reverse, + ) + + if not messages: + return + + offset_id = messages[-1].id + (1 if reverse else 0) + + for message in messages: + yield message + + current += 1 + + if current >= total: + return diff --git a/src/parsers/Telegram/telegram_media_downloader/module/language.py b/src/parsers/Telegram/telegram_media_downloader/module/language.py new file mode 100644 index 0000000..71690f1 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/language.py @@ -0,0 +1,271 @@ +"""Multi language support""" + +# disable pylint: disable = C0301 +from enum import Enum + + +class Language(Enum): + """Language for ui""" + + EN = 1 # english + ZH = 2 # china + RU = 3 # russian + UA = 4 # ukrainian + + +_language = Language.EN + + +def set_language(language: Language): + """Set Lanaguage""" + # pylint: disable = W0603 + global _language + _language = language + + +translations = { + "Forward": ["转发", "Переслать", "Переслати"], + "Total": ["总数", "Всего", "Всього"], + "Success": ["成功", "Успешно", "Успішно"], + "Failed": ["失败", "Не удалось", "Не вдалося"], + "Skipped": ["跳过", "Пропущено", "Пропущено"], + "Message ID": ["消息ID", "ID сообщения", "ID повідомлення"], + "Telegram Media Downloader": [ + "电报媒体下载器", + "Telegram Media Downloader", + "Telegram Media Downloader", + ], + "Version": ["版本", "Версия", "Версія"], + "Downloading": ["下载", "Скачивание", "Скачування"], + "Available commands:": ["可用命令:", "Доступные команды:", "Доступні команди:"], + "Show available commands": [ + "显示可用命令", + "Показать доступные команды", + "Показати доступні команди", + ], + "Download messages": ["下载消息", "Скачать сообщения", "Скачати повідомлення"], + "Forward messages": ["转发消息", "Переслать сообщения", "Переслати повідомлення"], + "Listen for forwarded messages": [ + "监听转发消息", + "Прослушивать пересланные сообщения", + "Прослуховувати переслані повідомлення", + ], + "Set language": ["设置语言", "Установить язык", "Встановити мову"], + "**Note**: 1 means the start of the entire chat": [ + "**注意**: 1表示整个聊天的开始", + "**Примечание**: 1 означает начало всего чата", + "**Увага**: 1 означає початок всього чату", + ], + "0 means the end of the entire chat": [ + "0表示整个聊天的结束", + "0 означает конец всего чата", + "0 означає кінець всього чату", + ], + "means optional, not required": [ + "表示可选项,非必填", + "означает необязательный параметр", + "означає необов'язковий параметр", + ], + "To download the video, use the method to directly enter /download to view": [ + "下载视频,使用方法直接输入/download查看", + "Чтобы скачать видео, введите /download для просмотра", + "Щоб скачати відео, введіть /download для перегляду", + ], + "Forward video, use the method to directly enter /forward to view": [ + "转发视频,使用方法直接输入/forward查看", + "Переслать видео, введите /forward для просмотра", + "Переслати відео, введіть /forward для перегляду", + ], + "Listen forward, use the method to directly enter /listen_forward to view": [ + "监控转发,使用方法直接输入/listen_forward查看", + "Слушать пересылку, введите /listen_forward для просмотра", + "Слухати пересилання, введіть /listen_forward для перегляду", + ], + "Add download filter, use the method to directly enter /add_filter to view": [ + "添加下载过滤器", + "Добавить фильтр загрузки, используйте метод, чтобы непосредственно ввести /add_filter для просмотра", + "Додати фільтр завантаження, використовуйте метод, щоб безпосередньо ввести /add_filter для перегляду", + ], + "Help": ["帮助", "Помощь", "Допомога"], + "Invalid command format": [ + "无效的命令格式", + "Неверный формат команды", + "Невірний формат команди", + ], + "Invalid command format. Please use /set_language en/ru/zh/ua": [ + "无效的命令格式。请使用 /set_language en/ru/zh/ua", + "Неверный формат команды. Пожалуйста, используйте /set_language en/ru/zh/ua", + "Невірний формат команди. Будь ласка, використовуйте /set_language en/ru/zh/ua", + ], + "Language set to English": [ + "语言设置为中文", + "Выбран английский язык", + "Обрано англійську мову", + ], + "Language set to": [ + "语言设置为", + "Выбран язык", + "Обрано мову", + ], + "Invalid command format. Please use /add_filter your filter": [ + "无效的命令格式。请使用 /add_filter 你的过滤规则", + "Неверный формат команды. Пожалуйста, используйте /add_filter ВашФильтр", + "Невірний формат команди. Будь ласка, використовуйте /add_filter ВашФільтр", + ], + "Add download filter": [ + "添加下载过滤器", + "Добавить фильтр скачивания", + "Додати фільтр скачування", + ], + "Check error, please add again": [ + "检验错误,请重新添加", + "Ошибка проверки, пожалуйста, добавьте еще раз", + "Помилка перевірки, будь ласка, додайте ще раз", + ], + "Direct download, directly forward the message to your robot": [ + "直接下载,直接转发消息给你的机器人", + "Скачивание напрямую, пересылка сообщения напрямую вашему роботу", + "Безпосереднє скачування, безспесередня пересилка повідомлення вашому роботу", + ], + "Directly download a single message": [ + "直接下载单条消息", + "Прямое скачивание одного сообщения", + "Безпосереднє скачування одного повідомлення", + ], + "From": ["从", "От", "Від"], + "download": ["下载", "скачать", "скачати"], + "error": ["错误", "ошибка", "помилка"], + "Parameter error, please enter according to the reference format": [ + "参数错误,请根据参考格式输入", + "Ошибка параметра, введите в соответствии с форматом ссылки", + "Помилка параметра, введіть відповідно до формату посилання", + ], + "Download all messages of common group": [ + "下载公共群组的所有消息", + "Скачать все сообщения общей группы", + "Скачати всі повідомлення спільної групи", + ], + "The private group (channel) link is a random group message link": [ + "私密群组(频道) 链接为随便复制一条群组消息链接", + "Ссылка на частную группу (канал) - это ссылка на случайное сообщение группы", + "Посилання на приватну групу (канал) - це посилання на випадкове повідомлення групи", + ], + "The download starts from the N message to the end of the M message": [ + "下载从第N条消息开始的到第M条信息结束", + "Скачивание начинается с сообщения N до конца сообщения M", + "Скачування починається з повідомлення N до кінця повідомлення M", + ], + "When M is 0, it means the last message. The filter is optional": [ + "M为0的时候表示到最后一条信息,过滤器为可选", + "Когда M равно 0, это означает последнее сообщение. Фильтр необязателен", + "Коли M дорівнює 0, це означає останнє повідомлення. Фільтр необов'язковий", + ], + "chat input error, please enter the channel or group link": [ + "chat输入错误,请输入频道或群组的链接", + "Ошибка ввода чата, введите ссылку на канал или группу", + "Помилка введеня чату, введіть посилання на канал або групу", + ], + "Error type": ["错误类型", "Тип ошибки", "Тип помилки"], + "Exception message": ["异常消息", "Сообщение исключения", "Повідомлення винятка"], + "Invalid chat link": [ + "无效的聊天链接", + "Ошибочная ссылка на чат", + "Помилкове посилання на чат", + ], + "Cannot be forwarded to this bot, will cause an infinite loop": [ + "不能转发给该机器人,会导致无限循环", + "Невозможно переслать этому боту, это вызовет бесконечный цикл", + "Неможливо переслати цьому боту, це спричинить безкінечний цикл", + ], + "Please use": ["请使用", "Пожалуйста, используйте", "Будь ласка, використовуйте"], + "Filter": ["过滤器", "Фильтр", "Фільтр"], + "Error forwarding message": [ + "失败的转发消息", + "Ошибка пересылки сообщения", + "Помилка пересилки повідомлення", + ], + "file reference expired, refetching": [ + "文件引用过期,重新获取中", + "Ссылка на файл истекла, повторное получение", + "Посилання на файл минуло, повторне отримання", + ], + "file reference expired for 3 retries, download skipped": [ + "文件引用过期重试超过3次,跳过下载", + "Ссылка на файл истекла после 3 попыток, загрузка пропущена", + "Посилання на файл минуло після 3 спроб, завантаження пропущено", + ], + "Timeout Error occurred when downloading Message": [ + "下载消息超时错误", + "Ошибка времени ожидания при скачивании сообщения", + "Помилка часу очікування при скачуванні повідомлення", + ], + "retrying": ["重试", "повторная попытка", "повторна спроба"], + "seconds": ["秒", "секунд", "секунд"], + "Timing out after 3 reties, download skipped": [ + "超时重试超过3次,跳过下载", + "Истекло время ожидания после 3 попыток, загрузка пропущена", + "Час очікування закінчився після 3 спроб, завантаження пропущено", + ], + "could not be downloaded due to following exception": [ + "无法下载,因为以下异常", + "не может быть скачен по следующей причине", + "не може бути скачаний з наступної причини", + ], + "Downloading files failed during last run": [ + "下载最后一次运行失败的文件", + "Скачивание файлов не удалось во время последнего запуска", + "Скачування файлів не вдалося під час останнього запуску", + ], + "Successfully started (Press Ctrl+C to stop)": [ + "成功启动(按Ctrl+C停止)", + "Запуск успешный (нажмите Ctrl + C для остановки)", + "Запуск успішний (натисніть Ctrl + C для зупинки)", + ], + "KeyboardInterrupt": ["键盘中断", "KeyboardInterrupt", "KeyboardInterrupt"], + "update config": ["更新配置", "обновить конфигурацию", "оновити конфігурацію"], + "Updated last read message_id to config file": [ + "更新最后阅读消息ID到配置文件", + "Обновлен идентификатор последнего прочитанного сообщения в конфигурационном файле", + "Оновлено ідентифікатор останнього прочитаного повідомлення у конфігураційному файлі", + ], + "total download": ["总下载", "всего скачено", "всього скачано"], + "total upload file": ["总上传文件", "всего скаченных файлов", "всього скачаних файлів"], + "Stopped": ["停止", "остановлено", "зупинено"], + "already download,download skipped": [ + "已下载,已跳过下载", + "уже скачен, скачивание пропущена", + "вже скачан, скачування пропущено", + ], + "Media downloaded with wrong size": [ + "媒体下载错误的大小", + "Медиафайл скачен с неправильным размером", + "Медіафайл скачано з неправильним розміром", + ], + "actual": ["实际", "фактический", "фактичний"], + "file name": ["文件名", "имя файла", "ім'я файлу"], + "Successfully downloaded": ["成功下载", "Успешно скачано", "Успішно скачано"], + "Get group and user info from message link": [ + "从消息链接中获取群组和用户信息", + "Получить информацию о группе и пользователе по ссылке на сообщение", + "Отримайте інформацію про групу та користувача за посиланням у повідомленні", + ], +} + + +def _t(text: str): + """Get translation + Parameters + ---------- + text : str + language : str + Returns + ------- + str + """ + if _language is Language.EN: + return text + + if text in translations: + return translations[text][_language.value - 2] + + return text diff --git a/src/parsers/Telegram/telegram_media_downloader/module/pyrogram_extension.py b/src/parsers/Telegram/telegram_media_downloader/module/pyrogram_extension.py new file mode 100644 index 0000000..9bc0765 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/pyrogram_extension.py @@ -0,0 +1,597 @@ +"""Pyrogram ext""" + +import asyncio +import os +import secrets +import struct +import time +from functools import wraps +from io import BytesIO, StringIO +from mimetypes import MimeTypes +from typing import List, Optional, Union + +import pyrogram +from loguru import logger +from pyrogram.client import Cache +from pyrogram.file_id import ( + FILE_REFERENCE_FLAG, + PHOTO_TYPES, + WEB_LOCATION_FLAG, + FileType, + b64_decode, + rle_decode, +) +from pyrogram.mime_types import mime_types + +from module.app import Application, DownloadStatus, ForwardStatus, TaskNode +from module.download_stat import get_download_result +from module.language import Language, _t +from utils.format import create_progress_bar, format_byte, truncate_filename +from utils.meta_data import MetaData + +_mimetypes = MimeTypes() +_mimetypes.readfp(StringIO(mime_types)) +_download_cache = Cache(1024 * 1024 * 1024) + + +def reset_download_cache(): + """Reset download cache""" + _download_cache.store.clear() + + +def _guess_mime_type(filename: str) -> Optional[str]: + """Guess mime type""" + return _mimetypes.guess_type(filename)[0] + + +def _guess_extension(mime_type: str) -> Optional[str]: + """Guess extension""" + return _mimetypes.guess_extension(mime_type) + + +def _get_file_type(file_id: str): + """Get file type""" + decoded = rle_decode(b64_decode(file_id)) + + # File id versioning. Major versions lower than 4 don't have a minor version + major = decoded[-1] + + if major < 4: + buffer = BytesIO(decoded[:-1]) + else: + buffer = BytesIO(decoded[:-2]) + + file_type, _ = struct.unpack(" str: + """Get extension""" + + if not file_id: + if dot: + return ".unknown" + return "unknown" + + file_type = _get_file_type(file_id) + + guessed_extension = _guess_extension(mime_type) + + if file_type in PHOTO_TYPES: + extension = "jpg" + elif file_type == FileType.VOICE: + extension = guessed_extension or "ogg" + elif file_type in (FileType.VIDEO, FileType.ANIMATION, FileType.VIDEO_NOTE): + extension = guessed_extension or "mp4" + elif file_type == FileType.DOCUMENT: + extension = guessed_extension or "zip" + elif file_type == FileType.STICKER: + extension = guessed_extension or "webp" + elif file_type == FileType.AUDIO: + extension = guessed_extension or "mp3" + else: + extension = "unknown" + + if dot: + extension = "." + extension + return extension + + +async def send_message_by_language( + client: pyrogram.client.Client, + language: Language, + chat_id: Union[int, str], + reply_to_message_id: int, + language_str: List[str], +): + """Record download status""" + msg = language_str[language.value - 1] + + return await client.send_message( + chat_id, msg, reply_to_message_id=reply_to_message_id + ) + + +async def download_thumbnail( + client: pyrogram.Client, + temp_path: str, + message: pyrogram.types.Message, +): + """Downloads the thumbnail of a video message to a temporary file. + + Args: + client: A Pyrogram client instance. + temp_path: The path to a temporary directory where the thumbnail file + will be stored. + message: A Pyrogram Message object representing the video message. + + Returns: + A string representing the path of the thumbnail file, or None if the + download failed. + + Raises: + ValueError: If the downloaded thumbnail file size doesn't match the + expected file size. + """ + thumbnail_file = None + if message.video.thumbs: + message = await fetch_message(client, message) + thumbnail = message.video.thumbs[0] if message.video.thumbs else None + unique_name = os.path.join( + temp_path, + "thumbnail", + f"thumb-{int(time.time())}-{secrets.token_hex(8)}.jpg", + ) + + max_attempts = 3 + for attempt in range(1, max_attempts + 1): + try: + thumbnail_file = await client.download_media( + thumbnail, file_name=unique_name + ) + + if os.path.getsize(thumbnail_file) == thumbnail.file_size: + break + + raise ValueError( + f"Thumbnail file size is {os.path.getsize(thumbnail_file)}" + f" bytes, actual {thumbnail.file_size}: {thumbnail_file}" + ) + + except Exception as e: + if attempt == max_attempts: + logger.exception( + f"Failed to download thumbnail after {max_attempts}" + f" attempts: {e}" + ) + else: + message = await fetch_message(client, message) + logger.warning( + f"Attempt {attempt} to download thumbnail failed: {e}" + ) + # Wait 2 seconds before retrying + await asyncio.sleep(2) + + thumbnail = None + thumbnail_file = None + return thumbnail_file + + +async def upload_telegram_chat( + client: pyrogram.Client, + upload_user: pyrogram.Client, + app: Application, + node: TaskNode, + message: pyrogram.types.Message, + file_name: str, + download_status: DownloadStatus, +): + """Upload telegram chat""" + # upload telegram + forward_ret = ForwardStatus.FailedForward + if node.upload_telegram_chat_id: + if download_status is DownloadStatus.SkipDownload: + forward_ret = ForwardStatus.SkipForward + elif download_status is DownloadStatus.SuccessDownload: + try: + forward_ret = await upload_telegram_chat_message( + client, + upload_user, + app, + node.upload_telegram_chat_id, + message, + file_name, + ) + except Exception as e: + logger.exception(f"Upload file {file_name} error: {e}") + finally: + if app.after_upload_telegram_delete: + os.remove(file_name) + + # forward text + # FIXME: fix upload text + # if ( + # download_status is DownloadStatus.SkipDownload + # and message.text + # and bot + # ): + # await upload_telegram_chat( + # client, app, node.upload_telegram_chat_id, message, file_name + # ) + node.stat_forward(forward_ret) + + +async def upload_telegram_chat_message( + client: pyrogram.Client, + upload_user: pyrogram.Client, + app: Application, + upload_telegram_chat_id: Union[int, str], + message: pyrogram.types.Message, + file_name: str, +) -> ForwardStatus: + """See upload telegram_chat""" + max_attempts = 3 + for attempt in range(1, max_attempts + 1): + try: + await _upload_telegram_chat_message( + client, upload_user, app, upload_telegram_chat_id, message, file_name + ) + return ForwardStatus.SuccessForward + except pyrogram.errors.exceptions.flood_420.FloodWait as wait_err: + await asyncio.sleep(wait_err.value * 2) + logger.warning( + "Upload Message[{}]: FlowWait {}", message.id, wait_err.value + ) + if attempt == max_attempts: + return ForwardStatus.FailedForward + + return ForwardStatus.FailedForward + + +async def _upload_telegram_chat_message( + client: pyrogram.Client, + upload_user: pyrogram.Client, + app: Application, + upload_telegram_chat_id: Union[int, str], + message: pyrogram.types.Message, + file_name: str, +): + """ + Uploads a video or message to a Telegram chat. + + Parameters: + client (pyrogram.Client): The pyrogram client. + upload_telegram_chat_id (Union[int, str]): The ID of the chat to upload to. + message (pyrogram.types.Message): The message to upload. + file_name (str): The name of the file to upload. + """ + + if message.video: + # Download thumbnail + thumbnail_file = await download_thumbnail(client, app.temp_save_path, message) + try: + # TODO(tangyoha): add more log when upload video more than 2000MB failed + # Send video to the destination chat + await upload_user.send_video( + chat_id=upload_telegram_chat_id, + video=file_name, + thumb=thumbnail_file, + width=message.video.width, + height=message.video.height, + duration=message.video.duration, + caption=message.caption or "", + parse_mode=pyrogram.enums.ParseMode.HTML, + ) + except Exception as e: + raise e + finally: + if thumbnail_file: + os.remove(str(thumbnail_file)) + + elif message.photo: + await upload_user.send_photo( + upload_telegram_chat_id, file_name, caption=message.caption + ) + elif message.document: + await upload_user.send_document( + upload_telegram_chat_id, file_name, caption=message.caption + ) + elif message.voice: + await upload_user.send_voice( + upload_telegram_chat_id, file_name, caption=message.caption + ) + elif message.video_note: + await upload_user.send_video_note( + upload_telegram_chat_id, file_name, caption=message.caption + ) + elif message.text: + await upload_user.send_message(upload_telegram_chat_id, message.text) + + +def record_download_status(func): + """Record download status""" + + @wraps(func) + async def inner( + client: pyrogram.client.Client, + message: pyrogram.types.Message, + media_types: List[str], + file_formats: dict, + chat_id: Union[int, str], + task_id: int = 0, + ): + if _download_cache[(chat_id, message.id)] is DownloadStatus.Downloading: + return DownloadStatus.Downloading, None + + _download_cache[(chat_id, message.id)] = DownloadStatus.Downloading + + status, file_name = await func( + client, message, media_types, file_formats, chat_id, task_id + ) + + _download_cache[(chat_id, message.id)] = status + + return status, file_name + + return inner + + +async def report_bot_download_status( + client: pyrogram.Client, + node: TaskNode, + download_status: DownloadStatus, + download_size: int = 0, +): + """ + Sends a message with the current status of the download bot. + + Parameters: + client (pyrogram.Client): The client instance. + node (TaskNode): The download task node. + download_status (DownloadStatus): The current download status. + + Returns: + None + """ + node.stat(download_status) + node.total_download_byte += download_size + await report_bot_status(client, node) + + +async def report_bot_forward_status( + client: pyrogram.Client, + node: TaskNode, + status: ForwardStatus, +): + """ + Sends a message with the current status of the download bot. + + Parameters: + client (pyrogram.Client): The client instance. + node (TaskNode): The download task node. + status (ForwardStatus): The current forward status. + + Returns: + None + """ + node.stat_forward(status) + await report_bot_status(client, node) + + +async def report_bot_status( + client: pyrogram.Client, + node: TaskNode, + immediate_reply=False, +): + """ + Sends a message with the current status of the download bot. + + Parameters: + client (pyrogram.Client): The client instance. + node (TaskNode): The download task node. + immediate_reply(bool): Immediate reply + + Returns: + None + """ + if not node.reply_message_id or not node.bot: + return + + if immediate_reply or node.can_reply(): + if node.upload_telegram_chat_id: + node.forward_msg_detail_str = ( + f"\n📥 {_t('Forward')}\n" + f"├─ 📁 {_t('Total')}: {node.total_forward_task}\n" + f"├─ ✅ {_t('Success')}: {node.success_forward_task}\n" + f"├─ ❌ {_t('Failed')}: {node.failed_forward_task}\n" + f"└─ ⏩ {_t('Skipped')}: {node.skip_forward_task}\n" + ) + + upload_msg_detail_str: str = "" + + if node.upload_success_count: + upload_msg_detail_str = ( + f"\n📥 {_t('Upload')}\n" + f"└─ ✅ {_t('Success')}: {node.upload_success_count}\n" + ) + + download_result_str = "" + download_result = get_download_result() + if node.chat_id in download_result: + messages = download_result[node.chat_id] + for idx, value in messages.items(): + task_id = value["task_id"] + if task_id != node.task_id or value["down_byte"] == value["total_size"]: + continue + + temp_file_name = truncate_filename( + os.path.basename(value["file_name"]), 10 + ) + progress = int(value["down_byte"] / value["total_size"] * 100) + download_result_str += ( + f" ├─ 🆔 {_t('Message ID')}: {idx}\n" + f" │ ├─ 📁 : {temp_file_name}\n" + f" │ ├─ 📏 : {format_byte(value['total_size'])}\n" + f" │ ├─ 🚀 : {format_byte(value['download_speed'])}/s\n" + f" │ └─ 📊 : [{create_progress_bar(progress)}]" + f" ({progress}%)\n" + ) + + if download_result_str: + download_result_str = "\n📈 Download Progresses:\n" + download_result_str + + new_msg_str = ( + f"```\n" + f"🆔 task id: {node.task_id}\n" + f"📥 {_t('Downloading')}: {format_byte(node.total_download_byte)}\n" + f"├─ 📁 {_t('Total')}: {node.total_download_task}\n" + f"├─ ✅ {_t('Success')}: {node.success_download_task}\n" + f"├─ ❌ {_t('Failed')}: {node.failed_download_task}\n" + f"└─ ⏩ {_t('Skipped')}: {node.skip_download_task}\n" + f"{node.forward_msg_detail_str}" + f"{upload_msg_detail_str}" + f"{download_result_str}\n```" + ) + + try: + if new_msg_str != node.last_edit_msg: + await client.edit_message_text( + node.from_user_id, + node.reply_message_id, + new_msg_str, + parse_mode=pyrogram.enums.ParseMode.MARKDOWN, + ) + except Exception: + pass + + +def set_max_concurrent_transmissions( + client: pyrogram.Client, max_concurrent_transmissions: int +): + """Set maximum concurrent transmissions""" + if getattr(client, "max_concurrent_transmissions", None): + client.max_concurrent_transmissions = max_concurrent_transmissions + client.save_file_semaphore = asyncio.Semaphore( + client.max_concurrent_transmissions + ) + client.get_file_semaphore = asyncio.Semaphore( + client.max_concurrent_transmissions + ) + + +async def fetch_message(client: pyrogram.Client, message: pyrogram.types.Message): + """ + This function retrieves a message from a specified chat using the Pyrogram library. + Args: + client (pyrogram.Client): A client instance created using Pyrogram. + message (pyrogram.types.Message): A message instance returned from Pyrogram. + Returns: + pyrogram.types.Message: A message object retrieved from the specified chat. + """ + return await client.get_messages( + chat_id=message.chat.id, + message_ids=message.id, + ) + + +async def get_message_with_retry( + client: pyrogram.Client, + chat_id: Union[int, str], + message_id: int, + max_attempts: int = 3, + wait_second: int = 15, +): + """ + This function retrieves a message from a specified chat using the Pyrogram library. + Args: + client (pyrogram.Client): A client instance created using Pyrogram. + chat_id (Union[int, str]): Chat Id + message_id (int): message id. + Returns: + pyrogram.types.Message: A message object retrieved from the specified chat. + """ + for attempt in range(1, max_attempts + 1): + try: + return await client.get_messages( + chat_id=chat_id, + message_ids=message_id, + ) + except Exception as e: + if attempt == max_attempts: + logger.error("Failed Get Message[{}]", message_id) + return None + + logger.exception("Get Message[{}]: Error {}", message_id, e) + await asyncio.sleep(wait_second) + + +async def check_user_permission( + client: pyrogram.Client, user_id: Union[int, str], chat_id: Union[int, str] +) -> bool: + """ + Check if the user has permission to send videos in the group. + + Args: + client (pyrogram.Client): A client instance created using Pyrogram. + user_id (Union[int, str]): User Id + chat_id (Union[int, str]): Chat Id + + Returns: + if can_send_media_messages return True + """ + try: + member = await client.get_chat_member(chat_id, user_id) + return member and ( + not member.permissions or member.permissions.can_send_media_messages + ) + except Exception: + # logger.exception(e) + pass + + return False + + +def set_meta_data( + meta_data: MetaData, message: pyrogram.types.Message, caption: str = None +): + """Get all meta data""" + # message + meta_data.message_date = getattr(message, "date", None) + if caption: + meta_data.message_caption = caption + else: + meta_data.message_caption = getattr(message, "caption", None) or "" + meta_data.message_id = getattr(message, "id", None) + + from_user = getattr(message, "from_user") + meta_data.sender_id = from_user.id if from_user else 0 + meta_data.sender_name = (from_user.username if from_user else "") or "" + meta_data.reply_to_message_id = getattr( + message, "reply_to_message_id", 1 + ) # 1 for General + + # media + for kind in meta_data.AVAILABLE_MEDIA: + media_obj = getattr(message, kind, None) + if media_obj is not None: + meta_data.media_type = kind + break + else: + return + meta_data.media_file_name = getattr(media_obj, "file_name", None) or "" + meta_data.media_file_size = getattr(media_obj, "file_size", None) + meta_data.media_width = getattr(media_obj, "width", None) + meta_data.media_height = getattr(media_obj, "height", None) + meta_data.media_duration = getattr(media_obj, "duration", None) + meta_data.file_extension = get_extension( + media_obj.file_id, getattr(media_obj, "mime_type", ""), False + ) diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/CONTRIBUTING.md b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/CONTRIBUTING.md new file mode 100644 index 0000000..8fab0f0 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contribution + +# Git Flow + +The crypto-js project uses [git flow](https://github.com/nvie/gitflow) to manage branches. +Do your changes on the `develop` or even better on a `feature/*` branch. Don't do any changes on the `master` branch. + +# Pull request + +Target your pull request on `develop` branch. Other pull request won't be accepted. + +# How to build + +1. Clone + +2. Run + + ```sh + npm install + ``` + +3. Run + + ```sh + npm run build + ``` + +4. Check `build` folder diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/LICENSE b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/LICENSE new file mode 100644 index 0000000..3f98399 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/LICENSE @@ -0,0 +1,24 @@ +# License + +[The MIT License (MIT)](http://opensource.org/licenses/MIT) + +Copyright (c) 2009-2013 Jeff Mott +Copyright (c) 2013-2016 Evan Vosberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/README.md b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/README.md new file mode 100644 index 0000000..692ead6 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/README.md @@ -0,0 +1,259 @@ +# crypto-js [![Build Status](https://travis-ci.org/brix/crypto-js.svg?branch=develop)](https://travis-ci.org/brix/crypto-js) + +JavaScript library of crypto standards. + +## Node.js (Install) + +Requirements: + +- Node.js +- npm (Node.js package manager) + +```bash +npm install crypto-js +``` + +### Usage + +ES6 import for typical API call signing use case: + +```javascript +import sha256 from 'crypto-js/sha256'; +import hmacSHA512 from 'crypto-js/hmac-sha512'; +import Base64 from 'crypto-js/enc-base64'; + +const message, nonce, path, privateKey; // ... +const hashDigest = sha256(nonce + message); +const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey)); +``` + +Modular include: + +```javascript +var AES = require("crypto-js/aes"); +var SHA256 = require("crypto-js/sha256"); +... +console.log(SHA256("Message")); +``` + +Including all libraries, for access to extra methods: + +```javascript +var CryptoJS = require("crypto-js"); +console.log(CryptoJS.HmacSHA1("Message", "Key")); +``` + +## Client (browser) + +Requirements: + +- Node.js +- Bower (package manager for frontend) + +```bash +bower install crypto-js +``` + +### Usage + +Modular include: + +```javascript +require.config({ + packages: [ + { + name: 'crypto-js', + location: 'path-to/bower_components/crypto-js', + main: 'index' + } + ] +}); + +require(["crypto-js/aes", "crypto-js/sha256"], function (AES, SHA256) { + console.log(SHA256("Message")); +}); +``` + +Including all libraries, for access to extra methods: + +```javascript +// Above-mentioned will work or use this simple form +require.config({ + paths: { + 'crypto-js': 'path-to/bower_components/crypto-js/crypto-js' + } +}); + +require(["crypto-js"], function (CryptoJS) { + console.log(CryptoJS.HmacSHA1("Message", "Key")); +}); +``` + +### Usage without RequireJS + +```html + + +``` + +## API + +See: https://cryptojs.gitbook.io/docs/ + +### AES Encryption + +#### Plain text encryption + +```javascript +var CryptoJS = require("crypto-js"); + +// Encrypt +var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString(); + +// Decrypt +var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123'); +var originalText = bytes.toString(CryptoJS.enc.Utf8); + +console.log(originalText); // 'my message' +``` + +#### Object encryption + +```javascript +var CryptoJS = require("crypto-js"); + +var data = [{id: 1}, {id: 2}] + +// Encrypt +var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123').toString(); + +// Decrypt +var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123'); +var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); + +console.log(decryptedData); // [{id: 1}, {id: 2}] +``` + +### List of modules + + +- ```crypto-js/core``` +- ```crypto-js/x64-core``` +- ```crypto-js/lib-typedarrays``` + +--- + +- ```crypto-js/md5``` +- ```crypto-js/sha1``` +- ```crypto-js/sha256``` +- ```crypto-js/sha224``` +- ```crypto-js/sha512``` +- ```crypto-js/sha384``` +- ```crypto-js/sha3``` +- ```crypto-js/ripemd160``` + +--- + +- ```crypto-js/hmac-md5``` +- ```crypto-js/hmac-sha1``` +- ```crypto-js/hmac-sha256``` +- ```crypto-js/hmac-sha224``` +- ```crypto-js/hmac-sha512``` +- ```crypto-js/hmac-sha384``` +- ```crypto-js/hmac-sha3``` +- ```crypto-js/hmac-ripemd160``` + +--- + +- ```crypto-js/pbkdf2``` + +--- + +- ```crypto-js/aes``` +- ```crypto-js/tripledes``` +- ```crypto-js/rc4``` +- ```crypto-js/rabbit``` +- ```crypto-js/rabbit-legacy``` +- ```crypto-js/evpkdf``` + +--- + +- ```crypto-js/format-openssl``` +- ```crypto-js/format-hex``` + +--- + +- ```crypto-js/enc-latin1``` +- ```crypto-js/enc-utf8``` +- ```crypto-js/enc-hex``` +- ```crypto-js/enc-utf16``` +- ```crypto-js/enc-base64``` + +--- + +- ```crypto-js/mode-cfb``` +- ```crypto-js/mode-ctr``` +- ```crypto-js/mode-ctr-gladman``` +- ```crypto-js/mode-ofb``` +- ```crypto-js/mode-ecb``` + +--- + +- ```crypto-js/pad-pkcs7``` +- ```crypto-js/pad-ansix923``` +- ```crypto-js/pad-iso10126``` +- ```crypto-js/pad-iso97971``` +- ```crypto-js/pad-zeropadding``` +- ```crypto-js/pad-nopadding``` + + +## Release notes + +### 4.1.1 + +Fix module order in bundled release. + +Include the browser field in the released package.json. + +### 4.1.0 + +Added url safe variant of base64 encoding. [357](https://github.com/brix/crypto-js/pull/357) + +Avoid webpack to add crypto-browser package. [364](https://github.com/brix/crypto-js/pull/364) + +### 4.0.0 + +This is an update including breaking changes for some environments. + +In this version `Math.random()` has been replaced by the random methods of the native crypto module. + +For this reason CryptoJS might not run in some JavaScript environments without native crypto module. Such as IE 10 or before or React Native. + +### 3.3.0 + +Rollback, `3.3.0` is the same as `3.1.9-1`. + +The move of using native secure crypto module will be shifted to a new `4.x.x` version. As it is a breaking change the impact is too big for a minor release. + +### 3.2.1 + +The usage of the native crypto module has been fixed. The import and access of the native crypto module has been improved. + +### 3.2.0 + +In this version `Math.random()` has been replaced by the random methods of the native crypto module. + +For this reason CryptoJS might does not run in some JavaScript environments without native crypto module. Such as IE 10 or before. + +If it's absolute required to run CryptoJS in such an environment, stay with `3.1.x` version. Encrypting and decrypting stays compatible. But keep in mind `3.1.x` versions still use `Math.random()` which is cryptographically not secure, as it's not random enough. + +This version came along with `CRITICAL` `BUG`. + +DO NOT USE THIS VERSION! Please, go for a newer version! + +### 3.1.x + +The `3.1.x` are based on the original CryptoJS, wrapped in CommonJS modules. diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/aes.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/aes.js new file mode 100644 index 0000000..156e2c7 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/aes.js @@ -0,0 +1,234 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Lookup tables + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX_0 = []; + var SUB_MIX_1 = []; + var SUB_MIX_2 = []; + var SUB_MIX_3 = []; + var INV_SUB_MIX_0 = []; + var INV_SUB_MIX_1 = []; + var INV_SUB_MIX_2 = []; + var INV_SUB_MIX_3 = []; + + // Compute lookup tables + (function () { + // Compute double table + var d = []; + for (var i = 0; i < 256; i++) { + if (i < 128) { + d[i] = i << 1; + } else { + d[i] = (i << 1) ^ 0x11b; + } + } + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; i++) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX_0[x] = (t << 24) | (t >>> 8); + SUB_MIX_1[x] = (t << 16) | (t >>> 16); + SUB_MIX_2[x] = (t << 8) | (t >>> 24); + SUB_MIX_3[x] = t; + + // Compute inv sub bytes, inv mix columns tables + var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX_3[sx] = t; + + // Compute next counter + if (!x) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } + }()); + + // Precomputed Rcon lookup + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + + /** + * AES block cipher algorithm. + */ + var AES = C_algo.AES = BlockCipher.extend({ + _doReset: function () { + var t; + + // Skip reset of nRounds has been set before and key did not change + if (this._nRounds && this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + // Compute number of rounds + var nRounds = this._nRounds = keySize + 6; + + // Compute number of key schedule rows + var ksRows = (nRounds + 1) * 4; + + // Compute key schedule + var keySchedule = this._keySchedule = []; + for (var ksRow = 0; ksRow < ksRows; ksRow++) { + if (ksRow < keySize) { + keySchedule[ksRow] = keyWords[ksRow]; + } else { + t = keySchedule[ksRow - 1]; + + if (!(ksRow % keySize)) { + // Rot word + t = (t << 8) | (t >>> 24); + + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + + // Mix Rcon + t ^= RCON[(ksRow / keySize) | 0] << 24; + } else if (keySize > 6 && ksRow % keySize == 4) { + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + } + + keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; + } + } + + // Compute inv key schedule + var invKeySchedule = this._invKeySchedule = []; + for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { + var ksRow = ksRows - invKsRow; + + if (invKsRow % 4) { + var t = keySchedule[ksRow]; + } else { + var t = keySchedule[ksRow - 4]; + } + + if (invKsRow < 4 || ksRow <= 4) { + invKeySchedule[invKsRow] = t; + } else { + invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ + INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; + } + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); + }, + + decryptBlock: function (M, offset) { + // Swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + + this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + + // Inv swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + }, + + _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { + // Shortcut + var nRounds = this._nRounds; + + // Get input, add round key + var s0 = M[offset] ^ keySchedule[0]; + var s1 = M[offset + 1] ^ keySchedule[1]; + var s2 = M[offset + 2] ^ keySchedule[2]; + var s3 = M[offset + 3] ^ keySchedule[3]; + + // Key schedule row counter + var ksRow = 4; + + // Rounds + for (var round = 1; round < nRounds; round++) { + // Shift rows, sub bytes, mix columns, add round key + var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; + var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; + var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; + var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; + + // Update state + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + + // Shift rows, sub bytes, add round key + var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + + // Set output + M[offset] = t0; + M[offset + 1] = t1; + M[offset + 2] = t2; + M[offset + 3] = t3; + }, + + keySize: 256/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); + */ + C.AES = BlockCipher._createHelper(AES); + }()); + + + return CryptoJS.AES; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/bower.json b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/bower.json new file mode 100644 index 0000000..1e12fdc --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/bower.json @@ -0,0 +1,39 @@ +{ + "name": "crypto-js", + "version": "4.1.1", + "description": "JavaScript library of crypto standards.", + "license": "MIT", + "homepage": "http://github.com/brix/crypto-js", + "repository": { + "type": "git", + "url": "http://github.com/brix/crypto-js.git" + }, + "keywords": [ + "security", + "crypto", + "Hash", + "MD5", + "SHA1", + "SHA-1", + "SHA256", + "SHA-256", + "RC4", + "Rabbit", + "AES", + "DES", + "PBKDF2", + "HMAC", + "OFB", + "CFB", + "CTR", + "CBC", + "Base64", + "Base64url" + ], + "main": "index.js", + "dependencies": {}, + "browser": { + "crypto": false + }, + "ignore": [] +} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/cipher-core.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/cipher-core.js new file mode 100644 index 0000000..ebc61f6 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/cipher-core.js @@ -0,0 +1,890 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./evpkdf")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./evpkdf"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Cipher core components. + */ + CryptoJS.lib.Cipher || (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var Base64 = C_enc.Base64; + var C_algo = C.algo; + var EvpKDF = C_algo.EvpKDF; + + /** + * Abstract base cipher template. + * + * @property {number} keySize This cipher's key size. Default: 4 (128 bits) + * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) + * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. + * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. + */ + var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + * + * @property {WordArray} iv The IV to use for this operation. + */ + cfg: Base.extend(), + + /** + * Creates this cipher in encryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); + */ + createEncryptor: function (key, cfg) { + return this.create(this._ENC_XFORM_MODE, key, cfg); + }, + + /** + * Creates this cipher in decryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); + */ + createDecryptor: function (key, cfg) { + return this.create(this._DEC_XFORM_MODE, key, cfg); + }, + + /** + * Initializes a newly created cipher. + * + * @param {number} xformMode Either the encryption or decryption transormation mode constant. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @example + * + * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); + */ + init: function (xformMode, key, cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Store transform mode and key + this._xformMode = xformMode; + this._key = key; + + // Set initial values + this.reset(); + }, + + /** + * Resets this cipher to its initial state. + * + * @example + * + * cipher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-cipher logic + this._doReset(); + }, + + /** + * Adds data to be encrypted or decrypted. + * + * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. + * + * @return {WordArray} The data after processing. + * + * @example + * + * var encrypted = cipher.process('data'); + * var encrypted = cipher.process(wordArray); + */ + process: function (dataUpdate) { + // Append + this._append(dataUpdate); + + // Process available blocks + return this._process(); + }, + + /** + * Finalizes the encryption or decryption process. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. + * + * @return {WordArray} The data after final processing. + * + * @example + * + * var encrypted = cipher.finalize(); + * var encrypted = cipher.finalize('data'); + * var encrypted = cipher.finalize(wordArray); + */ + finalize: function (dataUpdate) { + // Final data update + if (dataUpdate) { + this._append(dataUpdate); + } + + // Perform concrete-cipher logic + var finalProcessedData = this._doFinalize(); + + return finalProcessedData; + }, + + keySize: 128/32, + + ivSize: 128/32, + + _ENC_XFORM_MODE: 1, + + _DEC_XFORM_MODE: 2, + + /** + * Creates shortcut functions to a cipher's object interface. + * + * @param {Cipher} cipher The cipher to create a helper for. + * + * @return {Object} An object with encrypt and decrypt shortcut functions. + * + * @static + * + * @example + * + * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); + */ + _createHelper: (function () { + function selectCipherStrategy(key) { + if (typeof key == 'string') { + return PasswordBasedCipher; + } else { + return SerializableCipher; + } + } + + return function (cipher) { + return { + encrypt: function (message, key, cfg) { + return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); + }, + + decrypt: function (ciphertext, key, cfg) { + return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); + } + }; + }; + }()) + }); + + /** + * Abstract base stream cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + */ + var StreamCipher = C_lib.StreamCipher = Cipher.extend({ + _doFinalize: function () { + // Process partial blocks + var finalProcessedBlocks = this._process(!!'flush'); + + return finalProcessedBlocks; + }, + + blockSize: 1 + }); + + /** + * Mode namespace. + */ + var C_mode = C.mode = {}; + + /** + * Abstract base block cipher mode template. + */ + var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ + /** + * Creates this mode for encryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); + */ + createEncryptor: function (cipher, iv) { + return this.Encryptor.create(cipher, iv); + }, + + /** + * Creates this mode for decryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); + */ + createDecryptor: function (cipher, iv) { + return this.Decryptor.create(cipher, iv); + }, + + /** + * Initializes a newly created mode. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @example + * + * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); + */ + init: function (cipher, iv) { + this._cipher = cipher; + this._iv = iv; + } + }); + + /** + * Cipher Block Chaining mode. + */ + var CBC = C_mode.CBC = (function () { + /** + * Abstract base CBC mode. + */ + var CBC = BlockCipherMode.extend(); + + /** + * CBC encryptor. + */ + CBC.Encryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // XOR and encrypt + xorBlock.call(this, words, offset, blockSize); + cipher.encryptBlock(words, offset); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + /** + * CBC decryptor. + */ + CBC.Decryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + // Decrypt and XOR + cipher.decryptBlock(words, offset); + xorBlock.call(this, words, offset, blockSize); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function xorBlock(words, offset, blockSize) { + var block; + + // Shortcut + var iv = this._iv; + + // Choose mixing block + if (iv) { + block = iv; + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + block = this._prevBlock; + } + + // XOR blocks + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= block[i]; + } + } + + return CBC; + }()); + + /** + * Padding namespace. + */ + var C_pad = C.pad = {}; + + /** + * PKCS #5/7 padding strategy. + */ + var Pkcs7 = C_pad.Pkcs7 = { + /** + * Pads data using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to pad. + * @param {number} blockSize The multiple that the data should be padded to. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.pad(wordArray, 4); + */ + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding word + var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + + // Create padding + var paddingWords = []; + for (var i = 0; i < nPaddingBytes; i += 4) { + paddingWords.push(paddingWord); + } + var padding = WordArray.create(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, + + /** + * Unpads data that had been padded using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to unpad. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.unpad(wordArray); + */ + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + /** + * Abstract base block cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + */ + var BlockCipher = C_lib.BlockCipher = Cipher.extend({ + /** + * Configuration options. + * + * @property {Mode} mode The block mode to use. Default: CBC + * @property {Padding} padding The padding strategy to use. Default: Pkcs7 + */ + cfg: Cipher.cfg.extend({ + mode: CBC, + padding: Pkcs7 + }), + + reset: function () { + var modeCreator; + + // Reset cipher + Cipher.reset.call(this); + + // Shortcuts + var cfg = this.cfg; + var iv = cfg.iv; + var mode = cfg.mode; + + // Reset block mode + if (this._xformMode == this._ENC_XFORM_MODE) { + modeCreator = mode.createEncryptor; + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + modeCreator = mode.createDecryptor; + // Keep at least one block in the buffer for unpadding + this._minBufferSize = 1; + } + + if (this._mode && this._mode.__creator == modeCreator) { + this._mode.init(this, iv && iv.words); + } else { + this._mode = modeCreator.call(mode, this, iv && iv.words); + this._mode.__creator = modeCreator; + } + }, + + _doProcessBlock: function (words, offset) { + this._mode.processBlock(words, offset); + }, + + _doFinalize: function () { + var finalProcessedBlocks; + + // Shortcut + var padding = this.cfg.padding; + + // Finalize + if (this._xformMode == this._ENC_XFORM_MODE) { + // Pad data + padding.pad(this._data, this.blockSize); + + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + + // Unpad data + padding.unpad(finalProcessedBlocks); + } + + return finalProcessedBlocks; + }, + + blockSize: 128/32 + }); + + /** + * A collection of cipher parameters. + * + * @property {WordArray} ciphertext The raw ciphertext. + * @property {WordArray} key The key to this ciphertext. + * @property {WordArray} iv The IV used in the ciphering operation. + * @property {WordArray} salt The salt used with a key derivation function. + * @property {Cipher} algorithm The cipher algorithm. + * @property {Mode} mode The block mode used in the ciphering operation. + * @property {Padding} padding The padding scheme used in the ciphering operation. + * @property {number} blockSize The block size of the cipher. + * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + */ + var CipherParams = C_lib.CipherParams = Base.extend({ + /** + * Initializes a newly created cipher params object. + * + * @param {Object} cipherParams An object with any of the possible cipher parameters. + * + * @example + * + * var cipherParams = CryptoJS.lib.CipherParams.create({ + * ciphertext: ciphertextWordArray, + * key: keyWordArray, + * iv: ivWordArray, + * salt: saltWordArray, + * algorithm: CryptoJS.algo.AES, + * mode: CryptoJS.mode.CBC, + * padding: CryptoJS.pad.PKCS7, + * blockSize: 4, + * formatter: CryptoJS.format.OpenSSL + * }); + */ + init: function (cipherParams) { + this.mixIn(cipherParams); + }, + + /** + * Converts this cipher params object to a string. + * + * @param {Format} formatter (Optional) The formatting strategy to use. + * + * @return {string} The stringified cipher params. + * + * @throws Error If neither the formatter nor the default formatter is set. + * + * @example + * + * var string = cipherParams + ''; + * var string = cipherParams.toString(); + * var string = cipherParams.toString(CryptoJS.format.OpenSSL); + */ + toString: function (formatter) { + return (formatter || this.formatter).stringify(this); + } + }); + + /** + * Format namespace. + */ + var C_format = C.format = {}; + + /** + * OpenSSL formatting strategy. + */ + var OpenSSLFormatter = C_format.OpenSSL = { + /** + * Converts a cipher params object to an OpenSSL-compatible string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The OpenSSL-compatible string. + * + * @static + * + * @example + * + * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); + */ + stringify: function (cipherParams) { + var wordArray; + + // Shortcuts + var ciphertext = cipherParams.ciphertext; + var salt = cipherParams.salt; + + // Format + if (salt) { + wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + } else { + wordArray = ciphertext; + } + + return wordArray.toString(Base64); + }, + + /** + * Converts an OpenSSL-compatible string to a cipher params object. + * + * @param {string} openSSLStr The OpenSSL-compatible string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); + */ + parse: function (openSSLStr) { + var salt; + + // Parse base64 + var ciphertext = Base64.parse(openSSLStr); + + // Shortcut + var ciphertextWords = ciphertext.words; + + // Test for salt + if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { + // Extract salt + salt = WordArray.create(ciphertextWords.slice(2, 4)); + + // Remove salt from ciphertext + ciphertextWords.splice(0, 4); + ciphertext.sigBytes -= 16; + } + + return CipherParams.create({ ciphertext: ciphertext, salt: salt }); + } + }; + + /** + * A cipher wrapper that returns ciphertext as a serializable cipher params object. + */ + var SerializableCipher = C_lib.SerializableCipher = Base.extend({ + /** + * Configuration options. + * + * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL + */ + cfg: Base.extend({ + format: OpenSSLFormatter + }), + + /** + * Encrypts a message. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Encrypt + var encryptor = cipher.createEncryptor(key, cfg); + var ciphertext = encryptor.finalize(message); + + // Shortcut + var cipherCfg = encryptor.cfg; + + // Create and return serializable cipher params + return CipherParams.create({ + ciphertext: ciphertext, + key: key, + iv: cipherCfg.iv, + algorithm: cipher, + mode: cipherCfg.mode, + padding: cipherCfg.padding, + blockSize: cipher.blockSize, + formatter: cfg.format + }); + }, + + /** + * Decrypts serialized ciphertext. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Decrypt + var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); + + return plaintext; + }, + + /** + * Converts serialized ciphertext to CipherParams, + * else assumed CipherParams already and returns ciphertext unchanged. + * + * @param {CipherParams|string} ciphertext The ciphertext. + * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. + * + * @return {CipherParams} The unserialized ciphertext. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); + */ + _parse: function (ciphertext, format) { + if (typeof ciphertext == 'string') { + return format.parse(ciphertext, this); + } else { + return ciphertext; + } + } + }); + + /** + * Key derivation function namespace. + */ + var C_kdf = C.kdf = {}; + + /** + * OpenSSL key derivation function. + */ + var OpenSSLKdf = C_kdf.OpenSSL = { + /** + * Derives a key and IV from a password. + * + * @param {string} password The password to derive from. + * @param {number} keySize The size in words of the key to generate. + * @param {number} ivSize The size in words of the IV to generate. + * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. + * + * @return {CipherParams} A cipher params object with the key, IV, and salt. + * + * @static + * + * @example + * + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); + */ + execute: function (password, keySize, ivSize, salt) { + // Generate random salt + if (!salt) { + salt = WordArray.random(64/8); + } + + // Derive key and IV + var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + + // Separate key and IV + var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); + key.sigBytes = keySize * 4; + + // Return params + return CipherParams.create({ key: key, iv: iv, salt: salt }); + } + }; + + /** + * A serializable cipher wrapper that derives the key from a password, + * and returns ciphertext as a serializable cipher params object. + */ + var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ + /** + * Configuration options. + * + * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL + */ + cfg: SerializableCipher.cfg.extend({ + kdf: OpenSSLKdf + }), + + /** + * Encrypts a message using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Encrypt + var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); + + // Mix in derived params + ciphertext.mixIn(derivedParams); + + return ciphertext; + }, + + /** + * Decrypts serialized ciphertext using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Decrypt + var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); + + return plaintext; + } + }); + }()); + + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/core.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/core.js new file mode 100644 index 0000000..a1c3625 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/core.js @@ -0,0 +1,807 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(); + } + else if (typeof define === "function" && define.amd) { + // AMD + define([], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(); + } +}(this, function () { + + /*globals window, global, require*/ + + /** + * CryptoJS core components. + */ + var CryptoJS = CryptoJS || (function (Math, undefined) { + + var crypto; + + // Native crypto from window (Browser) + if (typeof window !== 'undefined' && window.crypto) { + crypto = window.crypto; + } + + // Native crypto in web worker (Browser) + if (typeof self !== 'undefined' && self.crypto) { + crypto = self.crypto; + } + + // Native crypto from worker + if (typeof globalThis !== 'undefined' && globalThis.crypto) { + crypto = globalThis.crypto; + } + + // Native (experimental IE 11) crypto from window (Browser) + if (!crypto && typeof window !== 'undefined' && window.msCrypto) { + crypto = window.msCrypto; + } + + // Native crypto from global (NodeJS) + if (!crypto && typeof global !== 'undefined' && global.crypto) { + crypto = global.crypto; + } + + // Native crypto import via require (NodeJS) + if (!crypto && typeof require === 'function') { + try { + crypto = require('crypto'); + } catch (err) {} + } + + /* + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var cryptoSecureRandomInt = function () { + if (crypto) { + // Use getRandomValues method (Browser) + if (typeof crypto.getRandomValues === 'function') { + try { + return crypto.getRandomValues(new Uint32Array(1))[0]; + } catch (err) {} + } + + // Use randomBytes method (NodeJS) + if (typeof crypto.randomBytes === 'function') { + try { + return crypto.randomBytes(4).readInt32LE(); + } catch (err) {} + } + } + + throw new Error('Native crypto module could not be used to get secure random number.'); + }; + + /* + * Local polyfill of Object.create + + */ + var create = Object.create || (function () { + function F() {} + + return function (obj) { + var subtype; + + F.prototype = obj; + + subtype = new F(); + + F.prototype = null; + + return subtype; + }; + }()); + + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + var subtype = create(this); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else { + // Copy one word at a time + for (var j = 0; j < thatSigBytes; j += 4) { + thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]; + } + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + + for (var i = 0; i < nBytes; i += 4) { + words.push(cryptoSecureRandomInt()); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + var processedWords; + + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; + }(Math)); + + + return CryptoJS; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/crypto-js.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/crypto-js.js new file mode 100644 index 0000000..70fe18c --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/crypto-js.js @@ -0,0 +1,6191 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(); + } + else if (typeof define === "function" && define.amd) { + // AMD + define([], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(); + } +}(this, function () { + + /*globals window, global, require*/ + + /** + * CryptoJS core components. + */ + var CryptoJS = CryptoJS || (function (Math, undefined) { + + var crypto; + + // Native crypto from window (Browser) + if (typeof window !== 'undefined' && window.crypto) { + crypto = window.crypto; + } + + // Native crypto in web worker (Browser) + if (typeof self !== 'undefined' && self.crypto) { + crypto = self.crypto; + } + + // Native crypto from worker + if (typeof globalThis !== 'undefined' && globalThis.crypto) { + crypto = globalThis.crypto; + } + + // Native (experimental IE 11) crypto from window (Browser) + if (!crypto && typeof window !== 'undefined' && window.msCrypto) { + crypto = window.msCrypto; + } + + // Native crypto from global (NodeJS) + if (!crypto && typeof global !== 'undefined' && global.crypto) { + crypto = global.crypto; + } + + // Native crypto import via require (NodeJS) + if (!crypto && typeof require === 'function') { + try { + crypto = require('crypto'); + } catch (err) {} + } + + /* + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var cryptoSecureRandomInt = function () { + if (crypto) { + // Use getRandomValues method (Browser) + if (typeof crypto.getRandomValues === 'function') { + try { + return crypto.getRandomValues(new Uint32Array(1))[0]; + } catch (err) {} + } + + // Use randomBytes method (NodeJS) + if (typeof crypto.randomBytes === 'function') { + try { + return crypto.randomBytes(4).readInt32LE(); + } catch (err) {} + } + } + + throw new Error('Native crypto module could not be used to get secure random number.'); + }; + + /* + * Local polyfill of Object.create + + */ + var create = Object.create || (function () { + function F() {} + + return function (obj) { + var subtype; + + F.prototype = obj; + + subtype = new F(); + + F.prototype = null; + + return subtype; + }; + }()); + + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + var subtype = create(this); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else { + // Copy one word at a time + for (var j = 0; j < thatSigBytes; j += 4) { + thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]; + } + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + + for (var i = 0; i < nBytes; i += 4) { + words.push(cryptoSecureRandomInt()); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + var processedWords; + + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; + }(Math)); + + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var X32WordArray = C_lib.WordArray; + + /** + * x64 namespace. + */ + var C_x64 = C.x64 = {}; + + /** + * A 64-bit word. + */ + var X64Word = C_x64.Word = Base.extend({ + /** + * Initializes a newly created 64-bit word. + * + * @param {number} high The high 32 bits. + * @param {number} low The low 32 bits. + * + * @example + * + * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); + */ + init: function (high, low) { + this.high = high; + this.low = low; + } + + /** + * Bitwise NOTs this word. + * + * @return {X64Word} A new x64-Word object after negating. + * + * @example + * + * var negated = x64Word.not(); + */ + // not: function () { + // var high = ~this.high; + // var low = ~this.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ANDs this word with the passed word. + * + * @param {X64Word} word The x64-Word to AND with this word. + * + * @return {X64Word} A new x64-Word object after ANDing. + * + * @example + * + * var anded = x64Word.and(anotherX64Word); + */ + // and: function (word) { + // var high = this.high & word.high; + // var low = this.low & word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to OR with this word. + * + * @return {X64Word} A new x64-Word object after ORing. + * + * @example + * + * var ored = x64Word.or(anotherX64Word); + */ + // or: function (word) { + // var high = this.high | word.high; + // var low = this.low | word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise XORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to XOR with this word. + * + * @return {X64Word} A new x64-Word object after XORing. + * + * @example + * + * var xored = x64Word.xor(anotherX64Word); + */ + // xor: function (word) { + // var high = this.high ^ word.high; + // var low = this.low ^ word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the left. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftL(25); + */ + // shiftL: function (n) { + // if (n < 32) { + // var high = (this.high << n) | (this.low >>> (32 - n)); + // var low = this.low << n; + // } else { + // var high = this.low << (n - 32); + // var low = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the right. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftR(7); + */ + // shiftR: function (n) { + // if (n < 32) { + // var low = (this.low >>> n) | (this.high << (32 - n)); + // var high = this.high >>> n; + // } else { + // var low = this.high >>> (n - 32); + // var high = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Rotates this word n bits to the left. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotL(25); + */ + // rotL: function (n) { + // return this.shiftL(n).or(this.shiftR(64 - n)); + // }, + + /** + * Rotates this word n bits to the right. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotR(7); + */ + // rotR: function (n) { + // return this.shiftR(n).or(this.shiftL(64 - n)); + // }, + + /** + * Adds this word with the passed word. + * + * @param {X64Word} word The x64-Word to add with this word. + * + * @return {X64Word} A new x64-Word object after adding. + * + * @example + * + * var added = x64Word.add(anotherX64Word); + */ + // add: function (word) { + // var low = (this.low + word.low) | 0; + // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; + // var high = (this.high + word.high + carry) | 0; + + // return X64Word.create(high, low); + // } + }); + + /** + * An array of 64-bit words. + * + * @property {Array} words The array of CryptoJS.x64.Word objects. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var X64WordArray = C_x64.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.x64.WordArray.create(); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ]); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ], 10); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 8; + } + }, + + /** + * Converts this 64-bit word array to a 32-bit word array. + * + * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. + * + * @example + * + * var x32WordArray = x64WordArray.toX32(); + */ + toX32: function () { + // Shortcuts + var x64Words = this.words; + var x64WordsLength = x64Words.length; + + // Convert + var x32Words = []; + for (var i = 0; i < x64WordsLength; i++) { + var x64Word = x64Words[i]; + x32Words.push(x64Word.high); + x32Words.push(x64Word.low); + } + + return X32WordArray.create(x32Words, this.sigBytes); + }, + + /** + * Creates a copy of this word array. + * + * @return {X64WordArray} The clone. + * + * @example + * + * var clone = x64WordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + + // Clone "words" array + var words = clone.words = this.words.slice(0); + + // Clone each X64Word object + var wordsLength = words.length; + for (var i = 0; i < wordsLength; i++) { + words[i] = words[i].clone(); + } + + return clone; + } + }); + }()); + + + (function () { + // Check if typed arrays are supported + if (typeof ArrayBuffer != 'function') { + return; + } + + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + + // Reference original init + var superInit = WordArray.init; + + // Augment WordArray.init to handle typed arrays + var subInit = WordArray.init = function (typedArray) { + // Convert buffers to uint8 + if (typedArray instanceof ArrayBuffer) { + typedArray = new Uint8Array(typedArray); + } + + // Convert other array views to uint8 + if ( + typedArray instanceof Int8Array || + (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) || + typedArray instanceof Int16Array || + typedArray instanceof Uint16Array || + typedArray instanceof Int32Array || + typedArray instanceof Uint32Array || + typedArray instanceof Float32Array || + typedArray instanceof Float64Array + ) { + typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); + } + + // Handle Uint8Array + if (typedArray instanceof Uint8Array) { + // Shortcut + var typedArrayByteLength = typedArray.byteLength; + + // Extract bytes + var words = []; + for (var i = 0; i < typedArrayByteLength; i++) { + words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); + } + + // Initialize this word array + superInit.call(this, words, typedArrayByteLength); + } else { + // Else call normal init + superInit.apply(this, arguments); + } + }; + + subInit.prototype = WordArray; + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * UTF-16 BE encoding strategy. + */ + var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = { + /** + * Converts a word array to a UTF-16 BE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 BE string. + * + * @static + * + * @example + * + * var utf16String = CryptoJS.enc.Utf16.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff; + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 BE string to a word array. + * + * @param {string} utf16Str The UTF-16 BE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16.parse(utf16String); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + /** + * UTF-16 LE encoding strategy. + */ + C_enc.Utf16LE = { + /** + * Converts a word array to a UTF-16 LE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 LE string. + * + * @static + * + * @example + * + * var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff); + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 LE string to a word array. + * + * @param {string} utf16Str The UTF-16 LE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16)); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + function swapEndian(word) { + return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff); + } + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + var Base64 = C_enc.Base64 = { + /** + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64url encoding strategy. + */ + var Base64url = C_enc.Base64url = { + /** + * Converts a word array to a Base64url string. + * + * @param {WordArray} wordArray The word array. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {string} The Base64url string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64url.stringify(wordArray); + */ + stringify: function (wordArray, urlSafe=true) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = urlSafe ? this._safe_map : this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64url string to a word array. + * + * @param {string} base64Str The Base64url string. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64url.parse(base64String); + */ + parse: function (base64Str, urlSafe=true) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = urlSafe ? this._safe_map : this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var T = []; + + // Compute constants + (function () { + for (var i = 0; i < 64; i++) { + T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + } + }()); + + /** + * MD5 hash algorithm. + */ + var MD5 = C_algo.MD5 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + + // Shortcuts + var H = this._hash.words; + + var M_offset_0 = M[offset + 0]; + var M_offset_1 = M[offset + 1]; + var M_offset_2 = M[offset + 2]; + var M_offset_3 = M[offset + 3]; + var M_offset_4 = M[offset + 4]; + var M_offset_5 = M[offset + 5]; + var M_offset_6 = M[offset + 6]; + var M_offset_7 = M[offset + 7]; + var M_offset_8 = M[offset + 8]; + var M_offset_9 = M[offset + 9]; + var M_offset_10 = M[offset + 10]; + var M_offset_11 = M[offset + 11]; + var M_offset_12 = M[offset + 12]; + var M_offset_13 = M[offset + 13]; + var M_offset_14 = M[offset + 14]; + var M_offset_15 = M[offset + 15]; + + // Working varialbes + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + + // Computation + a = FF(a, b, c, d, M_offset_0, 7, T[0]); + d = FF(d, a, b, c, M_offset_1, 12, T[1]); + c = FF(c, d, a, b, M_offset_2, 17, T[2]); + b = FF(b, c, d, a, M_offset_3, 22, T[3]); + a = FF(a, b, c, d, M_offset_4, 7, T[4]); + d = FF(d, a, b, c, M_offset_5, 12, T[5]); + c = FF(c, d, a, b, M_offset_6, 17, T[6]); + b = FF(b, c, d, a, M_offset_7, 22, T[7]); + a = FF(a, b, c, d, M_offset_8, 7, T[8]); + d = FF(d, a, b, c, M_offset_9, 12, T[9]); + c = FF(c, d, a, b, M_offset_10, 17, T[10]); + b = FF(b, c, d, a, M_offset_11, 22, T[11]); + a = FF(a, b, c, d, M_offset_12, 7, T[12]); + d = FF(d, a, b, c, M_offset_13, 12, T[13]); + c = FF(c, d, a, b, M_offset_14, 17, T[14]); + b = FF(b, c, d, a, M_offset_15, 22, T[15]); + + a = GG(a, b, c, d, M_offset_1, 5, T[16]); + d = GG(d, a, b, c, M_offset_6, 9, T[17]); + c = GG(c, d, a, b, M_offset_11, 14, T[18]); + b = GG(b, c, d, a, M_offset_0, 20, T[19]); + a = GG(a, b, c, d, M_offset_5, 5, T[20]); + d = GG(d, a, b, c, M_offset_10, 9, T[21]); + c = GG(c, d, a, b, M_offset_15, 14, T[22]); + b = GG(b, c, d, a, M_offset_4, 20, T[23]); + a = GG(a, b, c, d, M_offset_9, 5, T[24]); + d = GG(d, a, b, c, M_offset_14, 9, T[25]); + c = GG(c, d, a, b, M_offset_3, 14, T[26]); + b = GG(b, c, d, a, M_offset_8, 20, T[27]); + a = GG(a, b, c, d, M_offset_13, 5, T[28]); + d = GG(d, a, b, c, M_offset_2, 9, T[29]); + c = GG(c, d, a, b, M_offset_7, 14, T[30]); + b = GG(b, c, d, a, M_offset_12, 20, T[31]); + + a = HH(a, b, c, d, M_offset_5, 4, T[32]); + d = HH(d, a, b, c, M_offset_8, 11, T[33]); + c = HH(c, d, a, b, M_offset_11, 16, T[34]); + b = HH(b, c, d, a, M_offset_14, 23, T[35]); + a = HH(a, b, c, d, M_offset_1, 4, T[36]); + d = HH(d, a, b, c, M_offset_4, 11, T[37]); + c = HH(c, d, a, b, M_offset_7, 16, T[38]); + b = HH(b, c, d, a, M_offset_10, 23, T[39]); + a = HH(a, b, c, d, M_offset_13, 4, T[40]); + d = HH(d, a, b, c, M_offset_0, 11, T[41]); + c = HH(c, d, a, b, M_offset_3, 16, T[42]); + b = HH(b, c, d, a, M_offset_6, 23, T[43]); + a = HH(a, b, c, d, M_offset_9, 4, T[44]); + d = HH(d, a, b, c, M_offset_12, 11, T[45]); + c = HH(c, d, a, b, M_offset_15, 16, T[46]); + b = HH(b, c, d, a, M_offset_2, 23, T[47]); + + a = II(a, b, c, d, M_offset_0, 6, T[48]); + d = II(d, a, b, c, M_offset_7, 10, T[49]); + c = II(c, d, a, b, M_offset_14, 15, T[50]); + b = II(b, c, d, a, M_offset_5, 21, T[51]); + a = II(a, b, c, d, M_offset_12, 6, T[52]); + d = II(d, a, b, c, M_offset_3, 10, T[53]); + c = II(c, d, a, b, M_offset_10, 15, T[54]); + b = II(b, c, d, a, M_offset_1, 21, T[55]); + a = II(a, b, c, d, M_offset_8, 6, T[56]); + d = II(d, a, b, c, M_offset_15, 10, T[57]); + c = II(c, d, a, b, M_offset_6, 15, T[58]); + b = II(b, c, d, a, M_offset_13, 21, T[59]); + a = II(a, b, c, d, M_offset_4, 6, T[60]); + d = II(d, a, b, c, M_offset_11, 10, T[61]); + c = II(c, d, a, b, M_offset_2, 15, T[62]); + b = II(b, c, d, a, M_offset_9, 21, T[63]); + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + + var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); + var nBitsTotalL = nBitsTotal; + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( + (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | + (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) + ); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | + (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) + ); + + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 4; i++) { + // Shortcut + var H_i = H[i]; + + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + function FF(a, b, c, d, x, s, t) { + var n = a + ((b & c) | (~b & d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function GG(a, b, c, d, x, s, t) { + var n = a + ((b & d) | (c & ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function HH(a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function II(a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.MD5('message'); + * var hash = CryptoJS.MD5(wordArray); + */ + C.MD5 = Hasher._createHelper(MD5); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacMD5(message, key); + */ + C.HmacMD5 = Hasher._createHmacHelper(MD5); + }(Math)); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Reusable object + var W = []; + + /** + * SHA-1 hash algorithm. + */ + var SHA1 = C_algo.SHA1 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + // Computation + for (var i = 0; i < 80; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = (n << 1) | (n >>> 31); + } + + var t = ((a << 5) | (a >>> 27)) + e + W[i]; + if (i < 20) { + t += ((b & c) | (~b & d)) + 0x5a827999; + } else if (i < 40) { + t += (b ^ c ^ d) + 0x6ed9eba1; + } else if (i < 60) { + t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; + } else /* if (i < 80) */ { + t += (b ^ c ^ d) - 0x359d3e2a; + } + + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA1('message'); + * var hash = CryptoJS.SHA1(wordArray); + */ + C.SHA1 = Hasher._createHelper(SHA1); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA1(message, key); + */ + C.HmacSHA1 = Hasher._createHmacHelper(SHA1); + }()); + + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + + /** + * SHA-224 hash algorithm. + */ + var SHA224 = C_algo.SHA224 = SHA256.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]); + }, + + _doFinalize: function () { + var hash = SHA256._doFinalize.call(this); + + hash.sigBytes -= 4; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA224('message'); + * var hash = CryptoJS.SHA224(wordArray); + */ + C.SHA224 = SHA256._createHelper(SHA224); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA224(message, key); + */ + C.HmacSHA224 = SHA256._createHmacHelper(SHA224); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + + function X64Word_create() { + return X64Word.create.apply(X64Word, arguments); + } + + // Constants + var K = [ + X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), + X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), + X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), + X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), + X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), + X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), + X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), + X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), + X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), + X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), + X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), + X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), + X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), + X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), + X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), + X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), + X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), + X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), + X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), + X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), + X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), + X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), + X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), + X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), + X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), + X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), + X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), + X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), + X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), + X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), + X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), + X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), + X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), + X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), + X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), + X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), + X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), + X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), + X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), + X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) + ]; + + // Reusable objects + var W = []; + (function () { + for (var i = 0; i < 80; i++) { + W[i] = X64Word_create(); + } + }()); + + /** + * SHA-512 hash algorithm. + */ + var SHA512 = C_algo.SHA512 = Hasher.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), + new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), + new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), + new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var H = this._hash.words; + + var H0 = H[0]; + var H1 = H[1]; + var H2 = H[2]; + var H3 = H[3]; + var H4 = H[4]; + var H5 = H[5]; + var H6 = H[6]; + var H7 = H[7]; + + var H0h = H0.high; + var H0l = H0.low; + var H1h = H1.high; + var H1l = H1.low; + var H2h = H2.high; + var H2l = H2.low; + var H3h = H3.high; + var H3l = H3.low; + var H4h = H4.high; + var H4l = H4.low; + var H5h = H5.high; + var H5l = H5.low; + var H6h = H6.high; + var H6l = H6.low; + var H7h = H7.high; + var H7l = H7.low; + + // Working variables + var ah = H0h; + var al = H0l; + var bh = H1h; + var bl = H1l; + var ch = H2h; + var cl = H2l; + var dh = H3h; + var dl = H3l; + var eh = H4h; + var el = H4l; + var fh = H5h; + var fl = H5l; + var gh = H6h; + var gl = H6l; + var hh = H7h; + var hl = H7l; + + // Rounds + for (var i = 0; i < 80; i++) { + var Wil; + var Wih; + + // Shortcut + var Wi = W[i]; + + // Extend message + if (i < 16) { + Wih = Wi.high = M[offset + i * 2] | 0; + Wil = Wi.low = M[offset + i * 2 + 1] | 0; + } else { + // Gamma0 + var gamma0x = W[i - 15]; + var gamma0xh = gamma0x.high; + var gamma0xl = gamma0x.low; + var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); + var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); + + // Gamma1 + var gamma1x = W[i - 2]; + var gamma1xh = gamma1x.high; + var gamma1xl = gamma1x.low; + var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); + var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7 = W[i - 7]; + var Wi7h = Wi7.high; + var Wi7l = Wi7.low; + + var Wi16 = W[i - 16]; + var Wi16h = Wi16.high; + var Wi16l = Wi16.low; + + Wil = gamma0l + Wi7l; + Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + Wil = Wil + gamma1l; + Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + Wil = Wil + Wi16l; + Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + + Wi.high = Wih; + Wi.low = Wil; + } + + var chh = (eh & fh) ^ (~eh & gh); + var chl = (el & fl) ^ (~el & gl); + var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); + var majl = (al & bl) ^ (al & cl) ^ (bl & cl); + + var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); + var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); + var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); + var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); + + // t1 = h + sigma1 + ch + K[i] + W[i] + var Ki = K[i]; + var Kih = Ki.high; + var Kil = Ki.low; + + var t1l = hl + sigma1l; + var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); + var t1l = t1l + chl; + var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); + var t1l = t1l + Kil; + var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); + var t1l = t1l + Wil; + var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); + + // t2 = sigma0 + maj + var t2l = sigma0l + majl; + var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); + + // Update working variables + hh = gh; + hl = gl; + gh = fh; + gl = fl; + fh = eh; + fl = el; + el = (dl + t1l) | 0; + eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; + dh = ch; + dl = cl; + ch = bh; + cl = bl; + bh = ah; + bl = al; + al = (t1l + t2l) | 0; + ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; + } + + // Intermediate hash value + H0l = H0.low = (H0l + al); + H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); + H1l = H1.low = (H1l + bl); + H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); + H2l = H2.low = (H2l + cl); + H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); + H3l = H3.low = (H3l + dl); + H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); + H4l = H4.low = (H4l + el); + H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); + H5l = H5.low = (H5l + fl); + H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); + H6l = H6.low = (H6l + gl); + H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); + H7l = H7.low = (H7l + hl); + H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Convert hash to 32-bit word array before returning + var hash = this._hash.toX32(); + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + + blockSize: 1024/32 + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA512('message'); + * var hash = CryptoJS.SHA512(wordArray); + */ + C.SHA512 = Hasher._createHelper(SHA512); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA512(message, key); + */ + C.HmacSHA512 = Hasher._createHmacHelper(SHA512); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + var SHA512 = C_algo.SHA512; + + /** + * SHA-384 hash algorithm. + */ + var SHA384 = C_algo.SHA384 = SHA512.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507), + new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939), + new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511), + new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4) + ]); + }, + + _doFinalize: function () { + var hash = SHA512._doFinalize.call(this); + + hash.sigBytes -= 16; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA384('message'); + * var hash = CryptoJS.SHA384(wordArray); + */ + C.SHA384 = SHA512._createHelper(SHA384); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA384(message, key); + */ + C.HmacSHA384 = SHA512._createHmacHelper(SHA384); + }()); + + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var C_algo = C.algo; + + // Constants tables + var RHO_OFFSETS = []; + var PI_INDEXES = []; + var ROUND_CONSTANTS = []; + + // Compute Constants + (function () { + // Compute rho offset constants + var x = 1, y = 0; + for (var t = 0; t < 24; t++) { + RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64; + + var newX = y % 5; + var newY = (2 * x + 3 * y) % 5; + x = newX; + y = newY; + } + + // Compute pi index constants + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5; + } + } + + // Compute round constants + var LFSR = 0x01; + for (var i = 0; i < 24; i++) { + var roundConstantMsw = 0; + var roundConstantLsw = 0; + + for (var j = 0; j < 7; j++) { + if (LFSR & 0x01) { + var bitPosition = (1 << j) - 1; + if (bitPosition < 32) { + roundConstantLsw ^= 1 << bitPosition; + } else /* if (bitPosition >= 32) */ { + roundConstantMsw ^= 1 << (bitPosition - 32); + } + } + + // Compute next LFSR + if (LFSR & 0x80) { + // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1 + LFSR = (LFSR << 1) ^ 0x71; + } else { + LFSR <<= 1; + } + } + + ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw); + } + }()); + + // Reusable objects for temporary values + var T = []; + (function () { + for (var i = 0; i < 25; i++) { + T[i] = X64Word.create(); + } + }()); + + /** + * SHA-3 hash algorithm. + */ + var SHA3 = C_algo.SHA3 = Hasher.extend({ + /** + * Configuration options. + * + * @property {number} outputLength + * The desired number of bits in the output hash. + * Only values permitted are: 224, 256, 384, 512. + * Default: 512 + */ + cfg: Hasher.cfg.extend({ + outputLength: 512 + }), + + _doReset: function () { + var state = this._state = [] + for (var i = 0; i < 25; i++) { + state[i] = new X64Word.init(); + } + + this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32; + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var state = this._state; + var nBlockSizeLanes = this.blockSize / 2; + + // Absorb + for (var i = 0; i < nBlockSizeLanes; i++) { + // Shortcuts + var M2i = M[offset + 2 * i]; + var M2i1 = M[offset + 2 * i + 1]; + + // Swap endian + M2i = ( + (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | + (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00) + ); + M2i1 = ( + (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | + (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00) + ); + + // Absorb message into state + var lane = state[i]; + lane.high ^= M2i1; + lane.low ^= M2i; + } + + // Rounds + for (var round = 0; round < 24; round++) { + // Theta + for (var x = 0; x < 5; x++) { + // Mix column lanes + var tMsw = 0, tLsw = 0; + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + tMsw ^= lane.high; + tLsw ^= lane.low; + } + + // Temporary values + var Tx = T[x]; + Tx.high = tMsw; + Tx.low = tLsw; + } + for (var x = 0; x < 5; x++) { + // Shortcuts + var Tx4 = T[(x + 4) % 5]; + var Tx1 = T[(x + 1) % 5]; + var Tx1Msw = Tx1.high; + var Tx1Lsw = Tx1.low; + + // Mix surrounding columns + var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31)); + var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31)); + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + lane.high ^= tMsw; + lane.low ^= tLsw; + } + } + + // Rho Pi + for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + + // Shortcuts + var lane = state[laneIndex]; + var laneMsw = lane.high; + var laneLsw = lane.low; + var rhoOffset = RHO_OFFSETS[laneIndex]; + + // Rotate lanes + if (rhoOffset < 32) { + tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + } else /* if (rhoOffset >= 32) */ { + tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + } + + // Transpose lanes + var TPiLane = T[PI_INDEXES[laneIndex]]; + TPiLane.high = tMsw; + TPiLane.low = tLsw; + } + + // Rho pi at x = y = 0 + var T0 = T[0]; + var state0 = state[0]; + T0.high = state0.high; + T0.low = state0.low; + + // Chi + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + // Shortcuts + var laneIndex = x + 5 * y; + var lane = state[laneIndex]; + var TLane = T[laneIndex]; + var Tx1Lane = T[((x + 1) % 5) + 5 * y]; + var Tx2Lane = T[((x + 2) % 5) + 5 * y]; + + // Mix rows + lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high); + lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low); + } + } + + // Iota + var lane = state[0]; + var roundConstant = ROUND_CONSTANTS[round]; + lane.high ^= roundConstant.high; + lane.low ^= roundConstant.low; + } + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + var blockSizeBits = this.blockSize * 32; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32); + dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var state = this._state; + var outputLengthBytes = this.cfg.outputLength / 8; + var outputLengthLanes = outputLengthBytes / 8; + + // Squeeze + var hashWords = []; + for (var i = 0; i < outputLengthLanes; i++) { + // Shortcuts + var lane = state[i]; + var laneMsw = lane.high; + var laneLsw = lane.low; + + // Swap endian + laneMsw = ( + (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | + (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00) + ); + laneLsw = ( + (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | + (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00) + ); + + // Squeeze state to retrieve hash + hashWords.push(laneLsw); + hashWords.push(laneMsw); + } + + // Return final computed hash + return new WordArray.init(hashWords, outputLengthBytes); + }, + + clone: function () { + var clone = Hasher.clone.call(this); + + var state = clone._state = this._state.slice(0); + for (var i = 0; i < 25; i++) { + state[i] = state[i].clone(); + } + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA3('message'); + * var hash = CryptoJS.SHA3(wordArray); + */ + C.SHA3 = Hasher._createHelper(SHA3); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA3(message, key); + */ + C.HmacSHA3 = Hasher._createHmacHelper(SHA3); + }(Math)); + + + /** @preserve + (c) 2012 by Cédric Mesnil. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var _zl = WordArray.create([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13]); + var _zr = WordArray.create([ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]); + var _sl = WordArray.create([ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ]); + var _sr = WordArray.create([ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ]); + + var _hl = WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]); + var _hr = WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]); + + /** + * RIPEMD160 hash algorithm. + */ + var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({ + _doReset: function () { + this._hash = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]); + }, + + _doProcessBlock: function (M, offset) { + + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + // Swap + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + // Shortcut + var H = this._hash.words; + var hl = _hl.words; + var hr = _hr.words; + var zl = _zl.words; + var zr = _zr.words; + var sl = _sl.words; + var sr = _sr.words; + + // Working variables + var al, bl, cl, dl, el; + var ar, br, cr, dr, er; + + ar = al = H[0]; + br = bl = H[1]; + cr = cl = H[2]; + dr = dl = H[3]; + er = el = H[4]; + // Computation + var t; + for (var i = 0; i < 80; i += 1) { + t = (al + M[offset+zl[i]])|0; + if (i<16){ + t += f1(bl,cl,dl) + hl[0]; + } else if (i<32) { + t += f2(bl,cl,dl) + hl[1]; + } else if (i<48) { + t += f3(bl,cl,dl) + hl[2]; + } else if (i<64) { + t += f4(bl,cl,dl) + hl[3]; + } else {// if (i<80) { + t += f5(bl,cl,dl) + hl[4]; + } + t = t|0; + t = rotl(t,sl[i]); + t = (t+el)|0; + al = el; + el = dl; + dl = rotl(cl, 10); + cl = bl; + bl = t; + + t = (ar + M[offset+zr[i]])|0; + if (i<16){ + t += f5(br,cr,dr) + hr[0]; + } else if (i<32) { + t += f4(br,cr,dr) + hr[1]; + } else if (i<48) { + t += f3(br,cr,dr) + hr[2]; + } else if (i<64) { + t += f2(br,cr,dr) + hr[3]; + } else {// if (i<80) { + t += f1(br,cr,dr) + hr[4]; + } + t = t|0; + t = rotl(t,sr[i]) ; + t = (t+er)|0; + ar = er; + er = dr; + dr = rotl(cr, 10); + cr = br; + br = t; + } + // Intermediate hash value + t = (H[1] + cl + dr)|0; + H[1] = (H[2] + dl + er)|0; + H[2] = (H[3] + el + ar)|0; + H[3] = (H[4] + al + br)|0; + H[4] = (H[0] + bl + cr)|0; + H[0] = t; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) | + (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00) + ); + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 5; i++) { + // Shortcut + var H_i = H[i]; + + // Swap + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + + function f1(x, y, z) { + return ((x) ^ (y) ^ (z)); + + } + + function f2(x, y, z) { + return (((x)&(y)) | ((~x)&(z))); + } + + function f3(x, y, z) { + return (((x) | (~(y))) ^ (z)); + } + + function f4(x, y, z) { + return (((x) & (z)) | ((y)&(~(z)))); + } + + function f5(x, y, z) { + return ((x) ^ ((y) |(~(z)))); + + } + + function rotl(x,n) { + return (x<>>(32-n)); + } + + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.RIPEMD160('message'); + * var hash = CryptoJS.RIPEMD160(wordArray); + */ + C.RIPEMD160 = Hasher._createHelper(RIPEMD160); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacRIPEMD160(message, key); + */ + C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160); + }(Math)); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var C_algo = C.algo; + + /** + * HMAC algorithm. + */ + var HMAC = C_algo.HMAC = Base.extend({ + /** + * Initializes a newly created HMAC. + * + * @param {Hasher} hasher The hash algorithm to use. + * @param {WordArray|string} key The secret key. + * + * @example + * + * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + */ + init: function (hasher, key) { + // Init hasher + hasher = this._hasher = new hasher.init(); + + // Convert string to WordArray, else assume WordArray already + if (typeof key == 'string') { + key = Utf8.parse(key); + } + + // Shortcuts + var hasherBlockSize = hasher.blockSize; + var hasherBlockSizeBytes = hasherBlockSize * 4; + + // Allow arbitrary length keys + if (key.sigBytes > hasherBlockSizeBytes) { + key = hasher.finalize(key); + } + + // Clamp excess bits + key.clamp(); + + // Clone key for inner and outer pads + var oKey = this._oKey = key.clone(); + var iKey = this._iKey = key.clone(); + + // Shortcuts + var oKeyWords = oKey.words; + var iKeyWords = iKey.words; + + // XOR keys with pad constants + for (var i = 0; i < hasherBlockSize; i++) { + oKeyWords[i] ^= 0x5c5c5c5c; + iKeyWords[i] ^= 0x36363636; + } + oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes; + + // Set initial values + this.reset(); + }, + + /** + * Resets this HMAC to its initial state. + * + * @example + * + * hmacHasher.reset(); + */ + reset: function () { + // Shortcut + var hasher = this._hasher; + + // Reset + hasher.reset(); + hasher.update(this._iKey); + }, + + /** + * Updates this HMAC with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {HMAC} This HMAC instance. + * + * @example + * + * hmacHasher.update('message'); + * hmacHasher.update(wordArray); + */ + update: function (messageUpdate) { + this._hasher.update(messageUpdate); + + // Chainable + return this; + }, + + /** + * Finalizes the HMAC computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The HMAC. + * + * @example + * + * var hmac = hmacHasher.finalize(); + * var hmac = hmacHasher.finalize('message'); + * var hmac = hmacHasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Shortcut + var hasher = this._hasher; + + // Compute HMAC + var innerHash = hasher.finalize(messageUpdate); + hasher.reset(); + var hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); + + return hmac; + } + }); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA1 = C_algo.SHA1; + var HMAC = C_algo.HMAC; + + /** + * Password-Based Key Derivation Function 2 algorithm. + */ + var PBKDF2 = C_algo.PBKDF2 = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hasher to use. Default: SHA1 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: SHA1, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.PBKDF2.create(); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + var cfg = this.cfg; + + // Init HMAC + var hmac = HMAC.create(cfg.hasher, password); + + // Initial values + var derivedKey = WordArray.create(); + var blockIndex = WordArray.create([0x00000001]); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var blockIndexWords = blockIndex.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + var block = hmac.update(salt).finalize(blockIndex); + hmac.reset(); + + // Shortcuts + var blockWords = block.words; + var blockWordsLength = blockWords.length; + + // Iterations + var intermediate = block; + for (var i = 1; i < iterations; i++) { + intermediate = hmac.finalize(intermediate); + hmac.reset(); + + // Shortcut + var intermediateWords = intermediate.words; + + // XOR intermediate with block + for (var j = 0; j < blockWordsLength; j++) { + blockWords[j] ^= intermediateWords[j]; + } + } + + derivedKey.concat(block); + blockIndexWords[0]++; + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.PBKDF2(password, salt); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.PBKDF2 = function (password, salt, cfg) { + return PBKDF2.create(cfg).compute(password, salt); + }; + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var MD5 = C_algo.MD5; + + /** + * This key derivation function is meant to conform with EVP_BytesToKey. + * www.openssl.org/docs/crypto/EVP_BytesToKey.html + */ + var EvpKDF = C_algo.EvpKDF = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hash algorithm to use. Default: MD5 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: MD5, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.EvpKDF.create(); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + var block; + + // Shortcut + var cfg = this.cfg; + + // Init hasher + var hasher = cfg.hasher.create(); + + // Initial values + var derivedKey = WordArray.create(); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + if (block) { + hasher.update(block); + } + block = hasher.update(password).finalize(salt); + hasher.reset(); + + // Iterations + for (var i = 1; i < iterations; i++) { + block = hasher.finalize(block); + hasher.reset(); + } + + derivedKey.concat(block); + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.EvpKDF(password, salt); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.EvpKDF = function (password, salt, cfg) { + return EvpKDF.create(cfg).compute(password, salt); + }; + }()); + + + /** + * Cipher core components. + */ + CryptoJS.lib.Cipher || (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var Base64 = C_enc.Base64; + var C_algo = C.algo; + var EvpKDF = C_algo.EvpKDF; + + /** + * Abstract base cipher template. + * + * @property {number} keySize This cipher's key size. Default: 4 (128 bits) + * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) + * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. + * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. + */ + var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + * + * @property {WordArray} iv The IV to use for this operation. + */ + cfg: Base.extend(), + + /** + * Creates this cipher in encryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); + */ + createEncryptor: function (key, cfg) { + return this.create(this._ENC_XFORM_MODE, key, cfg); + }, + + /** + * Creates this cipher in decryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); + */ + createDecryptor: function (key, cfg) { + return this.create(this._DEC_XFORM_MODE, key, cfg); + }, + + /** + * Initializes a newly created cipher. + * + * @param {number} xformMode Either the encryption or decryption transormation mode constant. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @example + * + * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); + */ + init: function (xformMode, key, cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Store transform mode and key + this._xformMode = xformMode; + this._key = key; + + // Set initial values + this.reset(); + }, + + /** + * Resets this cipher to its initial state. + * + * @example + * + * cipher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-cipher logic + this._doReset(); + }, + + /** + * Adds data to be encrypted or decrypted. + * + * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. + * + * @return {WordArray} The data after processing. + * + * @example + * + * var encrypted = cipher.process('data'); + * var encrypted = cipher.process(wordArray); + */ + process: function (dataUpdate) { + // Append + this._append(dataUpdate); + + // Process available blocks + return this._process(); + }, + + /** + * Finalizes the encryption or decryption process. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. + * + * @return {WordArray} The data after final processing. + * + * @example + * + * var encrypted = cipher.finalize(); + * var encrypted = cipher.finalize('data'); + * var encrypted = cipher.finalize(wordArray); + */ + finalize: function (dataUpdate) { + // Final data update + if (dataUpdate) { + this._append(dataUpdate); + } + + // Perform concrete-cipher logic + var finalProcessedData = this._doFinalize(); + + return finalProcessedData; + }, + + keySize: 128/32, + + ivSize: 128/32, + + _ENC_XFORM_MODE: 1, + + _DEC_XFORM_MODE: 2, + + /** + * Creates shortcut functions to a cipher's object interface. + * + * @param {Cipher} cipher The cipher to create a helper for. + * + * @return {Object} An object with encrypt and decrypt shortcut functions. + * + * @static + * + * @example + * + * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); + */ + _createHelper: (function () { + function selectCipherStrategy(key) { + if (typeof key == 'string') { + return PasswordBasedCipher; + } else { + return SerializableCipher; + } + } + + return function (cipher) { + return { + encrypt: function (message, key, cfg) { + return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); + }, + + decrypt: function (ciphertext, key, cfg) { + return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); + } + }; + }; + }()) + }); + + /** + * Abstract base stream cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + */ + var StreamCipher = C_lib.StreamCipher = Cipher.extend({ + _doFinalize: function () { + // Process partial blocks + var finalProcessedBlocks = this._process(!!'flush'); + + return finalProcessedBlocks; + }, + + blockSize: 1 + }); + + /** + * Mode namespace. + */ + var C_mode = C.mode = {}; + + /** + * Abstract base block cipher mode template. + */ + var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ + /** + * Creates this mode for encryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); + */ + createEncryptor: function (cipher, iv) { + return this.Encryptor.create(cipher, iv); + }, + + /** + * Creates this mode for decryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); + */ + createDecryptor: function (cipher, iv) { + return this.Decryptor.create(cipher, iv); + }, + + /** + * Initializes a newly created mode. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @example + * + * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); + */ + init: function (cipher, iv) { + this._cipher = cipher; + this._iv = iv; + } + }); + + /** + * Cipher Block Chaining mode. + */ + var CBC = C_mode.CBC = (function () { + /** + * Abstract base CBC mode. + */ + var CBC = BlockCipherMode.extend(); + + /** + * CBC encryptor. + */ + CBC.Encryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // XOR and encrypt + xorBlock.call(this, words, offset, blockSize); + cipher.encryptBlock(words, offset); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + /** + * CBC decryptor. + */ + CBC.Decryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + // Decrypt and XOR + cipher.decryptBlock(words, offset); + xorBlock.call(this, words, offset, blockSize); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function xorBlock(words, offset, blockSize) { + var block; + + // Shortcut + var iv = this._iv; + + // Choose mixing block + if (iv) { + block = iv; + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + block = this._prevBlock; + } + + // XOR blocks + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= block[i]; + } + } + + return CBC; + }()); + + /** + * Padding namespace. + */ + var C_pad = C.pad = {}; + + /** + * PKCS #5/7 padding strategy. + */ + var Pkcs7 = C_pad.Pkcs7 = { + /** + * Pads data using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to pad. + * @param {number} blockSize The multiple that the data should be padded to. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.pad(wordArray, 4); + */ + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding word + var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + + // Create padding + var paddingWords = []; + for (var i = 0; i < nPaddingBytes; i += 4) { + paddingWords.push(paddingWord); + } + var padding = WordArray.create(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, + + /** + * Unpads data that had been padded using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to unpad. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.unpad(wordArray); + */ + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + /** + * Abstract base block cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + */ + var BlockCipher = C_lib.BlockCipher = Cipher.extend({ + /** + * Configuration options. + * + * @property {Mode} mode The block mode to use. Default: CBC + * @property {Padding} padding The padding strategy to use. Default: Pkcs7 + */ + cfg: Cipher.cfg.extend({ + mode: CBC, + padding: Pkcs7 + }), + + reset: function () { + var modeCreator; + + // Reset cipher + Cipher.reset.call(this); + + // Shortcuts + var cfg = this.cfg; + var iv = cfg.iv; + var mode = cfg.mode; + + // Reset block mode + if (this._xformMode == this._ENC_XFORM_MODE) { + modeCreator = mode.createEncryptor; + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + modeCreator = mode.createDecryptor; + // Keep at least one block in the buffer for unpadding + this._minBufferSize = 1; + } + + if (this._mode && this._mode.__creator == modeCreator) { + this._mode.init(this, iv && iv.words); + } else { + this._mode = modeCreator.call(mode, this, iv && iv.words); + this._mode.__creator = modeCreator; + } + }, + + _doProcessBlock: function (words, offset) { + this._mode.processBlock(words, offset); + }, + + _doFinalize: function () { + var finalProcessedBlocks; + + // Shortcut + var padding = this.cfg.padding; + + // Finalize + if (this._xformMode == this._ENC_XFORM_MODE) { + // Pad data + padding.pad(this._data, this.blockSize); + + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + + // Unpad data + padding.unpad(finalProcessedBlocks); + } + + return finalProcessedBlocks; + }, + + blockSize: 128/32 + }); + + /** + * A collection of cipher parameters. + * + * @property {WordArray} ciphertext The raw ciphertext. + * @property {WordArray} key The key to this ciphertext. + * @property {WordArray} iv The IV used in the ciphering operation. + * @property {WordArray} salt The salt used with a key derivation function. + * @property {Cipher} algorithm The cipher algorithm. + * @property {Mode} mode The block mode used in the ciphering operation. + * @property {Padding} padding The padding scheme used in the ciphering operation. + * @property {number} blockSize The block size of the cipher. + * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + */ + var CipherParams = C_lib.CipherParams = Base.extend({ + /** + * Initializes a newly created cipher params object. + * + * @param {Object} cipherParams An object with any of the possible cipher parameters. + * + * @example + * + * var cipherParams = CryptoJS.lib.CipherParams.create({ + * ciphertext: ciphertextWordArray, + * key: keyWordArray, + * iv: ivWordArray, + * salt: saltWordArray, + * algorithm: CryptoJS.algo.AES, + * mode: CryptoJS.mode.CBC, + * padding: CryptoJS.pad.PKCS7, + * blockSize: 4, + * formatter: CryptoJS.format.OpenSSL + * }); + */ + init: function (cipherParams) { + this.mixIn(cipherParams); + }, + + /** + * Converts this cipher params object to a string. + * + * @param {Format} formatter (Optional) The formatting strategy to use. + * + * @return {string} The stringified cipher params. + * + * @throws Error If neither the formatter nor the default formatter is set. + * + * @example + * + * var string = cipherParams + ''; + * var string = cipherParams.toString(); + * var string = cipherParams.toString(CryptoJS.format.OpenSSL); + */ + toString: function (formatter) { + return (formatter || this.formatter).stringify(this); + } + }); + + /** + * Format namespace. + */ + var C_format = C.format = {}; + + /** + * OpenSSL formatting strategy. + */ + var OpenSSLFormatter = C_format.OpenSSL = { + /** + * Converts a cipher params object to an OpenSSL-compatible string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The OpenSSL-compatible string. + * + * @static + * + * @example + * + * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); + */ + stringify: function (cipherParams) { + var wordArray; + + // Shortcuts + var ciphertext = cipherParams.ciphertext; + var salt = cipherParams.salt; + + // Format + if (salt) { + wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + } else { + wordArray = ciphertext; + } + + return wordArray.toString(Base64); + }, + + /** + * Converts an OpenSSL-compatible string to a cipher params object. + * + * @param {string} openSSLStr The OpenSSL-compatible string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); + */ + parse: function (openSSLStr) { + var salt; + + // Parse base64 + var ciphertext = Base64.parse(openSSLStr); + + // Shortcut + var ciphertextWords = ciphertext.words; + + // Test for salt + if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { + // Extract salt + salt = WordArray.create(ciphertextWords.slice(2, 4)); + + // Remove salt from ciphertext + ciphertextWords.splice(0, 4); + ciphertext.sigBytes -= 16; + } + + return CipherParams.create({ ciphertext: ciphertext, salt: salt }); + } + }; + + /** + * A cipher wrapper that returns ciphertext as a serializable cipher params object. + */ + var SerializableCipher = C_lib.SerializableCipher = Base.extend({ + /** + * Configuration options. + * + * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL + */ + cfg: Base.extend({ + format: OpenSSLFormatter + }), + + /** + * Encrypts a message. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Encrypt + var encryptor = cipher.createEncryptor(key, cfg); + var ciphertext = encryptor.finalize(message); + + // Shortcut + var cipherCfg = encryptor.cfg; + + // Create and return serializable cipher params + return CipherParams.create({ + ciphertext: ciphertext, + key: key, + iv: cipherCfg.iv, + algorithm: cipher, + mode: cipherCfg.mode, + padding: cipherCfg.padding, + blockSize: cipher.blockSize, + formatter: cfg.format + }); + }, + + /** + * Decrypts serialized ciphertext. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Decrypt + var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); + + return plaintext; + }, + + /** + * Converts serialized ciphertext to CipherParams, + * else assumed CipherParams already and returns ciphertext unchanged. + * + * @param {CipherParams|string} ciphertext The ciphertext. + * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. + * + * @return {CipherParams} The unserialized ciphertext. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); + */ + _parse: function (ciphertext, format) { + if (typeof ciphertext == 'string') { + return format.parse(ciphertext, this); + } else { + return ciphertext; + } + } + }); + + /** + * Key derivation function namespace. + */ + var C_kdf = C.kdf = {}; + + /** + * OpenSSL key derivation function. + */ + var OpenSSLKdf = C_kdf.OpenSSL = { + /** + * Derives a key and IV from a password. + * + * @param {string} password The password to derive from. + * @param {number} keySize The size in words of the key to generate. + * @param {number} ivSize The size in words of the IV to generate. + * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. + * + * @return {CipherParams} A cipher params object with the key, IV, and salt. + * + * @static + * + * @example + * + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); + */ + execute: function (password, keySize, ivSize, salt) { + // Generate random salt + if (!salt) { + salt = WordArray.random(64/8); + } + + // Derive key and IV + var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + + // Separate key and IV + var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); + key.sigBytes = keySize * 4; + + // Return params + return CipherParams.create({ key: key, iv: iv, salt: salt }); + } + }; + + /** + * A serializable cipher wrapper that derives the key from a password, + * and returns ciphertext as a serializable cipher params object. + */ + var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ + /** + * Configuration options. + * + * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL + */ + cfg: SerializableCipher.cfg.extend({ + kdf: OpenSSLKdf + }), + + /** + * Encrypts a message using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Encrypt + var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); + + // Mix in derived params + ciphertext.mixIn(derivedParams); + + return ciphertext; + }, + + /** + * Decrypts serialized ciphertext using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Decrypt + var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); + + return plaintext; + } + }); + }()); + + + /** + * Cipher Feedback block mode. + */ + CryptoJS.mode.CFB = (function () { + var CFB = CryptoJS.lib.BlockCipherMode.extend(); + + CFB.Encryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + CFB.Decryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + var keystream; + + // Shortcut + var iv = this._iv; + + // Generate keystream + if (iv) { + keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + keystream = this._prevBlock; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + + return CFB; + }()); + + + /** + * Counter block mode. + */ + CryptoJS.mode.CTR = (function () { + var CTR = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = CTR.Encryptor = CTR.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Increment counter + counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTR.Decryptor = Encryptor; + + return CTR; + }()); + + + /** @preserve + * Counter block mode compatible with Dr Brian Gladman fileenc.c + * derived from CryptoJS.mode.CTR + * Jan Hruby jhruby.web@gmail.com + */ + CryptoJS.mode.CTRGladman = (function () { + var CTRGladman = CryptoJS.lib.BlockCipherMode.extend(); + + function incWord(word) + { + if (((word >> 24) & 0xff) === 0xff) { //overflow + var b1 = (word >> 16)&0xff; + var b2 = (word >> 8)&0xff; + var b3 = word & 0xff; + + if (b1 === 0xff) // overflow b1 + { + b1 = 0; + if (b2 === 0xff) + { + b2 = 0; + if (b3 === 0xff) + { + b3 = 0; + } + else + { + ++b3; + } + } + else + { + ++b2; + } + } + else + { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } + else + { + word += (0x01 << 24); + } + return word; + } + + function incCounter(counter) + { + if ((counter[0] = incWord(counter[0])) === 0) + { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = incWord(counter[1]); + } + return counter; + } + + var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + + incCounter(counter); + + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTRGladman.Decryptor = Encryptor; + + return CTRGladman; + }()); + + + + + /** + * Output Feedback block mode. + */ + CryptoJS.mode.OFB = (function () { + var OFB = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = OFB.Encryptor = OFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var keystream = this._keystream; + + // Generate keystream + if (iv) { + keystream = this._keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + OFB.Decryptor = Encryptor; + + return OFB; + }()); + + + /** + * Electronic Codebook block mode. + */ + CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + } + }); + + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + } + }); + + return ECB; + }()); + + + /** + * ANSI X.923 padding strategy. + */ + CryptoJS.pad.AnsiX923 = { + pad: function (data, blockSize) { + // Shortcuts + var dataSigBytes = data.sigBytes; + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes; + + // Compute last byte position + var lastBytePos = dataSigBytes + nPaddingBytes - 1; + + // Pad + data.clamp(); + data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8); + data.sigBytes += nPaddingBytes; + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + /** + * ISO 10126 padding strategy. + */ + CryptoJS.pad.Iso10126 = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Pad + data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)). + concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1)); + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + /** + * ISO/IEC 9797-1 Padding Method 2. + */ + CryptoJS.pad.Iso97971 = { + pad: function (data, blockSize) { + // Add 0x80 byte + data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1)); + + // Zero pad the rest + CryptoJS.pad.ZeroPadding.pad(data, blockSize); + }, + + unpad: function (data) { + // Remove zero padding + CryptoJS.pad.ZeroPadding.unpad(data); + + // Remove one more byte -- the 0x80 byte + data.sigBytes--; + } + }; + + + /** + * Zero padding strategy. + */ + CryptoJS.pad.ZeroPadding = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Pad + data.clamp(); + data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes); + }, + + unpad: function (data) { + // Shortcut + var dataWords = data.words; + + // Unpad + var i = data.sigBytes - 1; + for (var i = data.sigBytes - 1; i >= 0; i--) { + if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + data.sigBytes = i + 1; + break; + } + } + } + }; + + + /** + * A noop padding strategy. + */ + CryptoJS.pad.NoPadding = { + pad: function () { + }, + + unpad: function () { + } + }; + + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var CipherParams = C_lib.CipherParams; + var C_enc = C.enc; + var Hex = C_enc.Hex; + var C_format = C.format; + + var HexFormatter = C_format.Hex = { + /** + * Converts the ciphertext of a cipher params object to a hexadecimally encoded string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The hexadecimally encoded string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.format.Hex.stringify(cipherParams); + */ + stringify: function (cipherParams) { + return cipherParams.ciphertext.toString(Hex); + }, + + /** + * Converts a hexadecimally encoded ciphertext string to a cipher params object. + * + * @param {string} input The hexadecimally encoded string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.Hex.parse(hexString); + */ + parse: function (input) { + var ciphertext = Hex.parse(input); + return CipherParams.create({ ciphertext: ciphertext }); + } + }; + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Lookup tables + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX_0 = []; + var SUB_MIX_1 = []; + var SUB_MIX_2 = []; + var SUB_MIX_3 = []; + var INV_SUB_MIX_0 = []; + var INV_SUB_MIX_1 = []; + var INV_SUB_MIX_2 = []; + var INV_SUB_MIX_3 = []; + + // Compute lookup tables + (function () { + // Compute double table + var d = []; + for (var i = 0; i < 256; i++) { + if (i < 128) { + d[i] = i << 1; + } else { + d[i] = (i << 1) ^ 0x11b; + } + } + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; i++) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX_0[x] = (t << 24) | (t >>> 8); + SUB_MIX_1[x] = (t << 16) | (t >>> 16); + SUB_MIX_2[x] = (t << 8) | (t >>> 24); + SUB_MIX_3[x] = t; + + // Compute inv sub bytes, inv mix columns tables + var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX_3[sx] = t; + + // Compute next counter + if (!x) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } + }()); + + // Precomputed Rcon lookup + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + + /** + * AES block cipher algorithm. + */ + var AES = C_algo.AES = BlockCipher.extend({ + _doReset: function () { + var t; + + // Skip reset of nRounds has been set before and key did not change + if (this._nRounds && this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + // Compute number of rounds + var nRounds = this._nRounds = keySize + 6; + + // Compute number of key schedule rows + var ksRows = (nRounds + 1) * 4; + + // Compute key schedule + var keySchedule = this._keySchedule = []; + for (var ksRow = 0; ksRow < ksRows; ksRow++) { + if (ksRow < keySize) { + keySchedule[ksRow] = keyWords[ksRow]; + } else { + t = keySchedule[ksRow - 1]; + + if (!(ksRow % keySize)) { + // Rot word + t = (t << 8) | (t >>> 24); + + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + + // Mix Rcon + t ^= RCON[(ksRow / keySize) | 0] << 24; + } else if (keySize > 6 && ksRow % keySize == 4) { + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + } + + keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; + } + } + + // Compute inv key schedule + var invKeySchedule = this._invKeySchedule = []; + for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { + var ksRow = ksRows - invKsRow; + + if (invKsRow % 4) { + var t = keySchedule[ksRow]; + } else { + var t = keySchedule[ksRow - 4]; + } + + if (invKsRow < 4 || ksRow <= 4) { + invKeySchedule[invKsRow] = t; + } else { + invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ + INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; + } + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); + }, + + decryptBlock: function (M, offset) { + // Swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + + this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + + // Inv swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + }, + + _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { + // Shortcut + var nRounds = this._nRounds; + + // Get input, add round key + var s0 = M[offset] ^ keySchedule[0]; + var s1 = M[offset + 1] ^ keySchedule[1]; + var s2 = M[offset + 2] ^ keySchedule[2]; + var s3 = M[offset + 3] ^ keySchedule[3]; + + // Key schedule row counter + var ksRow = 4; + + // Rounds + for (var round = 1; round < nRounds; round++) { + // Shift rows, sub bytes, mix columns, add round key + var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; + var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; + var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; + var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; + + // Update state + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + + // Shift rows, sub bytes, add round key + var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + + // Set output + M[offset] = t0; + M[offset + 1] = t1; + M[offset + 2] = t2; + M[offset + 3] = t3; + }, + + keySize: 256/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); + */ + C.AES = BlockCipher._createHelper(AES); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Permuted Choice 1 constants + var PC1 = [ + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, + 31, 23, 15, 7, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 28, 20, 12, 4 + ]; + + // Permuted Choice 2 constants + var PC2 = [ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 + ]; + + // Cumulative bit shift constants + var BIT_SHIFTS = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; + + // SBOXes and round permutation constants + var SBOX_P = [ + { + 0x0: 0x808200, + 0x10000000: 0x8000, + 0x20000000: 0x808002, + 0x30000000: 0x2, + 0x40000000: 0x200, + 0x50000000: 0x808202, + 0x60000000: 0x800202, + 0x70000000: 0x800000, + 0x80000000: 0x202, + 0x90000000: 0x800200, + 0xa0000000: 0x8200, + 0xb0000000: 0x808000, + 0xc0000000: 0x8002, + 0xd0000000: 0x800002, + 0xe0000000: 0x0, + 0xf0000000: 0x8202, + 0x8000000: 0x0, + 0x18000000: 0x808202, + 0x28000000: 0x8202, + 0x38000000: 0x8000, + 0x48000000: 0x808200, + 0x58000000: 0x200, + 0x68000000: 0x808002, + 0x78000000: 0x2, + 0x88000000: 0x800200, + 0x98000000: 0x8200, + 0xa8000000: 0x808000, + 0xb8000000: 0x800202, + 0xc8000000: 0x800002, + 0xd8000000: 0x8002, + 0xe8000000: 0x202, + 0xf8000000: 0x800000, + 0x1: 0x8000, + 0x10000001: 0x2, + 0x20000001: 0x808200, + 0x30000001: 0x800000, + 0x40000001: 0x808002, + 0x50000001: 0x8200, + 0x60000001: 0x200, + 0x70000001: 0x800202, + 0x80000001: 0x808202, + 0x90000001: 0x808000, + 0xa0000001: 0x800002, + 0xb0000001: 0x8202, + 0xc0000001: 0x202, + 0xd0000001: 0x800200, + 0xe0000001: 0x8002, + 0xf0000001: 0x0, + 0x8000001: 0x808202, + 0x18000001: 0x808000, + 0x28000001: 0x800000, + 0x38000001: 0x200, + 0x48000001: 0x8000, + 0x58000001: 0x800002, + 0x68000001: 0x2, + 0x78000001: 0x8202, + 0x88000001: 0x8002, + 0x98000001: 0x800202, + 0xa8000001: 0x202, + 0xb8000001: 0x808200, + 0xc8000001: 0x800200, + 0xd8000001: 0x0, + 0xe8000001: 0x8200, + 0xf8000001: 0x808002 + }, + { + 0x0: 0x40084010, + 0x1000000: 0x4000, + 0x2000000: 0x80000, + 0x3000000: 0x40080010, + 0x4000000: 0x40000010, + 0x5000000: 0x40084000, + 0x6000000: 0x40004000, + 0x7000000: 0x10, + 0x8000000: 0x84000, + 0x9000000: 0x40004010, + 0xa000000: 0x40000000, + 0xb000000: 0x84010, + 0xc000000: 0x80010, + 0xd000000: 0x0, + 0xe000000: 0x4010, + 0xf000000: 0x40080000, + 0x800000: 0x40004000, + 0x1800000: 0x84010, + 0x2800000: 0x10, + 0x3800000: 0x40004010, + 0x4800000: 0x40084010, + 0x5800000: 0x40000000, + 0x6800000: 0x80000, + 0x7800000: 0x40080010, + 0x8800000: 0x80010, + 0x9800000: 0x0, + 0xa800000: 0x4000, + 0xb800000: 0x40080000, + 0xc800000: 0x40000010, + 0xd800000: 0x84000, + 0xe800000: 0x40084000, + 0xf800000: 0x4010, + 0x10000000: 0x0, + 0x11000000: 0x40080010, + 0x12000000: 0x40004010, + 0x13000000: 0x40084000, + 0x14000000: 0x40080000, + 0x15000000: 0x10, + 0x16000000: 0x84010, + 0x17000000: 0x4000, + 0x18000000: 0x4010, + 0x19000000: 0x80000, + 0x1a000000: 0x80010, + 0x1b000000: 0x40000010, + 0x1c000000: 0x84000, + 0x1d000000: 0x40004000, + 0x1e000000: 0x40000000, + 0x1f000000: 0x40084010, + 0x10800000: 0x84010, + 0x11800000: 0x80000, + 0x12800000: 0x40080000, + 0x13800000: 0x4000, + 0x14800000: 0x40004000, + 0x15800000: 0x40084010, + 0x16800000: 0x10, + 0x17800000: 0x40000000, + 0x18800000: 0x40084000, + 0x19800000: 0x40000010, + 0x1a800000: 0x40004010, + 0x1b800000: 0x80010, + 0x1c800000: 0x0, + 0x1d800000: 0x4010, + 0x1e800000: 0x40080010, + 0x1f800000: 0x84000 + }, + { + 0x0: 0x104, + 0x100000: 0x0, + 0x200000: 0x4000100, + 0x300000: 0x10104, + 0x400000: 0x10004, + 0x500000: 0x4000004, + 0x600000: 0x4010104, + 0x700000: 0x4010000, + 0x800000: 0x4000000, + 0x900000: 0x4010100, + 0xa00000: 0x10100, + 0xb00000: 0x4010004, + 0xc00000: 0x4000104, + 0xd00000: 0x10000, + 0xe00000: 0x4, + 0xf00000: 0x100, + 0x80000: 0x4010100, + 0x180000: 0x4010004, + 0x280000: 0x0, + 0x380000: 0x4000100, + 0x480000: 0x4000004, + 0x580000: 0x10000, + 0x680000: 0x10004, + 0x780000: 0x104, + 0x880000: 0x4, + 0x980000: 0x100, + 0xa80000: 0x4010000, + 0xb80000: 0x10104, + 0xc80000: 0x10100, + 0xd80000: 0x4000104, + 0xe80000: 0x4010104, + 0xf80000: 0x4000000, + 0x1000000: 0x4010100, + 0x1100000: 0x10004, + 0x1200000: 0x10000, + 0x1300000: 0x4000100, + 0x1400000: 0x100, + 0x1500000: 0x4010104, + 0x1600000: 0x4000004, + 0x1700000: 0x0, + 0x1800000: 0x4000104, + 0x1900000: 0x4000000, + 0x1a00000: 0x4, + 0x1b00000: 0x10100, + 0x1c00000: 0x4010000, + 0x1d00000: 0x104, + 0x1e00000: 0x10104, + 0x1f00000: 0x4010004, + 0x1080000: 0x4000000, + 0x1180000: 0x104, + 0x1280000: 0x4010100, + 0x1380000: 0x0, + 0x1480000: 0x10004, + 0x1580000: 0x4000100, + 0x1680000: 0x100, + 0x1780000: 0x4010004, + 0x1880000: 0x10000, + 0x1980000: 0x4010104, + 0x1a80000: 0x10104, + 0x1b80000: 0x4000004, + 0x1c80000: 0x4000104, + 0x1d80000: 0x4010000, + 0x1e80000: 0x4, + 0x1f80000: 0x10100 + }, + { + 0x0: 0x80401000, + 0x10000: 0x80001040, + 0x20000: 0x401040, + 0x30000: 0x80400000, + 0x40000: 0x0, + 0x50000: 0x401000, + 0x60000: 0x80000040, + 0x70000: 0x400040, + 0x80000: 0x80000000, + 0x90000: 0x400000, + 0xa0000: 0x40, + 0xb0000: 0x80001000, + 0xc0000: 0x80400040, + 0xd0000: 0x1040, + 0xe0000: 0x1000, + 0xf0000: 0x80401040, + 0x8000: 0x80001040, + 0x18000: 0x40, + 0x28000: 0x80400040, + 0x38000: 0x80001000, + 0x48000: 0x401000, + 0x58000: 0x80401040, + 0x68000: 0x0, + 0x78000: 0x80400000, + 0x88000: 0x1000, + 0x98000: 0x80401000, + 0xa8000: 0x400000, + 0xb8000: 0x1040, + 0xc8000: 0x80000000, + 0xd8000: 0x400040, + 0xe8000: 0x401040, + 0xf8000: 0x80000040, + 0x100000: 0x400040, + 0x110000: 0x401000, + 0x120000: 0x80000040, + 0x130000: 0x0, + 0x140000: 0x1040, + 0x150000: 0x80400040, + 0x160000: 0x80401000, + 0x170000: 0x80001040, + 0x180000: 0x80401040, + 0x190000: 0x80000000, + 0x1a0000: 0x80400000, + 0x1b0000: 0x401040, + 0x1c0000: 0x80001000, + 0x1d0000: 0x400000, + 0x1e0000: 0x40, + 0x1f0000: 0x1000, + 0x108000: 0x80400000, + 0x118000: 0x80401040, + 0x128000: 0x0, + 0x138000: 0x401000, + 0x148000: 0x400040, + 0x158000: 0x80000000, + 0x168000: 0x80001040, + 0x178000: 0x40, + 0x188000: 0x80000040, + 0x198000: 0x1000, + 0x1a8000: 0x80001000, + 0x1b8000: 0x80400040, + 0x1c8000: 0x1040, + 0x1d8000: 0x80401000, + 0x1e8000: 0x400000, + 0x1f8000: 0x401040 + }, + { + 0x0: 0x80, + 0x1000: 0x1040000, + 0x2000: 0x40000, + 0x3000: 0x20000000, + 0x4000: 0x20040080, + 0x5000: 0x1000080, + 0x6000: 0x21000080, + 0x7000: 0x40080, + 0x8000: 0x1000000, + 0x9000: 0x20040000, + 0xa000: 0x20000080, + 0xb000: 0x21040080, + 0xc000: 0x21040000, + 0xd000: 0x0, + 0xe000: 0x1040080, + 0xf000: 0x21000000, + 0x800: 0x1040080, + 0x1800: 0x21000080, + 0x2800: 0x80, + 0x3800: 0x1040000, + 0x4800: 0x40000, + 0x5800: 0x20040080, + 0x6800: 0x21040000, + 0x7800: 0x20000000, + 0x8800: 0x20040000, + 0x9800: 0x0, + 0xa800: 0x21040080, + 0xb800: 0x1000080, + 0xc800: 0x20000080, + 0xd800: 0x21000000, + 0xe800: 0x1000000, + 0xf800: 0x40080, + 0x10000: 0x40000, + 0x11000: 0x80, + 0x12000: 0x20000000, + 0x13000: 0x21000080, + 0x14000: 0x1000080, + 0x15000: 0x21040000, + 0x16000: 0x20040080, + 0x17000: 0x1000000, + 0x18000: 0x21040080, + 0x19000: 0x21000000, + 0x1a000: 0x1040000, + 0x1b000: 0x20040000, + 0x1c000: 0x40080, + 0x1d000: 0x20000080, + 0x1e000: 0x0, + 0x1f000: 0x1040080, + 0x10800: 0x21000080, + 0x11800: 0x1000000, + 0x12800: 0x1040000, + 0x13800: 0x20040080, + 0x14800: 0x20000000, + 0x15800: 0x1040080, + 0x16800: 0x80, + 0x17800: 0x21040000, + 0x18800: 0x40080, + 0x19800: 0x21040080, + 0x1a800: 0x0, + 0x1b800: 0x21000000, + 0x1c800: 0x1000080, + 0x1d800: 0x40000, + 0x1e800: 0x20040000, + 0x1f800: 0x20000080 + }, + { + 0x0: 0x10000008, + 0x100: 0x2000, + 0x200: 0x10200000, + 0x300: 0x10202008, + 0x400: 0x10002000, + 0x500: 0x200000, + 0x600: 0x200008, + 0x700: 0x10000000, + 0x800: 0x0, + 0x900: 0x10002008, + 0xa00: 0x202000, + 0xb00: 0x8, + 0xc00: 0x10200008, + 0xd00: 0x202008, + 0xe00: 0x2008, + 0xf00: 0x10202000, + 0x80: 0x10200000, + 0x180: 0x10202008, + 0x280: 0x8, + 0x380: 0x200000, + 0x480: 0x202008, + 0x580: 0x10000008, + 0x680: 0x10002000, + 0x780: 0x2008, + 0x880: 0x200008, + 0x980: 0x2000, + 0xa80: 0x10002008, + 0xb80: 0x10200008, + 0xc80: 0x0, + 0xd80: 0x10202000, + 0xe80: 0x202000, + 0xf80: 0x10000000, + 0x1000: 0x10002000, + 0x1100: 0x10200008, + 0x1200: 0x10202008, + 0x1300: 0x2008, + 0x1400: 0x200000, + 0x1500: 0x10000000, + 0x1600: 0x10000008, + 0x1700: 0x202000, + 0x1800: 0x202008, + 0x1900: 0x0, + 0x1a00: 0x8, + 0x1b00: 0x10200000, + 0x1c00: 0x2000, + 0x1d00: 0x10002008, + 0x1e00: 0x10202000, + 0x1f00: 0x200008, + 0x1080: 0x8, + 0x1180: 0x202000, + 0x1280: 0x200000, + 0x1380: 0x10000008, + 0x1480: 0x10002000, + 0x1580: 0x2008, + 0x1680: 0x10202008, + 0x1780: 0x10200000, + 0x1880: 0x10202000, + 0x1980: 0x10200008, + 0x1a80: 0x2000, + 0x1b80: 0x202008, + 0x1c80: 0x200008, + 0x1d80: 0x0, + 0x1e80: 0x10000000, + 0x1f80: 0x10002008 + }, + { + 0x0: 0x100000, + 0x10: 0x2000401, + 0x20: 0x400, + 0x30: 0x100401, + 0x40: 0x2100401, + 0x50: 0x0, + 0x60: 0x1, + 0x70: 0x2100001, + 0x80: 0x2000400, + 0x90: 0x100001, + 0xa0: 0x2000001, + 0xb0: 0x2100400, + 0xc0: 0x2100000, + 0xd0: 0x401, + 0xe0: 0x100400, + 0xf0: 0x2000000, + 0x8: 0x2100001, + 0x18: 0x0, + 0x28: 0x2000401, + 0x38: 0x2100400, + 0x48: 0x100000, + 0x58: 0x2000001, + 0x68: 0x2000000, + 0x78: 0x401, + 0x88: 0x100401, + 0x98: 0x2000400, + 0xa8: 0x2100000, + 0xb8: 0x100001, + 0xc8: 0x400, + 0xd8: 0x2100401, + 0xe8: 0x1, + 0xf8: 0x100400, + 0x100: 0x2000000, + 0x110: 0x100000, + 0x120: 0x2000401, + 0x130: 0x2100001, + 0x140: 0x100001, + 0x150: 0x2000400, + 0x160: 0x2100400, + 0x170: 0x100401, + 0x180: 0x401, + 0x190: 0x2100401, + 0x1a0: 0x100400, + 0x1b0: 0x1, + 0x1c0: 0x0, + 0x1d0: 0x2100000, + 0x1e0: 0x2000001, + 0x1f0: 0x400, + 0x108: 0x100400, + 0x118: 0x2000401, + 0x128: 0x2100001, + 0x138: 0x1, + 0x148: 0x2000000, + 0x158: 0x100000, + 0x168: 0x401, + 0x178: 0x2100400, + 0x188: 0x2000001, + 0x198: 0x2100000, + 0x1a8: 0x0, + 0x1b8: 0x2100401, + 0x1c8: 0x100401, + 0x1d8: 0x400, + 0x1e8: 0x2000400, + 0x1f8: 0x100001 + }, + { + 0x0: 0x8000820, + 0x1: 0x20000, + 0x2: 0x8000000, + 0x3: 0x20, + 0x4: 0x20020, + 0x5: 0x8020820, + 0x6: 0x8020800, + 0x7: 0x800, + 0x8: 0x8020000, + 0x9: 0x8000800, + 0xa: 0x20800, + 0xb: 0x8020020, + 0xc: 0x820, + 0xd: 0x0, + 0xe: 0x8000020, + 0xf: 0x20820, + 0x80000000: 0x800, + 0x80000001: 0x8020820, + 0x80000002: 0x8000820, + 0x80000003: 0x8000000, + 0x80000004: 0x8020000, + 0x80000005: 0x20800, + 0x80000006: 0x20820, + 0x80000007: 0x20, + 0x80000008: 0x8000020, + 0x80000009: 0x820, + 0x8000000a: 0x20020, + 0x8000000b: 0x8020800, + 0x8000000c: 0x0, + 0x8000000d: 0x8020020, + 0x8000000e: 0x8000800, + 0x8000000f: 0x20000, + 0x10: 0x20820, + 0x11: 0x8020800, + 0x12: 0x20, + 0x13: 0x800, + 0x14: 0x8000800, + 0x15: 0x8000020, + 0x16: 0x8020020, + 0x17: 0x20000, + 0x18: 0x0, + 0x19: 0x20020, + 0x1a: 0x8020000, + 0x1b: 0x8000820, + 0x1c: 0x8020820, + 0x1d: 0x20800, + 0x1e: 0x820, + 0x1f: 0x8000000, + 0x80000010: 0x20000, + 0x80000011: 0x800, + 0x80000012: 0x8020020, + 0x80000013: 0x20820, + 0x80000014: 0x20, + 0x80000015: 0x8020000, + 0x80000016: 0x8000000, + 0x80000017: 0x8000820, + 0x80000018: 0x8020820, + 0x80000019: 0x8000020, + 0x8000001a: 0x8000800, + 0x8000001b: 0x0, + 0x8000001c: 0x20800, + 0x8000001d: 0x820, + 0x8000001e: 0x20020, + 0x8000001f: 0x8020800 + } + ]; + + // Masks that select the SBOX input + var SBOX_MASK = [ + 0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000, + 0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f + ]; + + /** + * DES block cipher algorithm. + */ + var DES = C_algo.DES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + + // Select 56 bits according to PC1 + var keyBits = []; + for (var i = 0; i < 56; i++) { + var keyBitPos = PC1[i] - 1; + keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1; + } + + // Assemble 16 subkeys + var subKeys = this._subKeys = []; + for (var nSubKey = 0; nSubKey < 16; nSubKey++) { + // Create subkey + var subKey = subKeys[nSubKey] = []; + + // Shortcut + var bitShift = BIT_SHIFTS[nSubKey]; + + // Select 48 bits according to PC2 + for (var i = 0; i < 24; i++) { + // Select from the left 28 key bits + subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6); + + // Select from the right 28 key bits + subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6); + } + + // Since each subkey is applied to an expanded 32-bit input, + // the subkey can be broken into 8 values scaled to 32-bits, + // which allows the key to be used without expansion + subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31); + for (var i = 1; i < 7; i++) { + subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3); + } + subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27); + } + + // Compute inverse subkeys + var invSubKeys = this._invSubKeys = []; + for (var i = 0; i < 16; i++) { + invSubKeys[i] = subKeys[15 - i]; + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._subKeys); + }, + + decryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._invSubKeys); + }, + + _doCryptBlock: function (M, offset, subKeys) { + // Get input + this._lBlock = M[offset]; + this._rBlock = M[offset + 1]; + + // Initial permutation + exchangeLR.call(this, 4, 0x0f0f0f0f); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeRL.call(this, 2, 0x33333333); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeLR.call(this, 1, 0x55555555); + + // Rounds + for (var round = 0; round < 16; round++) { + // Shortcuts + var subKey = subKeys[round]; + var lBlock = this._lBlock; + var rBlock = this._rBlock; + + // Feistel function + var f = 0; + for (var i = 0; i < 8; i++) { + f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0]; + } + this._lBlock = rBlock; + this._rBlock = lBlock ^ f; + } + + // Undo swap from last round + var t = this._lBlock; + this._lBlock = this._rBlock; + this._rBlock = t; + + // Final permutation + exchangeLR.call(this, 1, 0x55555555); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeRL.call(this, 2, 0x33333333); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeLR.call(this, 4, 0x0f0f0f0f); + + // Set output + M[offset] = this._lBlock; + M[offset + 1] = this._rBlock; + }, + + keySize: 64/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + // Swap bits across the left and right words + function exchangeLR(offset, mask) { + var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask; + this._rBlock ^= t; + this._lBlock ^= t << offset; + } + + function exchangeRL(offset, mask) { + var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask; + this._lBlock ^= t; + this._rBlock ^= t << offset; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.DES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.DES.decrypt(ciphertext, key, cfg); + */ + C.DES = BlockCipher._createHelper(DES); + + /** + * Triple-DES block cipher algorithm. + */ + var TripleDES = C_algo.TripleDES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + // Make sure the key length is valid (64, 128 or >= 192 bit) + if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) { + throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.'); + } + + // Extend the key according to the keying options defined in 3DES standard + var key1 = keyWords.slice(0, 2); + var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4); + var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6); + + // Create DES instances + this._des1 = DES.createEncryptor(WordArray.create(key1)); + this._des2 = DES.createEncryptor(WordArray.create(key2)); + this._des3 = DES.createEncryptor(WordArray.create(key3)); + }, + + encryptBlock: function (M, offset) { + this._des1.encryptBlock(M, offset); + this._des2.decryptBlock(M, offset); + this._des3.encryptBlock(M, offset); + }, + + decryptBlock: function (M, offset) { + this._des3.decryptBlock(M, offset); + this._des2.encryptBlock(M, offset); + this._des1.decryptBlock(M, offset); + }, + + keySize: 192/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg); + */ + C.TripleDES = BlockCipher._createHelper(TripleDES); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + /** + * RC4 stream cipher algorithm. + */ + var RC4 = C_algo.RC4 = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + var keySigBytes = key.sigBytes; + + // Init sbox + var S = this._S = []; + for (var i = 0; i < 256; i++) { + S[i] = i; + } + + // Key setup + for (var i = 0, j = 0; i < 256; i++) { + var keyByteIndex = i % keySigBytes; + var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff; + + j = (j + S[i] + keyByte) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + } + + // Counters + this._i = this._j = 0; + }, + + _doProcessBlock: function (M, offset) { + M[offset] ^= generateKeystreamWord.call(this); + }, + + keySize: 256/32, + + ivSize: 0 + }); + + function generateKeystreamWord() { + // Shortcuts + var S = this._S; + var i = this._i; + var j = this._j; + + // Generate keystream word + var keystreamWord = 0; + for (var n = 0; n < 4; n++) { + i = (i + 1) % 256; + j = (j + S[i]) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + + keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8); + } + + // Update counters + this._i = i; + this._j = j; + + return keystreamWord; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4.decrypt(ciphertext, key, cfg); + */ + C.RC4 = StreamCipher._createHelper(RC4); + + /** + * Modified RC4 stream cipher algorithm. + */ + var RC4Drop = C_algo.RC4Drop = RC4.extend({ + /** + * Configuration options. + * + * @property {number} drop The number of keystream words to drop. Default 192 + */ + cfg: RC4.cfg.extend({ + drop: 192 + }), + + _doReset: function () { + RC4._doReset.call(this); + + // Drop + for (var i = this.cfg.drop; i > 0; i--) { + generateKeystreamWord.call(this); + } + } + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg); + */ + C.RC4Drop = StreamCipher._createHelper(RC4Drop); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm + */ + var Rabbit = C_algo.Rabbit = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Swap endian + for (var i = 0; i < 4; i++) { + K[i] = (((K[i] << 8) | (K[i] >>> 24)) & 0x00ff00ff) | + (((K[i] << 24) | (K[i] >>> 8)) & 0xff00ff00); + } + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg); + */ + C.Rabbit = StreamCipher._createHelper(Rabbit); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm. + * + * This is a legacy version that neglected to convert the key to little-endian. + * This error doesn't affect the cipher's security, + * but it does affect its compatibility with other implementations. + */ + var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg); + */ + C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy); + }()); + + + return CryptoJS; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/docs/QuickStartGuide.wiki b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/docs/QuickStartGuide.wiki new file mode 100644 index 0000000..7c7adbc --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/docs/QuickStartGuide.wiki @@ -0,0 +1,470 @@ + + +---- + += Quick-start Guide = + +== Hashers == + +=== The Hasher Algorithms === + +==== MD5 ==== + +MD5 is a widely used hash function. It's been used in a variety of security applications and is also commonly used to check the integrity of files. Though, MD5 is not collision resistant, and it isn't suitable for applications like SSL certificates or digital signatures that rely on this property. + +{{{ + + +}}} + +==== SHA-1 ==== + +The SHA hash functions were designed by the National Security Agency (NSA). SHA-1 is the most established of the existing SHA hash functions, and it's used in a variety of security applications and protocols. Though, SHA-1's collision resistance has been weakening as new attacks are discovered or improved. + +{{{ + + +}}} + +==== SHA-2 ==== + +SHA-256 is one of the four variants in the SHA-2 set. It isn't as widely used as SHA-1, though it appears to provide much better security. + +{{{ + + +}}} + +SHA-512 is largely identical to SHA-256 but operates on 64-bit words rather than 32. + +{{{ + + +}}} + +CryptoJS also supports SHA-224 and SHA-384, which are largely identical but truncated versions of SHA-256 and SHA-512 respectively. + +==== SHA-3 ==== + +SHA-3 is the winner of a five-year competition to select a new cryptographic hash algorithm where 64 competing designs were evaluated. + +{{{ + + +}}} + +SHA-3 can be configured to output hash lengths of one of 224, 256, 384, or 512 bits. The default is 512 bits. + +{{{ + + +}}} + +==== RIPEMD-160 ==== + +{{{ + + +}}} + +=== The Hasher Input === + +The hash algorithms accept either strings or instances of CryptoJS.lib.WordArray. A WordArray object represents an array of 32-bit words. When you pass a string, it's automatically converted to a WordArray encoded as UTF-8. + +=== The Hasher Output === + +The hash you get back isn't a string yet. It's a WordArray object. When you use a WordArray object in a string context, it's automatically converted to a hex string. + +{{{ + + +}}} + +You can convert a WordArray object to other formats by explicitly calling the toString method and passing an encoder. + +{{{ + + + +}}} + +=== Progressive Hashing === + +{{{ + + +}}} + +== HMAC == + +Keyed-hash message authentication codes (HMAC) is a mechanism for message authentication using cryptographic hash functions. + +HMAC can be used in combination with any iterated cryptographic hash function. + +{{{ + + + + + +}}} + +=== Progressive HMAC Hashing === + +{{{ + + +}}} + +== PBKDF2 == + +PBKDF2 is a password-based key derivation function. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required. + +A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack. + +{{{ + + +}}} + +== Ciphers == + +=== The Cipher Algorithms === + +==== AES ==== + +The Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated. + +{{{ + + +}}} + +CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key. + +==== DES, Triple DES ==== + +DES is a previously dominant algorithm for encryption, and was published as an official Federal Information Processing Standard (FIPS). DES is now considered to be insecure due to the small key size. + +{{{ + + +}}} + +Triple DES applies DES three times to each block to increase the key size. The algorithm is believed to be secure in this form. + +{{{ + + +}}} + +==== Rabbit ==== + +Rabbit is a high-performance stream cipher and a finalist in the eSTREAM Portfolio. It is one of the four designs selected after a 3 1/2-year process where 22 designs were evaluated. + +{{{ + + +}}} + +==== RC4, RC4Drop ==== + +RC4 is a widely-used stream cipher. It's used in popular protocols such as SSL and WEP. Although remarkable for its simplicity and speed, the algorithm's history doesn't inspire confidence in its security. + +{{{ + + +}}} + +It was discovered that the first few bytes of keystream are strongly non-random and leak information about the key. We can defend against this attack by discarding the initial portion of the keystream. This modified algorithm is traditionally called RC4-drop. + +By default, 192 words (768 bytes) are dropped, but you can configure the algorithm to drop any number of words. + +{{{ + + +}}} + +=== Custom Key and IV === + +{{{ + + +}}} + +=== Block Modes and Padding === + +{{{ + + + + +}}} + +CryptoJS supports the following modes: + + * CBC (the default) + * CFB + * CTR + * OFB + * ECB + +And CryptoJS supports the following padding schemes: + + * Pkcs7 (the default) + * Iso97971 + * AnsiX923 + * Iso10126 + * ZeroPadding + * NoPadding + +=== The Cipher Input === + +For the plaintext message, the cipher algorithms accept either strings or instances of CryptoJS.lib.WordArray. + +For the key, when you pass a string, it's treated as a passphrase and used to derive an actual key and IV. Or you can pass a WordArray that represents the actual key. If you pass the actual key, you must also pass the actual IV. + +For the ciphertext, the cipher algorithms accept either strings or instances of CryptoJS.lib.CipherParams. A CipherParams object represents a collection of parameters such as the IV, a salt, and the raw ciphertext itself. When you pass a string, it's automatically converted to a CipherParams object according to a configurable format strategy. + +=== The Cipher Output === + +The plaintext you get back after decryption is a WordArray object. See Hashers' Output for more detail. + +The ciphertext you get back after encryption isn't a string yet. It's a CipherParams object. A CipherParams object gives you access to all the parameters used during encryption. When you use a CipherParams object in a string context, it's automatically converted to a string according to a format strategy. The default is an OpenSSL-compatible format. + +{{{ + + +}}} + +You can define your own formats in order to be compatible with other crypto implementations. A format is an object with two methods—stringify and parse—that converts between CipherParams objects and ciphertext strings. + +Here's how you might write a JSON formatter: + +{{{ + + +}}} + +=== Progressive Ciphering === + +{{{ + + +}}} + +=== Interoperability === + +==== With OpenSSL ==== + +Encrypt with OpenSSL: + +{{{ +openssl enc -aes-256-cbc -in infile -out outfile -pass pass:"Secret Passphrase" -e -base64 +}}} + +Decrypt with CryptoJS: + +{{{ + + +}}} + +== Encoders == + +CryptoJS can convert from encoding formats such as Base64, Latin1 or Hex to WordArray objects and vica versa. + +{{{ + + + + +}}} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64.js new file mode 100644 index 0000000..152ca33 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64.js @@ -0,0 +1,136 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + var Base64 = C_enc.Base64 = { + /** + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + + return CryptoJS.enc.Base64; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64url.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64url.js new file mode 100644 index 0000000..9ffcc95 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-base64url.js @@ -0,0 +1,140 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64url encoding strategy. + */ + var Base64url = C_enc.Base64url = { + /** + * Converts a word array to a Base64url string. + * + * @param {WordArray} wordArray The word array. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {string} The Base64url string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64url.stringify(wordArray); + */ + stringify: function (wordArray, urlSafe=true) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = urlSafe ? this._safe_map : this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64url string to a word array. + * + * @param {string} base64Str The Base64url string. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64url.parse(base64String); + */ + parse: function (base64Str, urlSafe=true) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = urlSafe ? this._safe_map : this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + return CryptoJS.enc.Base64url; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-hex.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-hex.js new file mode 100644 index 0000000..daef773 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-hex.js @@ -0,0 +1,18 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.enc.Hex; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-latin1.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-latin1.js new file mode 100644 index 0000000..4991a9a --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-latin1.js @@ -0,0 +1,18 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.enc.Latin1; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf16.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf16.js new file mode 100644 index 0000000..585911a --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf16.js @@ -0,0 +1,149 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * UTF-16 BE encoding strategy. + */ + var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = { + /** + * Converts a word array to a UTF-16 BE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 BE string. + * + * @static + * + * @example + * + * var utf16String = CryptoJS.enc.Utf16.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff; + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 BE string to a word array. + * + * @param {string} utf16Str The UTF-16 BE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16.parse(utf16String); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + /** + * UTF-16 LE encoding strategy. + */ + C_enc.Utf16LE = { + /** + * Converts a word array to a UTF-16 LE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 LE string. + * + * @static + * + * @example + * + * var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff); + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 LE string to a word array. + * + * @param {string} utf16Str The UTF-16 LE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16)); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + function swapEndian(word) { + return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff); + } + }()); + + + return CryptoJS.enc.Utf16; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf8.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf8.js new file mode 100644 index 0000000..51e6a4a --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/enc-utf8.js @@ -0,0 +1,18 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.enc.Utf8; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/evpkdf.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/evpkdf.js new file mode 100644 index 0000000..1c50a42 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/evpkdf.js @@ -0,0 +1,134 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var MD5 = C_algo.MD5; + + /** + * This key derivation function is meant to conform with EVP_BytesToKey. + * www.openssl.org/docs/crypto/EVP_BytesToKey.html + */ + var EvpKDF = C_algo.EvpKDF = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hash algorithm to use. Default: MD5 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: MD5, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.EvpKDF.create(); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + var block; + + // Shortcut + var cfg = this.cfg; + + // Init hasher + var hasher = cfg.hasher.create(); + + // Initial values + var derivedKey = WordArray.create(); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + if (block) { + hasher.update(block); + } + block = hasher.update(password).finalize(salt); + hasher.reset(); + + // Iterations + for (var i = 1; i < iterations; i++) { + block = hasher.finalize(block); + hasher.reset(); + } + + derivedKey.concat(block); + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.EvpKDF(password, salt); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.EvpKDF = function (password, salt, cfg) { + return EvpKDF.create(cfg).compute(password, salt); + }; + }()); + + + return CryptoJS.EvpKDF; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-hex.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-hex.js new file mode 100644 index 0000000..69e0a6b --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-hex.js @@ -0,0 +1,66 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var CipherParams = C_lib.CipherParams; + var C_enc = C.enc; + var Hex = C_enc.Hex; + var C_format = C.format; + + var HexFormatter = C_format.Hex = { + /** + * Converts the ciphertext of a cipher params object to a hexadecimally encoded string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The hexadecimally encoded string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.format.Hex.stringify(cipherParams); + */ + stringify: function (cipherParams) { + return cipherParams.ciphertext.toString(Hex); + }, + + /** + * Converts a hexadecimally encoded ciphertext string to a cipher params object. + * + * @param {string} input The hexadecimally encoded string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.Hex.parse(hexString); + */ + parse: function (input) { + var ciphertext = Hex.parse(input); + return CipherParams.create({ ciphertext: ciphertext }); + } + }; + }()); + + + return CryptoJS.format.Hex; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-openssl.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-openssl.js new file mode 100644 index 0000000..5ee4a45 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/format-openssl.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.format.OpenSSL; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-md5.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-md5.js new file mode 100644 index 0000000..72b10c4 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-md5.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./md5"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./md5", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacMD5; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-ripemd160.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-ripemd160.js new file mode 100644 index 0000000..7f39618 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-ripemd160.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./ripemd160"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./ripemd160", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacRIPEMD160; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha1.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha1.js new file mode 100644 index 0000000..0e266da --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha1.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA1; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha224.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha224.js new file mode 100644 index 0000000..e6514d7 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha224.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256"), require("./sha224"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256", "./sha224", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA224; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha256.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha256.js new file mode 100644 index 0000000..e91a612 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha256.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA256; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha3.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha3.js new file mode 100644 index 0000000..9a2be02 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha3.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha3"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha3", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA3; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha384.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha384.js new file mode 100644 index 0000000..0e2f3e5 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha384.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512"), require("./sha384"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512", "./sha384", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA384; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha512.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha512.js new file mode 100644 index 0000000..bc77d30 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac-sha512.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA512; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac.js new file mode 100644 index 0000000..ee04ff5 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/hmac.js @@ -0,0 +1,143 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var C_algo = C.algo; + + /** + * HMAC algorithm. + */ + var HMAC = C_algo.HMAC = Base.extend({ + /** + * Initializes a newly created HMAC. + * + * @param {Hasher} hasher The hash algorithm to use. + * @param {WordArray|string} key The secret key. + * + * @example + * + * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + */ + init: function (hasher, key) { + // Init hasher + hasher = this._hasher = new hasher.init(); + + // Convert string to WordArray, else assume WordArray already + if (typeof key == 'string') { + key = Utf8.parse(key); + } + + // Shortcuts + var hasherBlockSize = hasher.blockSize; + var hasherBlockSizeBytes = hasherBlockSize * 4; + + // Allow arbitrary length keys + if (key.sigBytes > hasherBlockSizeBytes) { + key = hasher.finalize(key); + } + + // Clamp excess bits + key.clamp(); + + // Clone key for inner and outer pads + var oKey = this._oKey = key.clone(); + var iKey = this._iKey = key.clone(); + + // Shortcuts + var oKeyWords = oKey.words; + var iKeyWords = iKey.words; + + // XOR keys with pad constants + for (var i = 0; i < hasherBlockSize; i++) { + oKeyWords[i] ^= 0x5c5c5c5c; + iKeyWords[i] ^= 0x36363636; + } + oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes; + + // Set initial values + this.reset(); + }, + + /** + * Resets this HMAC to its initial state. + * + * @example + * + * hmacHasher.reset(); + */ + reset: function () { + // Shortcut + var hasher = this._hasher; + + // Reset + hasher.reset(); + hasher.update(this._iKey); + }, + + /** + * Updates this HMAC with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {HMAC} This HMAC instance. + * + * @example + * + * hmacHasher.update('message'); + * hmacHasher.update(wordArray); + */ + update: function (messageUpdate) { + this._hasher.update(messageUpdate); + + // Chainable + return this; + }, + + /** + * Finalizes the HMAC computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The HMAC. + * + * @example + * + * var hmac = hmacHasher.finalize(); + * var hmac = hmacHasher.finalize('message'); + * var hmac = hmacHasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Shortcut + var hasher = this._hasher; + + // Compute HMAC + var innerHash = hasher.finalize(messageUpdate); + hasher.reset(); + var hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); + + return hmac; + } + }); + }()); + + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/index.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/index.js new file mode 100644 index 0000000..a7be5d1 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/index.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./lib-typedarrays"), require("./enc-utf16"), require("./enc-base64"), require("./enc-base64url"), require("./md5"), require("./sha1"), require("./sha256"), require("./sha224"), require("./sha512"), require("./sha384"), require("./sha3"), require("./ripemd160"), require("./hmac"), require("./pbkdf2"), require("./evpkdf"), require("./cipher-core"), require("./mode-cfb"), require("./mode-ctr"), require("./mode-ctr-gladman"), require("./mode-ofb"), require("./mode-ecb"), require("./pad-ansix923"), require("./pad-iso10126"), require("./pad-iso97971"), require("./pad-zeropadding"), require("./pad-nopadding"), require("./format-hex"), require("./aes"), require("./tripledes"), require("./rc4"), require("./rabbit"), require("./rabbit-legacy")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./lib-typedarrays", "./enc-utf16", "./enc-base64", "./enc-base64url", "./md5", "./sha1", "./sha256", "./sha224", "./sha512", "./sha384", "./sha3", "./ripemd160", "./hmac", "./pbkdf2", "./evpkdf", "./cipher-core", "./mode-cfb", "./mode-ctr", "./mode-ctr-gladman", "./mode-ofb", "./mode-ecb", "./pad-ansix923", "./pad-iso10126", "./pad-iso97971", "./pad-zeropadding", "./pad-nopadding", "./format-hex", "./aes", "./tripledes", "./rc4", "./rabbit", "./rabbit-legacy"], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/lib-typedarrays.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/lib-typedarrays.js new file mode 100644 index 0000000..be49a40 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/lib-typedarrays.js @@ -0,0 +1,76 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Check if typed arrays are supported + if (typeof ArrayBuffer != 'function') { + return; + } + + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + + // Reference original init + var superInit = WordArray.init; + + // Augment WordArray.init to handle typed arrays + var subInit = WordArray.init = function (typedArray) { + // Convert buffers to uint8 + if (typedArray instanceof ArrayBuffer) { + typedArray = new Uint8Array(typedArray); + } + + // Convert other array views to uint8 + if ( + typedArray instanceof Int8Array || + (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) || + typedArray instanceof Int16Array || + typedArray instanceof Uint16Array || + typedArray instanceof Int32Array || + typedArray instanceof Uint32Array || + typedArray instanceof Float32Array || + typedArray instanceof Float64Array + ) { + typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); + } + + // Handle Uint8Array + if (typedArray instanceof Uint8Array) { + // Shortcut + var typedArrayByteLength = typedArray.byteLength; + + // Extract bytes + var words = []; + for (var i = 0; i < typedArrayByteLength; i++) { + words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); + } + + // Initialize this word array + superInit.call(this, words, typedArrayByteLength); + } else { + // Else call normal init + superInit.apply(this, arguments); + } + }; + + subInit.prototype = WordArray; + }()); + + + return CryptoJS.lib.WordArray; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/md5.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/md5.js new file mode 100644 index 0000000..f78592a --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/md5.js @@ -0,0 +1,268 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var T = []; + + // Compute constants + (function () { + for (var i = 0; i < 64; i++) { + T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + } + }()); + + /** + * MD5 hash algorithm. + */ + var MD5 = C_algo.MD5 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + + // Shortcuts + var H = this._hash.words; + + var M_offset_0 = M[offset + 0]; + var M_offset_1 = M[offset + 1]; + var M_offset_2 = M[offset + 2]; + var M_offset_3 = M[offset + 3]; + var M_offset_4 = M[offset + 4]; + var M_offset_5 = M[offset + 5]; + var M_offset_6 = M[offset + 6]; + var M_offset_7 = M[offset + 7]; + var M_offset_8 = M[offset + 8]; + var M_offset_9 = M[offset + 9]; + var M_offset_10 = M[offset + 10]; + var M_offset_11 = M[offset + 11]; + var M_offset_12 = M[offset + 12]; + var M_offset_13 = M[offset + 13]; + var M_offset_14 = M[offset + 14]; + var M_offset_15 = M[offset + 15]; + + // Working varialbes + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + + // Computation + a = FF(a, b, c, d, M_offset_0, 7, T[0]); + d = FF(d, a, b, c, M_offset_1, 12, T[1]); + c = FF(c, d, a, b, M_offset_2, 17, T[2]); + b = FF(b, c, d, a, M_offset_3, 22, T[3]); + a = FF(a, b, c, d, M_offset_4, 7, T[4]); + d = FF(d, a, b, c, M_offset_5, 12, T[5]); + c = FF(c, d, a, b, M_offset_6, 17, T[6]); + b = FF(b, c, d, a, M_offset_7, 22, T[7]); + a = FF(a, b, c, d, M_offset_8, 7, T[8]); + d = FF(d, a, b, c, M_offset_9, 12, T[9]); + c = FF(c, d, a, b, M_offset_10, 17, T[10]); + b = FF(b, c, d, a, M_offset_11, 22, T[11]); + a = FF(a, b, c, d, M_offset_12, 7, T[12]); + d = FF(d, a, b, c, M_offset_13, 12, T[13]); + c = FF(c, d, a, b, M_offset_14, 17, T[14]); + b = FF(b, c, d, a, M_offset_15, 22, T[15]); + + a = GG(a, b, c, d, M_offset_1, 5, T[16]); + d = GG(d, a, b, c, M_offset_6, 9, T[17]); + c = GG(c, d, a, b, M_offset_11, 14, T[18]); + b = GG(b, c, d, a, M_offset_0, 20, T[19]); + a = GG(a, b, c, d, M_offset_5, 5, T[20]); + d = GG(d, a, b, c, M_offset_10, 9, T[21]); + c = GG(c, d, a, b, M_offset_15, 14, T[22]); + b = GG(b, c, d, a, M_offset_4, 20, T[23]); + a = GG(a, b, c, d, M_offset_9, 5, T[24]); + d = GG(d, a, b, c, M_offset_14, 9, T[25]); + c = GG(c, d, a, b, M_offset_3, 14, T[26]); + b = GG(b, c, d, a, M_offset_8, 20, T[27]); + a = GG(a, b, c, d, M_offset_13, 5, T[28]); + d = GG(d, a, b, c, M_offset_2, 9, T[29]); + c = GG(c, d, a, b, M_offset_7, 14, T[30]); + b = GG(b, c, d, a, M_offset_12, 20, T[31]); + + a = HH(a, b, c, d, M_offset_5, 4, T[32]); + d = HH(d, a, b, c, M_offset_8, 11, T[33]); + c = HH(c, d, a, b, M_offset_11, 16, T[34]); + b = HH(b, c, d, a, M_offset_14, 23, T[35]); + a = HH(a, b, c, d, M_offset_1, 4, T[36]); + d = HH(d, a, b, c, M_offset_4, 11, T[37]); + c = HH(c, d, a, b, M_offset_7, 16, T[38]); + b = HH(b, c, d, a, M_offset_10, 23, T[39]); + a = HH(a, b, c, d, M_offset_13, 4, T[40]); + d = HH(d, a, b, c, M_offset_0, 11, T[41]); + c = HH(c, d, a, b, M_offset_3, 16, T[42]); + b = HH(b, c, d, a, M_offset_6, 23, T[43]); + a = HH(a, b, c, d, M_offset_9, 4, T[44]); + d = HH(d, a, b, c, M_offset_12, 11, T[45]); + c = HH(c, d, a, b, M_offset_15, 16, T[46]); + b = HH(b, c, d, a, M_offset_2, 23, T[47]); + + a = II(a, b, c, d, M_offset_0, 6, T[48]); + d = II(d, a, b, c, M_offset_7, 10, T[49]); + c = II(c, d, a, b, M_offset_14, 15, T[50]); + b = II(b, c, d, a, M_offset_5, 21, T[51]); + a = II(a, b, c, d, M_offset_12, 6, T[52]); + d = II(d, a, b, c, M_offset_3, 10, T[53]); + c = II(c, d, a, b, M_offset_10, 15, T[54]); + b = II(b, c, d, a, M_offset_1, 21, T[55]); + a = II(a, b, c, d, M_offset_8, 6, T[56]); + d = II(d, a, b, c, M_offset_15, 10, T[57]); + c = II(c, d, a, b, M_offset_6, 15, T[58]); + b = II(b, c, d, a, M_offset_13, 21, T[59]); + a = II(a, b, c, d, M_offset_4, 6, T[60]); + d = II(d, a, b, c, M_offset_11, 10, T[61]); + c = II(c, d, a, b, M_offset_2, 15, T[62]); + b = II(b, c, d, a, M_offset_9, 21, T[63]); + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + + var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); + var nBitsTotalL = nBitsTotal; + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( + (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | + (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) + ); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | + (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) + ); + + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 4; i++) { + // Shortcut + var H_i = H[i]; + + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + function FF(a, b, c, d, x, s, t) { + var n = a + ((b & c) | (~b & d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function GG(a, b, c, d, x, s, t) { + var n = a + ((b & d) | (c & ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function HH(a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function II(a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.MD5('message'); + * var hash = CryptoJS.MD5(wordArray); + */ + C.MD5 = Hasher._createHelper(MD5); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacMD5(message, key); + */ + C.HmacMD5 = Hasher._createHmacHelper(MD5); + }(Math)); + + + return CryptoJS.MD5; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-cfb.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-cfb.js new file mode 100644 index 0000000..b030840 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-cfb.js @@ -0,0 +1,80 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Cipher Feedback block mode. + */ + CryptoJS.mode.CFB = (function () { + var CFB = CryptoJS.lib.BlockCipherMode.extend(); + + CFB.Encryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + CFB.Decryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + var keystream; + + // Shortcut + var iv = this._iv; + + // Generate keystream + if (iv) { + keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + keystream = this._prevBlock; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + + return CFB; + }()); + + + return CryptoJS.mode.CFB; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr-gladman.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr-gladman.js new file mode 100644 index 0000000..9640129 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr-gladman.js @@ -0,0 +1,116 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** @preserve + * Counter block mode compatible with Dr Brian Gladman fileenc.c + * derived from CryptoJS.mode.CTR + * Jan Hruby jhruby.web@gmail.com + */ + CryptoJS.mode.CTRGladman = (function () { + var CTRGladman = CryptoJS.lib.BlockCipherMode.extend(); + + function incWord(word) + { + if (((word >> 24) & 0xff) === 0xff) { //overflow + var b1 = (word >> 16)&0xff; + var b2 = (word >> 8)&0xff; + var b3 = word & 0xff; + + if (b1 === 0xff) // overflow b1 + { + b1 = 0; + if (b2 === 0xff) + { + b2 = 0; + if (b3 === 0xff) + { + b3 = 0; + } + else + { + ++b3; + } + } + else + { + ++b2; + } + } + else + { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } + else + { + word += (0x01 << 24); + } + return word; + } + + function incCounter(counter) + { + if ((counter[0] = incWord(counter[0])) === 0) + { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = incWord(counter[1]); + } + return counter; + } + + var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + + incCounter(counter); + + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTRGladman.Decryptor = Encryptor; + + return CTRGladman; + }()); + + + + + return CryptoJS.mode.CTRGladman; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr.js new file mode 100644 index 0000000..e4073ac --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ctr.js @@ -0,0 +1,58 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Counter block mode. + */ + CryptoJS.mode.CTR = (function () { + var CTR = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = CTR.Encryptor = CTR.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Increment counter + counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTR.Decryptor = Encryptor; + + return CTR; + }()); + + + return CryptoJS.mode.CTR; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ecb.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ecb.js new file mode 100644 index 0000000..d44ea73 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ecb.js @@ -0,0 +1,40 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Electronic Codebook block mode. + */ + CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + } + }); + + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + } + }); + + return ECB; + }()); + + + return CryptoJS.mode.ECB; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ofb.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ofb.js new file mode 100644 index 0000000..b0417df --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/mode-ofb.js @@ -0,0 +1,54 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Output Feedback block mode. + */ + CryptoJS.mode.OFB = (function () { + var OFB = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = OFB.Encryptor = OFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var keystream = this._keystream; + + // Generate keystream + if (iv) { + keystream = this._keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + OFB.Decryptor = Encryptor; + + return OFB; + }()); + + + return CryptoJS.mode.OFB; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/package.json b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/package.json new file mode 100644 index 0000000..76bb388 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/package.json @@ -0,0 +1,42 @@ +{ + "name": "crypto-js", + "version": "4.1.1", + "description": "JavaScript library of crypto standards.", + "license": "MIT", + "author": { + "name": "Evan Vosberg", + "url": "http://github.com/evanvosberg" + }, + "homepage": "http://github.com/brix/crypto-js", + "repository": { + "type": "git", + "url": "http://github.com/brix/crypto-js.git" + }, + "keywords": [ + "security", + "crypto", + "Hash", + "MD5", + "SHA1", + "SHA-1", + "SHA256", + "SHA-256", + "RC4", + "Rabbit", + "AES", + "DES", + "PBKDF2", + "HMAC", + "OFB", + "CFB", + "CTR", + "CBC", + "Base64", + "Base64url" + ], + "main": "index.js", + "dependencies": {}, + "browser": { + "crypto": false + } +} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-ansix923.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-ansix923.js new file mode 100644 index 0000000..c29618e --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-ansix923.js @@ -0,0 +1,49 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ANSI X.923 padding strategy. + */ + CryptoJS.pad.AnsiX923 = { + pad: function (data, blockSize) { + // Shortcuts + var dataSigBytes = data.sigBytes; + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes; + + // Compute last byte position + var lastBytePos = dataSigBytes + nPaddingBytes - 1; + + // Pad + data.clamp(); + data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8); + data.sigBytes += nPaddingBytes; + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + return CryptoJS.pad.Ansix923; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso10126.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso10126.js new file mode 100644 index 0000000..d6bc3cc --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso10126.js @@ -0,0 +1,44 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ISO 10126 padding strategy. + */ + CryptoJS.pad.Iso10126 = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Pad + data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)). + concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1)); + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + return CryptoJS.pad.Iso10126; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso97971.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso97971.js new file mode 100644 index 0000000..2da3694 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-iso97971.js @@ -0,0 +1,40 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ISO/IEC 9797-1 Padding Method 2. + */ + CryptoJS.pad.Iso97971 = { + pad: function (data, blockSize) { + // Add 0x80 byte + data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1)); + + // Zero pad the rest + CryptoJS.pad.ZeroPadding.pad(data, blockSize); + }, + + unpad: function (data) { + // Remove zero padding + CryptoJS.pad.ZeroPadding.unpad(data); + + // Remove one more byte -- the 0x80 byte + data.sigBytes--; + } + }; + + + return CryptoJS.pad.Iso97971; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-nopadding.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-nopadding.js new file mode 100644 index 0000000..dd0103d --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-nopadding.js @@ -0,0 +1,30 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * A noop padding strategy. + */ + CryptoJS.pad.NoPadding = { + pad: function () { + }, + + unpad: function () { + } + }; + + + return CryptoJS.pad.NoPadding; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-pkcs7.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-pkcs7.js new file mode 100644 index 0000000..97078d2 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-pkcs7.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.pad.Pkcs7; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-zeropadding.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-zeropadding.js new file mode 100644 index 0000000..f342e11 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pad-zeropadding.js @@ -0,0 +1,47 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Zero padding strategy. + */ + CryptoJS.pad.ZeroPadding = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Pad + data.clamp(); + data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes); + }, + + unpad: function (data) { + // Shortcut + var dataWords = data.words; + + // Unpad + var i = data.sigBytes - 1; + for (var i = data.sigBytes - 1; i >= 0; i--) { + if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + data.sigBytes = i + 1; + break; + } + } + } + }; + + + return CryptoJS.pad.ZeroPadding; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pbkdf2.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pbkdf2.js new file mode 100644 index 0000000..0a490d7 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/pbkdf2.js @@ -0,0 +1,145 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA1 = C_algo.SHA1; + var HMAC = C_algo.HMAC; + + /** + * Password-Based Key Derivation Function 2 algorithm. + */ + var PBKDF2 = C_algo.PBKDF2 = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hasher to use. Default: SHA1 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: SHA1, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.PBKDF2.create(); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + var cfg = this.cfg; + + // Init HMAC + var hmac = HMAC.create(cfg.hasher, password); + + // Initial values + var derivedKey = WordArray.create(); + var blockIndex = WordArray.create([0x00000001]); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var blockIndexWords = blockIndex.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + var block = hmac.update(salt).finalize(blockIndex); + hmac.reset(); + + // Shortcuts + var blockWords = block.words; + var blockWordsLength = blockWords.length; + + // Iterations + var intermediate = block; + for (var i = 1; i < iterations; i++) { + intermediate = hmac.finalize(intermediate); + hmac.reset(); + + // Shortcut + var intermediateWords = intermediate.words; + + // XOR intermediate with block + for (var j = 0; j < blockWordsLength; j++) { + blockWords[j] ^= intermediateWords[j]; + } + } + + derivedKey.concat(block); + blockIndexWords[0]++; + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.PBKDF2(password, salt); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.PBKDF2 = function (password, salt, cfg) { + return PBKDF2.create(cfg).compute(password, salt); + }; + }()); + + + return CryptoJS.PBKDF2; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit-legacy.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit-legacy.js new file mode 100644 index 0000000..73a25bb --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit-legacy.js @@ -0,0 +1,190 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm. + * + * This is a legacy version that neglected to convert the key to little-endian. + * This error doesn't affect the cipher's security, + * but it does affect its compatibility with other implementations. + */ + var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg); + */ + C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy); + }()); + + + return CryptoJS.RabbitLegacy; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit.js new file mode 100644 index 0000000..80b0e9d --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rabbit.js @@ -0,0 +1,192 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm + */ + var Rabbit = C_algo.Rabbit = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Swap endian + for (var i = 0; i < 4; i++) { + K[i] = (((K[i] << 8) | (K[i] >>> 24)) & 0x00ff00ff) | + (((K[i] << 24) | (K[i] >>> 8)) & 0xff00ff00); + } + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg); + */ + C.Rabbit = StreamCipher._createHelper(Rabbit); + }()); + + + return CryptoJS.Rabbit; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rc4.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rc4.js new file mode 100644 index 0000000..d81a58c --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/rc4.js @@ -0,0 +1,139 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + /** + * RC4 stream cipher algorithm. + */ + var RC4 = C_algo.RC4 = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + var keySigBytes = key.sigBytes; + + // Init sbox + var S = this._S = []; + for (var i = 0; i < 256; i++) { + S[i] = i; + } + + // Key setup + for (var i = 0, j = 0; i < 256; i++) { + var keyByteIndex = i % keySigBytes; + var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff; + + j = (j + S[i] + keyByte) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + } + + // Counters + this._i = this._j = 0; + }, + + _doProcessBlock: function (M, offset) { + M[offset] ^= generateKeystreamWord.call(this); + }, + + keySize: 256/32, + + ivSize: 0 + }); + + function generateKeystreamWord() { + // Shortcuts + var S = this._S; + var i = this._i; + var j = this._j; + + // Generate keystream word + var keystreamWord = 0; + for (var n = 0; n < 4; n++) { + i = (i + 1) % 256; + j = (j + S[i]) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + + keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8); + } + + // Update counters + this._i = i; + this._j = j; + + return keystreamWord; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4.decrypt(ciphertext, key, cfg); + */ + C.RC4 = StreamCipher._createHelper(RC4); + + /** + * Modified RC4 stream cipher algorithm. + */ + var RC4Drop = C_algo.RC4Drop = RC4.extend({ + /** + * Configuration options. + * + * @property {number} drop The number of keystream words to drop. Default 192 + */ + cfg: RC4.cfg.extend({ + drop: 192 + }), + + _doReset: function () { + RC4._doReset.call(this); + + // Drop + for (var i = this.cfg.drop; i > 0; i--) { + generateKeystreamWord.call(this); + } + } + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg); + */ + C.RC4Drop = StreamCipher._createHelper(RC4Drop); + }()); + + + return CryptoJS.RC4; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/ripemd160.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/ripemd160.js new file mode 100644 index 0000000..022f175 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/ripemd160.js @@ -0,0 +1,267 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** @preserve + (c) 2012 by Cédric Mesnil. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var _zl = WordArray.create([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13]); + var _zr = WordArray.create([ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]); + var _sl = WordArray.create([ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ]); + var _sr = WordArray.create([ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ]); + + var _hl = WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]); + var _hr = WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]); + + /** + * RIPEMD160 hash algorithm. + */ + var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({ + _doReset: function () { + this._hash = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]); + }, + + _doProcessBlock: function (M, offset) { + + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + // Swap + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + // Shortcut + var H = this._hash.words; + var hl = _hl.words; + var hr = _hr.words; + var zl = _zl.words; + var zr = _zr.words; + var sl = _sl.words; + var sr = _sr.words; + + // Working variables + var al, bl, cl, dl, el; + var ar, br, cr, dr, er; + + ar = al = H[0]; + br = bl = H[1]; + cr = cl = H[2]; + dr = dl = H[3]; + er = el = H[4]; + // Computation + var t; + for (var i = 0; i < 80; i += 1) { + t = (al + M[offset+zl[i]])|0; + if (i<16){ + t += f1(bl,cl,dl) + hl[0]; + } else if (i<32) { + t += f2(bl,cl,dl) + hl[1]; + } else if (i<48) { + t += f3(bl,cl,dl) + hl[2]; + } else if (i<64) { + t += f4(bl,cl,dl) + hl[3]; + } else {// if (i<80) { + t += f5(bl,cl,dl) + hl[4]; + } + t = t|0; + t = rotl(t,sl[i]); + t = (t+el)|0; + al = el; + el = dl; + dl = rotl(cl, 10); + cl = bl; + bl = t; + + t = (ar + M[offset+zr[i]])|0; + if (i<16){ + t += f5(br,cr,dr) + hr[0]; + } else if (i<32) { + t += f4(br,cr,dr) + hr[1]; + } else if (i<48) { + t += f3(br,cr,dr) + hr[2]; + } else if (i<64) { + t += f2(br,cr,dr) + hr[3]; + } else {// if (i<80) { + t += f1(br,cr,dr) + hr[4]; + } + t = t|0; + t = rotl(t,sr[i]) ; + t = (t+er)|0; + ar = er; + er = dr; + dr = rotl(cr, 10); + cr = br; + br = t; + } + // Intermediate hash value + t = (H[1] + cl + dr)|0; + H[1] = (H[2] + dl + er)|0; + H[2] = (H[3] + el + ar)|0; + H[3] = (H[4] + al + br)|0; + H[4] = (H[0] + bl + cr)|0; + H[0] = t; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) | + (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00) + ); + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 5; i++) { + // Shortcut + var H_i = H[i]; + + // Swap + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + + function f1(x, y, z) { + return ((x) ^ (y) ^ (z)); + + } + + function f2(x, y, z) { + return (((x)&(y)) | ((~x)&(z))); + } + + function f3(x, y, z) { + return (((x) | (~(y))) ^ (z)); + } + + function f4(x, y, z) { + return (((x) & (z)) | ((y)&(~(z)))); + } + + function f5(x, y, z) { + return ((x) ^ ((y) |(~(z)))); + + } + + function rotl(x,n) { + return (x<>>(32-n)); + } + + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.RIPEMD160('message'); + * var hash = CryptoJS.RIPEMD160(wordArray); + */ + C.RIPEMD160 = Hasher._createHelper(RIPEMD160); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacRIPEMD160(message, key); + */ + C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160); + }(Math)); + + + return CryptoJS.RIPEMD160; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha1.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha1.js new file mode 100644 index 0000000..8568bb3 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha1.js @@ -0,0 +1,150 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Reusable object + var W = []; + + /** + * SHA-1 hash algorithm. + */ + var SHA1 = C_algo.SHA1 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + // Computation + for (var i = 0; i < 80; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = (n << 1) | (n >>> 31); + } + + var t = ((a << 5) | (a >>> 27)) + e + W[i]; + if (i < 20) { + t += ((b & c) | (~b & d)) + 0x5a827999; + } else if (i < 40) { + t += (b ^ c ^ d) + 0x6ed9eba1; + } else if (i < 60) { + t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; + } else /* if (i < 80) */ { + t += (b ^ c ^ d) - 0x359d3e2a; + } + + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA1('message'); + * var hash = CryptoJS.SHA1(wordArray); + */ + C.SHA1 = Hasher._createHelper(SHA1); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA1(message, key); + */ + C.HmacSHA1 = Hasher._createHmacHelper(SHA1); + }()); + + + return CryptoJS.SHA1; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha224.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha224.js new file mode 100644 index 0000000..b831ae5 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha224.js @@ -0,0 +1,80 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + + /** + * SHA-224 hash algorithm. + */ + var SHA224 = C_algo.SHA224 = SHA256.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]); + }, + + _doFinalize: function () { + var hash = SHA256._doFinalize.call(this); + + hash.sigBytes -= 4; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA224('message'); + * var hash = CryptoJS.SHA224(wordArray); + */ + C.SHA224 = SHA256._createHelper(SHA224); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA224(message, key); + */ + C.HmacSHA224 = SHA256._createHmacHelper(SHA224); + }()); + + + return CryptoJS.SHA224; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha256.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha256.js new file mode 100644 index 0000000..a8a4965 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha256.js @@ -0,0 +1,199 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + + return CryptoJS.SHA256; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha3.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha3.js new file mode 100644 index 0000000..6685057 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha3.js @@ -0,0 +1,326 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var C_algo = C.algo; + + // Constants tables + var RHO_OFFSETS = []; + var PI_INDEXES = []; + var ROUND_CONSTANTS = []; + + // Compute Constants + (function () { + // Compute rho offset constants + var x = 1, y = 0; + for (var t = 0; t < 24; t++) { + RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64; + + var newX = y % 5; + var newY = (2 * x + 3 * y) % 5; + x = newX; + y = newY; + } + + // Compute pi index constants + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5; + } + } + + // Compute round constants + var LFSR = 0x01; + for (var i = 0; i < 24; i++) { + var roundConstantMsw = 0; + var roundConstantLsw = 0; + + for (var j = 0; j < 7; j++) { + if (LFSR & 0x01) { + var bitPosition = (1 << j) - 1; + if (bitPosition < 32) { + roundConstantLsw ^= 1 << bitPosition; + } else /* if (bitPosition >= 32) */ { + roundConstantMsw ^= 1 << (bitPosition - 32); + } + } + + // Compute next LFSR + if (LFSR & 0x80) { + // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1 + LFSR = (LFSR << 1) ^ 0x71; + } else { + LFSR <<= 1; + } + } + + ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw); + } + }()); + + // Reusable objects for temporary values + var T = []; + (function () { + for (var i = 0; i < 25; i++) { + T[i] = X64Word.create(); + } + }()); + + /** + * SHA-3 hash algorithm. + */ + var SHA3 = C_algo.SHA3 = Hasher.extend({ + /** + * Configuration options. + * + * @property {number} outputLength + * The desired number of bits in the output hash. + * Only values permitted are: 224, 256, 384, 512. + * Default: 512 + */ + cfg: Hasher.cfg.extend({ + outputLength: 512 + }), + + _doReset: function () { + var state = this._state = [] + for (var i = 0; i < 25; i++) { + state[i] = new X64Word.init(); + } + + this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32; + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var state = this._state; + var nBlockSizeLanes = this.blockSize / 2; + + // Absorb + for (var i = 0; i < nBlockSizeLanes; i++) { + // Shortcuts + var M2i = M[offset + 2 * i]; + var M2i1 = M[offset + 2 * i + 1]; + + // Swap endian + M2i = ( + (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | + (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00) + ); + M2i1 = ( + (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | + (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00) + ); + + // Absorb message into state + var lane = state[i]; + lane.high ^= M2i1; + lane.low ^= M2i; + } + + // Rounds + for (var round = 0; round < 24; round++) { + // Theta + for (var x = 0; x < 5; x++) { + // Mix column lanes + var tMsw = 0, tLsw = 0; + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + tMsw ^= lane.high; + tLsw ^= lane.low; + } + + // Temporary values + var Tx = T[x]; + Tx.high = tMsw; + Tx.low = tLsw; + } + for (var x = 0; x < 5; x++) { + // Shortcuts + var Tx4 = T[(x + 4) % 5]; + var Tx1 = T[(x + 1) % 5]; + var Tx1Msw = Tx1.high; + var Tx1Lsw = Tx1.low; + + // Mix surrounding columns + var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31)); + var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31)); + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + lane.high ^= tMsw; + lane.low ^= tLsw; + } + } + + // Rho Pi + for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + + // Shortcuts + var lane = state[laneIndex]; + var laneMsw = lane.high; + var laneLsw = lane.low; + var rhoOffset = RHO_OFFSETS[laneIndex]; + + // Rotate lanes + if (rhoOffset < 32) { + tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + } else /* if (rhoOffset >= 32) */ { + tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + } + + // Transpose lanes + var TPiLane = T[PI_INDEXES[laneIndex]]; + TPiLane.high = tMsw; + TPiLane.low = tLsw; + } + + // Rho pi at x = y = 0 + var T0 = T[0]; + var state0 = state[0]; + T0.high = state0.high; + T0.low = state0.low; + + // Chi + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + // Shortcuts + var laneIndex = x + 5 * y; + var lane = state[laneIndex]; + var TLane = T[laneIndex]; + var Tx1Lane = T[((x + 1) % 5) + 5 * y]; + var Tx2Lane = T[((x + 2) % 5) + 5 * y]; + + // Mix rows + lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high); + lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low); + } + } + + // Iota + var lane = state[0]; + var roundConstant = ROUND_CONSTANTS[round]; + lane.high ^= roundConstant.high; + lane.low ^= roundConstant.low; + } + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + var blockSizeBits = this.blockSize * 32; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32); + dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var state = this._state; + var outputLengthBytes = this.cfg.outputLength / 8; + var outputLengthLanes = outputLengthBytes / 8; + + // Squeeze + var hashWords = []; + for (var i = 0; i < outputLengthLanes; i++) { + // Shortcuts + var lane = state[i]; + var laneMsw = lane.high; + var laneLsw = lane.low; + + // Swap endian + laneMsw = ( + (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | + (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00) + ); + laneLsw = ( + (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | + (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00) + ); + + // Squeeze state to retrieve hash + hashWords.push(laneLsw); + hashWords.push(laneMsw); + } + + // Return final computed hash + return new WordArray.init(hashWords, outputLengthBytes); + }, + + clone: function () { + var clone = Hasher.clone.call(this); + + var state = clone._state = this._state.slice(0); + for (var i = 0; i < 25; i++) { + state[i] = state[i].clone(); + } + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA3('message'); + * var hash = CryptoJS.SHA3(wordArray); + */ + C.SHA3 = Hasher._createHelper(SHA3); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA3(message, key); + */ + C.HmacSHA3 = Hasher._createHmacHelper(SHA3); + }(Math)); + + + return CryptoJS.SHA3; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha384.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha384.js new file mode 100644 index 0000000..7783bf6 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha384.js @@ -0,0 +1,83 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + var SHA512 = C_algo.SHA512; + + /** + * SHA-384 hash algorithm. + */ + var SHA384 = C_algo.SHA384 = SHA512.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507), + new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939), + new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511), + new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4) + ]); + }, + + _doFinalize: function () { + var hash = SHA512._doFinalize.call(this); + + hash.sigBytes -= 16; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA384('message'); + * var hash = CryptoJS.SHA384(wordArray); + */ + C.SHA384 = SHA512._createHelper(SHA384); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA384(message, key); + */ + C.HmacSHA384 = SHA512._createHmacHelper(SHA384); + }()); + + + return CryptoJS.SHA384; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha512.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha512.js new file mode 100644 index 0000000..85ccc9e --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/sha512.js @@ -0,0 +1,326 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + + function X64Word_create() { + return X64Word.create.apply(X64Word, arguments); + } + + // Constants + var K = [ + X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), + X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), + X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), + X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), + X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), + X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), + X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), + X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), + X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), + X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), + X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), + X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), + X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), + X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), + X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), + X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), + X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), + X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), + X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), + X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), + X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), + X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), + X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), + X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), + X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), + X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), + X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), + X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), + X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), + X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), + X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), + X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), + X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), + X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), + X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), + X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), + X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), + X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), + X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), + X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) + ]; + + // Reusable objects + var W = []; + (function () { + for (var i = 0; i < 80; i++) { + W[i] = X64Word_create(); + } + }()); + + /** + * SHA-512 hash algorithm. + */ + var SHA512 = C_algo.SHA512 = Hasher.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), + new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), + new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), + new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var H = this._hash.words; + + var H0 = H[0]; + var H1 = H[1]; + var H2 = H[2]; + var H3 = H[3]; + var H4 = H[4]; + var H5 = H[5]; + var H6 = H[6]; + var H7 = H[7]; + + var H0h = H0.high; + var H0l = H0.low; + var H1h = H1.high; + var H1l = H1.low; + var H2h = H2.high; + var H2l = H2.low; + var H3h = H3.high; + var H3l = H3.low; + var H4h = H4.high; + var H4l = H4.low; + var H5h = H5.high; + var H5l = H5.low; + var H6h = H6.high; + var H6l = H6.low; + var H7h = H7.high; + var H7l = H7.low; + + // Working variables + var ah = H0h; + var al = H0l; + var bh = H1h; + var bl = H1l; + var ch = H2h; + var cl = H2l; + var dh = H3h; + var dl = H3l; + var eh = H4h; + var el = H4l; + var fh = H5h; + var fl = H5l; + var gh = H6h; + var gl = H6l; + var hh = H7h; + var hl = H7l; + + // Rounds + for (var i = 0; i < 80; i++) { + var Wil; + var Wih; + + // Shortcut + var Wi = W[i]; + + // Extend message + if (i < 16) { + Wih = Wi.high = M[offset + i * 2] | 0; + Wil = Wi.low = M[offset + i * 2 + 1] | 0; + } else { + // Gamma0 + var gamma0x = W[i - 15]; + var gamma0xh = gamma0x.high; + var gamma0xl = gamma0x.low; + var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); + var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); + + // Gamma1 + var gamma1x = W[i - 2]; + var gamma1xh = gamma1x.high; + var gamma1xl = gamma1x.low; + var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); + var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7 = W[i - 7]; + var Wi7h = Wi7.high; + var Wi7l = Wi7.low; + + var Wi16 = W[i - 16]; + var Wi16h = Wi16.high; + var Wi16l = Wi16.low; + + Wil = gamma0l + Wi7l; + Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + Wil = Wil + gamma1l; + Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + Wil = Wil + Wi16l; + Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + + Wi.high = Wih; + Wi.low = Wil; + } + + var chh = (eh & fh) ^ (~eh & gh); + var chl = (el & fl) ^ (~el & gl); + var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); + var majl = (al & bl) ^ (al & cl) ^ (bl & cl); + + var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); + var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); + var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); + var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); + + // t1 = h + sigma1 + ch + K[i] + W[i] + var Ki = K[i]; + var Kih = Ki.high; + var Kil = Ki.low; + + var t1l = hl + sigma1l; + var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); + var t1l = t1l + chl; + var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); + var t1l = t1l + Kil; + var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); + var t1l = t1l + Wil; + var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); + + // t2 = sigma0 + maj + var t2l = sigma0l + majl; + var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); + + // Update working variables + hh = gh; + hl = gl; + gh = fh; + gl = fl; + fh = eh; + fl = el; + el = (dl + t1l) | 0; + eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; + dh = ch; + dl = cl; + ch = bh; + cl = bl; + bh = ah; + bl = al; + al = (t1l + t2l) | 0; + ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; + } + + // Intermediate hash value + H0l = H0.low = (H0l + al); + H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); + H1l = H1.low = (H1l + bl); + H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); + H2l = H2.low = (H2l + cl); + H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); + H3l = H3.low = (H3l + dl); + H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); + H4l = H4.low = (H4l + el); + H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); + H5l = H5.low = (H5l + fl); + H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); + H6l = H6.low = (H6l + gl); + H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); + H7l = H7.low = (H7l + hl); + H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Convert hash to 32-bit word array before returning + var hash = this._hash.toX32(); + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + + blockSize: 1024/32 + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA512('message'); + * var hash = CryptoJS.SHA512(wordArray); + */ + C.SHA512 = Hasher._createHelper(SHA512); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA512(message, key); + */ + C.HmacSHA512 = Hasher._createHmacHelper(SHA512); + }()); + + + return CryptoJS.SHA512; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/tripledes.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/tripledes.js new file mode 100644 index 0000000..f05d703 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/tripledes.js @@ -0,0 +1,779 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Permuted Choice 1 constants + var PC1 = [ + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, + 31, 23, 15, 7, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 28, 20, 12, 4 + ]; + + // Permuted Choice 2 constants + var PC2 = [ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 + ]; + + // Cumulative bit shift constants + var BIT_SHIFTS = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; + + // SBOXes and round permutation constants + var SBOX_P = [ + { + 0x0: 0x808200, + 0x10000000: 0x8000, + 0x20000000: 0x808002, + 0x30000000: 0x2, + 0x40000000: 0x200, + 0x50000000: 0x808202, + 0x60000000: 0x800202, + 0x70000000: 0x800000, + 0x80000000: 0x202, + 0x90000000: 0x800200, + 0xa0000000: 0x8200, + 0xb0000000: 0x808000, + 0xc0000000: 0x8002, + 0xd0000000: 0x800002, + 0xe0000000: 0x0, + 0xf0000000: 0x8202, + 0x8000000: 0x0, + 0x18000000: 0x808202, + 0x28000000: 0x8202, + 0x38000000: 0x8000, + 0x48000000: 0x808200, + 0x58000000: 0x200, + 0x68000000: 0x808002, + 0x78000000: 0x2, + 0x88000000: 0x800200, + 0x98000000: 0x8200, + 0xa8000000: 0x808000, + 0xb8000000: 0x800202, + 0xc8000000: 0x800002, + 0xd8000000: 0x8002, + 0xe8000000: 0x202, + 0xf8000000: 0x800000, + 0x1: 0x8000, + 0x10000001: 0x2, + 0x20000001: 0x808200, + 0x30000001: 0x800000, + 0x40000001: 0x808002, + 0x50000001: 0x8200, + 0x60000001: 0x200, + 0x70000001: 0x800202, + 0x80000001: 0x808202, + 0x90000001: 0x808000, + 0xa0000001: 0x800002, + 0xb0000001: 0x8202, + 0xc0000001: 0x202, + 0xd0000001: 0x800200, + 0xe0000001: 0x8002, + 0xf0000001: 0x0, + 0x8000001: 0x808202, + 0x18000001: 0x808000, + 0x28000001: 0x800000, + 0x38000001: 0x200, + 0x48000001: 0x8000, + 0x58000001: 0x800002, + 0x68000001: 0x2, + 0x78000001: 0x8202, + 0x88000001: 0x8002, + 0x98000001: 0x800202, + 0xa8000001: 0x202, + 0xb8000001: 0x808200, + 0xc8000001: 0x800200, + 0xd8000001: 0x0, + 0xe8000001: 0x8200, + 0xf8000001: 0x808002 + }, + { + 0x0: 0x40084010, + 0x1000000: 0x4000, + 0x2000000: 0x80000, + 0x3000000: 0x40080010, + 0x4000000: 0x40000010, + 0x5000000: 0x40084000, + 0x6000000: 0x40004000, + 0x7000000: 0x10, + 0x8000000: 0x84000, + 0x9000000: 0x40004010, + 0xa000000: 0x40000000, + 0xb000000: 0x84010, + 0xc000000: 0x80010, + 0xd000000: 0x0, + 0xe000000: 0x4010, + 0xf000000: 0x40080000, + 0x800000: 0x40004000, + 0x1800000: 0x84010, + 0x2800000: 0x10, + 0x3800000: 0x40004010, + 0x4800000: 0x40084010, + 0x5800000: 0x40000000, + 0x6800000: 0x80000, + 0x7800000: 0x40080010, + 0x8800000: 0x80010, + 0x9800000: 0x0, + 0xa800000: 0x4000, + 0xb800000: 0x40080000, + 0xc800000: 0x40000010, + 0xd800000: 0x84000, + 0xe800000: 0x40084000, + 0xf800000: 0x4010, + 0x10000000: 0x0, + 0x11000000: 0x40080010, + 0x12000000: 0x40004010, + 0x13000000: 0x40084000, + 0x14000000: 0x40080000, + 0x15000000: 0x10, + 0x16000000: 0x84010, + 0x17000000: 0x4000, + 0x18000000: 0x4010, + 0x19000000: 0x80000, + 0x1a000000: 0x80010, + 0x1b000000: 0x40000010, + 0x1c000000: 0x84000, + 0x1d000000: 0x40004000, + 0x1e000000: 0x40000000, + 0x1f000000: 0x40084010, + 0x10800000: 0x84010, + 0x11800000: 0x80000, + 0x12800000: 0x40080000, + 0x13800000: 0x4000, + 0x14800000: 0x40004000, + 0x15800000: 0x40084010, + 0x16800000: 0x10, + 0x17800000: 0x40000000, + 0x18800000: 0x40084000, + 0x19800000: 0x40000010, + 0x1a800000: 0x40004010, + 0x1b800000: 0x80010, + 0x1c800000: 0x0, + 0x1d800000: 0x4010, + 0x1e800000: 0x40080010, + 0x1f800000: 0x84000 + }, + { + 0x0: 0x104, + 0x100000: 0x0, + 0x200000: 0x4000100, + 0x300000: 0x10104, + 0x400000: 0x10004, + 0x500000: 0x4000004, + 0x600000: 0x4010104, + 0x700000: 0x4010000, + 0x800000: 0x4000000, + 0x900000: 0x4010100, + 0xa00000: 0x10100, + 0xb00000: 0x4010004, + 0xc00000: 0x4000104, + 0xd00000: 0x10000, + 0xe00000: 0x4, + 0xf00000: 0x100, + 0x80000: 0x4010100, + 0x180000: 0x4010004, + 0x280000: 0x0, + 0x380000: 0x4000100, + 0x480000: 0x4000004, + 0x580000: 0x10000, + 0x680000: 0x10004, + 0x780000: 0x104, + 0x880000: 0x4, + 0x980000: 0x100, + 0xa80000: 0x4010000, + 0xb80000: 0x10104, + 0xc80000: 0x10100, + 0xd80000: 0x4000104, + 0xe80000: 0x4010104, + 0xf80000: 0x4000000, + 0x1000000: 0x4010100, + 0x1100000: 0x10004, + 0x1200000: 0x10000, + 0x1300000: 0x4000100, + 0x1400000: 0x100, + 0x1500000: 0x4010104, + 0x1600000: 0x4000004, + 0x1700000: 0x0, + 0x1800000: 0x4000104, + 0x1900000: 0x4000000, + 0x1a00000: 0x4, + 0x1b00000: 0x10100, + 0x1c00000: 0x4010000, + 0x1d00000: 0x104, + 0x1e00000: 0x10104, + 0x1f00000: 0x4010004, + 0x1080000: 0x4000000, + 0x1180000: 0x104, + 0x1280000: 0x4010100, + 0x1380000: 0x0, + 0x1480000: 0x10004, + 0x1580000: 0x4000100, + 0x1680000: 0x100, + 0x1780000: 0x4010004, + 0x1880000: 0x10000, + 0x1980000: 0x4010104, + 0x1a80000: 0x10104, + 0x1b80000: 0x4000004, + 0x1c80000: 0x4000104, + 0x1d80000: 0x4010000, + 0x1e80000: 0x4, + 0x1f80000: 0x10100 + }, + { + 0x0: 0x80401000, + 0x10000: 0x80001040, + 0x20000: 0x401040, + 0x30000: 0x80400000, + 0x40000: 0x0, + 0x50000: 0x401000, + 0x60000: 0x80000040, + 0x70000: 0x400040, + 0x80000: 0x80000000, + 0x90000: 0x400000, + 0xa0000: 0x40, + 0xb0000: 0x80001000, + 0xc0000: 0x80400040, + 0xd0000: 0x1040, + 0xe0000: 0x1000, + 0xf0000: 0x80401040, + 0x8000: 0x80001040, + 0x18000: 0x40, + 0x28000: 0x80400040, + 0x38000: 0x80001000, + 0x48000: 0x401000, + 0x58000: 0x80401040, + 0x68000: 0x0, + 0x78000: 0x80400000, + 0x88000: 0x1000, + 0x98000: 0x80401000, + 0xa8000: 0x400000, + 0xb8000: 0x1040, + 0xc8000: 0x80000000, + 0xd8000: 0x400040, + 0xe8000: 0x401040, + 0xf8000: 0x80000040, + 0x100000: 0x400040, + 0x110000: 0x401000, + 0x120000: 0x80000040, + 0x130000: 0x0, + 0x140000: 0x1040, + 0x150000: 0x80400040, + 0x160000: 0x80401000, + 0x170000: 0x80001040, + 0x180000: 0x80401040, + 0x190000: 0x80000000, + 0x1a0000: 0x80400000, + 0x1b0000: 0x401040, + 0x1c0000: 0x80001000, + 0x1d0000: 0x400000, + 0x1e0000: 0x40, + 0x1f0000: 0x1000, + 0x108000: 0x80400000, + 0x118000: 0x80401040, + 0x128000: 0x0, + 0x138000: 0x401000, + 0x148000: 0x400040, + 0x158000: 0x80000000, + 0x168000: 0x80001040, + 0x178000: 0x40, + 0x188000: 0x80000040, + 0x198000: 0x1000, + 0x1a8000: 0x80001000, + 0x1b8000: 0x80400040, + 0x1c8000: 0x1040, + 0x1d8000: 0x80401000, + 0x1e8000: 0x400000, + 0x1f8000: 0x401040 + }, + { + 0x0: 0x80, + 0x1000: 0x1040000, + 0x2000: 0x40000, + 0x3000: 0x20000000, + 0x4000: 0x20040080, + 0x5000: 0x1000080, + 0x6000: 0x21000080, + 0x7000: 0x40080, + 0x8000: 0x1000000, + 0x9000: 0x20040000, + 0xa000: 0x20000080, + 0xb000: 0x21040080, + 0xc000: 0x21040000, + 0xd000: 0x0, + 0xe000: 0x1040080, + 0xf000: 0x21000000, + 0x800: 0x1040080, + 0x1800: 0x21000080, + 0x2800: 0x80, + 0x3800: 0x1040000, + 0x4800: 0x40000, + 0x5800: 0x20040080, + 0x6800: 0x21040000, + 0x7800: 0x20000000, + 0x8800: 0x20040000, + 0x9800: 0x0, + 0xa800: 0x21040080, + 0xb800: 0x1000080, + 0xc800: 0x20000080, + 0xd800: 0x21000000, + 0xe800: 0x1000000, + 0xf800: 0x40080, + 0x10000: 0x40000, + 0x11000: 0x80, + 0x12000: 0x20000000, + 0x13000: 0x21000080, + 0x14000: 0x1000080, + 0x15000: 0x21040000, + 0x16000: 0x20040080, + 0x17000: 0x1000000, + 0x18000: 0x21040080, + 0x19000: 0x21000000, + 0x1a000: 0x1040000, + 0x1b000: 0x20040000, + 0x1c000: 0x40080, + 0x1d000: 0x20000080, + 0x1e000: 0x0, + 0x1f000: 0x1040080, + 0x10800: 0x21000080, + 0x11800: 0x1000000, + 0x12800: 0x1040000, + 0x13800: 0x20040080, + 0x14800: 0x20000000, + 0x15800: 0x1040080, + 0x16800: 0x80, + 0x17800: 0x21040000, + 0x18800: 0x40080, + 0x19800: 0x21040080, + 0x1a800: 0x0, + 0x1b800: 0x21000000, + 0x1c800: 0x1000080, + 0x1d800: 0x40000, + 0x1e800: 0x20040000, + 0x1f800: 0x20000080 + }, + { + 0x0: 0x10000008, + 0x100: 0x2000, + 0x200: 0x10200000, + 0x300: 0x10202008, + 0x400: 0x10002000, + 0x500: 0x200000, + 0x600: 0x200008, + 0x700: 0x10000000, + 0x800: 0x0, + 0x900: 0x10002008, + 0xa00: 0x202000, + 0xb00: 0x8, + 0xc00: 0x10200008, + 0xd00: 0x202008, + 0xe00: 0x2008, + 0xf00: 0x10202000, + 0x80: 0x10200000, + 0x180: 0x10202008, + 0x280: 0x8, + 0x380: 0x200000, + 0x480: 0x202008, + 0x580: 0x10000008, + 0x680: 0x10002000, + 0x780: 0x2008, + 0x880: 0x200008, + 0x980: 0x2000, + 0xa80: 0x10002008, + 0xb80: 0x10200008, + 0xc80: 0x0, + 0xd80: 0x10202000, + 0xe80: 0x202000, + 0xf80: 0x10000000, + 0x1000: 0x10002000, + 0x1100: 0x10200008, + 0x1200: 0x10202008, + 0x1300: 0x2008, + 0x1400: 0x200000, + 0x1500: 0x10000000, + 0x1600: 0x10000008, + 0x1700: 0x202000, + 0x1800: 0x202008, + 0x1900: 0x0, + 0x1a00: 0x8, + 0x1b00: 0x10200000, + 0x1c00: 0x2000, + 0x1d00: 0x10002008, + 0x1e00: 0x10202000, + 0x1f00: 0x200008, + 0x1080: 0x8, + 0x1180: 0x202000, + 0x1280: 0x200000, + 0x1380: 0x10000008, + 0x1480: 0x10002000, + 0x1580: 0x2008, + 0x1680: 0x10202008, + 0x1780: 0x10200000, + 0x1880: 0x10202000, + 0x1980: 0x10200008, + 0x1a80: 0x2000, + 0x1b80: 0x202008, + 0x1c80: 0x200008, + 0x1d80: 0x0, + 0x1e80: 0x10000000, + 0x1f80: 0x10002008 + }, + { + 0x0: 0x100000, + 0x10: 0x2000401, + 0x20: 0x400, + 0x30: 0x100401, + 0x40: 0x2100401, + 0x50: 0x0, + 0x60: 0x1, + 0x70: 0x2100001, + 0x80: 0x2000400, + 0x90: 0x100001, + 0xa0: 0x2000001, + 0xb0: 0x2100400, + 0xc0: 0x2100000, + 0xd0: 0x401, + 0xe0: 0x100400, + 0xf0: 0x2000000, + 0x8: 0x2100001, + 0x18: 0x0, + 0x28: 0x2000401, + 0x38: 0x2100400, + 0x48: 0x100000, + 0x58: 0x2000001, + 0x68: 0x2000000, + 0x78: 0x401, + 0x88: 0x100401, + 0x98: 0x2000400, + 0xa8: 0x2100000, + 0xb8: 0x100001, + 0xc8: 0x400, + 0xd8: 0x2100401, + 0xe8: 0x1, + 0xf8: 0x100400, + 0x100: 0x2000000, + 0x110: 0x100000, + 0x120: 0x2000401, + 0x130: 0x2100001, + 0x140: 0x100001, + 0x150: 0x2000400, + 0x160: 0x2100400, + 0x170: 0x100401, + 0x180: 0x401, + 0x190: 0x2100401, + 0x1a0: 0x100400, + 0x1b0: 0x1, + 0x1c0: 0x0, + 0x1d0: 0x2100000, + 0x1e0: 0x2000001, + 0x1f0: 0x400, + 0x108: 0x100400, + 0x118: 0x2000401, + 0x128: 0x2100001, + 0x138: 0x1, + 0x148: 0x2000000, + 0x158: 0x100000, + 0x168: 0x401, + 0x178: 0x2100400, + 0x188: 0x2000001, + 0x198: 0x2100000, + 0x1a8: 0x0, + 0x1b8: 0x2100401, + 0x1c8: 0x100401, + 0x1d8: 0x400, + 0x1e8: 0x2000400, + 0x1f8: 0x100001 + }, + { + 0x0: 0x8000820, + 0x1: 0x20000, + 0x2: 0x8000000, + 0x3: 0x20, + 0x4: 0x20020, + 0x5: 0x8020820, + 0x6: 0x8020800, + 0x7: 0x800, + 0x8: 0x8020000, + 0x9: 0x8000800, + 0xa: 0x20800, + 0xb: 0x8020020, + 0xc: 0x820, + 0xd: 0x0, + 0xe: 0x8000020, + 0xf: 0x20820, + 0x80000000: 0x800, + 0x80000001: 0x8020820, + 0x80000002: 0x8000820, + 0x80000003: 0x8000000, + 0x80000004: 0x8020000, + 0x80000005: 0x20800, + 0x80000006: 0x20820, + 0x80000007: 0x20, + 0x80000008: 0x8000020, + 0x80000009: 0x820, + 0x8000000a: 0x20020, + 0x8000000b: 0x8020800, + 0x8000000c: 0x0, + 0x8000000d: 0x8020020, + 0x8000000e: 0x8000800, + 0x8000000f: 0x20000, + 0x10: 0x20820, + 0x11: 0x8020800, + 0x12: 0x20, + 0x13: 0x800, + 0x14: 0x8000800, + 0x15: 0x8000020, + 0x16: 0x8020020, + 0x17: 0x20000, + 0x18: 0x0, + 0x19: 0x20020, + 0x1a: 0x8020000, + 0x1b: 0x8000820, + 0x1c: 0x8020820, + 0x1d: 0x20800, + 0x1e: 0x820, + 0x1f: 0x8000000, + 0x80000010: 0x20000, + 0x80000011: 0x800, + 0x80000012: 0x8020020, + 0x80000013: 0x20820, + 0x80000014: 0x20, + 0x80000015: 0x8020000, + 0x80000016: 0x8000000, + 0x80000017: 0x8000820, + 0x80000018: 0x8020820, + 0x80000019: 0x8000020, + 0x8000001a: 0x8000800, + 0x8000001b: 0x0, + 0x8000001c: 0x20800, + 0x8000001d: 0x820, + 0x8000001e: 0x20020, + 0x8000001f: 0x8020800 + } + ]; + + // Masks that select the SBOX input + var SBOX_MASK = [ + 0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000, + 0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f + ]; + + /** + * DES block cipher algorithm. + */ + var DES = C_algo.DES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + + // Select 56 bits according to PC1 + var keyBits = []; + for (var i = 0; i < 56; i++) { + var keyBitPos = PC1[i] - 1; + keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1; + } + + // Assemble 16 subkeys + var subKeys = this._subKeys = []; + for (var nSubKey = 0; nSubKey < 16; nSubKey++) { + // Create subkey + var subKey = subKeys[nSubKey] = []; + + // Shortcut + var bitShift = BIT_SHIFTS[nSubKey]; + + // Select 48 bits according to PC2 + for (var i = 0; i < 24; i++) { + // Select from the left 28 key bits + subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6); + + // Select from the right 28 key bits + subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6); + } + + // Since each subkey is applied to an expanded 32-bit input, + // the subkey can be broken into 8 values scaled to 32-bits, + // which allows the key to be used without expansion + subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31); + for (var i = 1; i < 7; i++) { + subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3); + } + subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27); + } + + // Compute inverse subkeys + var invSubKeys = this._invSubKeys = []; + for (var i = 0; i < 16; i++) { + invSubKeys[i] = subKeys[15 - i]; + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._subKeys); + }, + + decryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._invSubKeys); + }, + + _doCryptBlock: function (M, offset, subKeys) { + // Get input + this._lBlock = M[offset]; + this._rBlock = M[offset + 1]; + + // Initial permutation + exchangeLR.call(this, 4, 0x0f0f0f0f); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeRL.call(this, 2, 0x33333333); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeLR.call(this, 1, 0x55555555); + + // Rounds + for (var round = 0; round < 16; round++) { + // Shortcuts + var subKey = subKeys[round]; + var lBlock = this._lBlock; + var rBlock = this._rBlock; + + // Feistel function + var f = 0; + for (var i = 0; i < 8; i++) { + f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0]; + } + this._lBlock = rBlock; + this._rBlock = lBlock ^ f; + } + + // Undo swap from last round + var t = this._lBlock; + this._lBlock = this._rBlock; + this._rBlock = t; + + // Final permutation + exchangeLR.call(this, 1, 0x55555555); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeRL.call(this, 2, 0x33333333); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeLR.call(this, 4, 0x0f0f0f0f); + + // Set output + M[offset] = this._lBlock; + M[offset + 1] = this._rBlock; + }, + + keySize: 64/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + // Swap bits across the left and right words + function exchangeLR(offset, mask) { + var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask; + this._rBlock ^= t; + this._lBlock ^= t << offset; + } + + function exchangeRL(offset, mask) { + var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask; + this._lBlock ^= t; + this._rBlock ^= t << offset; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.DES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.DES.decrypt(ciphertext, key, cfg); + */ + C.DES = BlockCipher._createHelper(DES); + + /** + * Triple-DES block cipher algorithm. + */ + var TripleDES = C_algo.TripleDES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + // Make sure the key length is valid (64, 128 or >= 192 bit) + if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) { + throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.'); + } + + // Extend the key according to the keying options defined in 3DES standard + var key1 = keyWords.slice(0, 2); + var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4); + var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6); + + // Create DES instances + this._des1 = DES.createEncryptor(WordArray.create(key1)); + this._des2 = DES.createEncryptor(WordArray.create(key2)); + this._des3 = DES.createEncryptor(WordArray.create(key3)); + }, + + encryptBlock: function (M, offset) { + this._des1.encryptBlock(M, offset); + this._des2.decryptBlock(M, offset); + this._des3.encryptBlock(M, offset); + }, + + decryptBlock: function (M, offset) { + this._des3.decryptBlock(M, offset); + this._des2.encryptBlock(M, offset); + this._des1.decryptBlock(M, offset); + }, + + keySize: 192/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg); + */ + C.TripleDES = BlockCipher._createHelper(TripleDES); + }()); + + + return CryptoJS.TripleDES; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/x64-core.js b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/x64-core.js new file mode 100644 index 0000000..5e401f2 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/aes/crypto-js-master/x64-core.js @@ -0,0 +1,304 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var X32WordArray = C_lib.WordArray; + + /** + * x64 namespace. + */ + var C_x64 = C.x64 = {}; + + /** + * A 64-bit word. + */ + var X64Word = C_x64.Word = Base.extend({ + /** + * Initializes a newly created 64-bit word. + * + * @param {number} high The high 32 bits. + * @param {number} low The low 32 bits. + * + * @example + * + * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); + */ + init: function (high, low) { + this.high = high; + this.low = low; + } + + /** + * Bitwise NOTs this word. + * + * @return {X64Word} A new x64-Word object after negating. + * + * @example + * + * var negated = x64Word.not(); + */ + // not: function () { + // var high = ~this.high; + // var low = ~this.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ANDs this word with the passed word. + * + * @param {X64Word} word The x64-Word to AND with this word. + * + * @return {X64Word} A new x64-Word object after ANDing. + * + * @example + * + * var anded = x64Word.and(anotherX64Word); + */ + // and: function (word) { + // var high = this.high & word.high; + // var low = this.low & word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to OR with this word. + * + * @return {X64Word} A new x64-Word object after ORing. + * + * @example + * + * var ored = x64Word.or(anotherX64Word); + */ + // or: function (word) { + // var high = this.high | word.high; + // var low = this.low | word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise XORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to XOR with this word. + * + * @return {X64Word} A new x64-Word object after XORing. + * + * @example + * + * var xored = x64Word.xor(anotherX64Word); + */ + // xor: function (word) { + // var high = this.high ^ word.high; + // var low = this.low ^ word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the left. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftL(25); + */ + // shiftL: function (n) { + // if (n < 32) { + // var high = (this.high << n) | (this.low >>> (32 - n)); + // var low = this.low << n; + // } else { + // var high = this.low << (n - 32); + // var low = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the right. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftR(7); + */ + // shiftR: function (n) { + // if (n < 32) { + // var low = (this.low >>> n) | (this.high << (32 - n)); + // var high = this.high >>> n; + // } else { + // var low = this.high >>> (n - 32); + // var high = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Rotates this word n bits to the left. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotL(25); + */ + // rotL: function (n) { + // return this.shiftL(n).or(this.shiftR(64 - n)); + // }, + + /** + * Rotates this word n bits to the right. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotR(7); + */ + // rotR: function (n) { + // return this.shiftR(n).or(this.shiftL(64 - n)); + // }, + + /** + * Adds this word with the passed word. + * + * @param {X64Word} word The x64-Word to add with this word. + * + * @return {X64Word} A new x64-Word object after adding. + * + * @example + * + * var added = x64Word.add(anotherX64Word); + */ + // add: function (word) { + // var low = (this.low + word.low) | 0; + // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; + // var high = (this.high + word.high + carry) | 0; + + // return X64Word.create(high, low); + // } + }); + + /** + * An array of 64-bit words. + * + * @property {Array} words The array of CryptoJS.x64.Word objects. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var X64WordArray = C_x64.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.x64.WordArray.create(); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ]); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ], 10); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 8; + } + }, + + /** + * Converts this 64-bit word array to a 32-bit word array. + * + * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. + * + * @example + * + * var x32WordArray = x64WordArray.toX32(); + */ + toX32: function () { + // Shortcuts + var x64Words = this.words; + var x64WordsLength = x64Words.length; + + // Convert + var x32Words = []; + for (var i = 0; i < x64WordsLength; i++) { + var x64Word = x64Words[i]; + x32Words.push(x64Word.high); + x32Words.push(x64Word.low); + } + + return X32WordArray.create(x32Words, this.sigBytes); + }, + + /** + * Creates a copy of this word array. + * + * @return {X64WordArray} The clone. + * + * @example + * + * var clone = x64WordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + + // Clone "words" array + var words = clone.words = this.words.slice(0); + + // Clone each X64Word object + var wordsLength = words.length; + for (var i = 0; i < wordsLength; i++) { + words[i] = words[i].clone(); + } + + return clone; + } + }); + }()); + + + return CryptoJS; + +})); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/css/index.css b/src/parsers/Telegram/telegram_media_downloader/module/static/css/index.css new file mode 100644 index 0000000..7407fee --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/css/index.css @@ -0,0 +1,16 @@ +.header-title { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} +.header-title .stop-btn { + padding: 8px; + border: 1px solid #009688; + border-radius: 4px; + font-size: 16px; + color: #009688; + cursor: pointer; +} + +/*# sourceMappingURL=index.css.map */ diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/layui.css b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/layui.css new file mode 100644 index 0000000..f8fdf94 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/layui.css @@ -0,0 +1 @@ +blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}a:active,a:hover{outline:0}img{display:inline-block;border:none;vertical-align:middle}li{list-style:none}table{border-collapse:collapse;border-spacing:0}h1,h2,h3{font-weight:400}h4,h5,h6{font-size:100%;font-weight:400}button,input,select,textarea{font-size:100%}button,input,optgroup,option,select,textarea{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;outline:0}pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}body{line-height:1.6;color:#333;color:rgba(0,0,0,.85);font:14px Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif}hr{height:0;line-height:0;margin:10px 0;padding:0;border:none!important;border-bottom:1px solid #eee!important;clear:both;overflow:hidden;background:0 0}a{color:#333;text-decoration:none}a:hover{color:#777}a cite{font-style:normal;*cursor:pointer}.layui-border-box,.layui-border-box *{box-sizing:border-box}.layui-box,.layui-box *{box-sizing:content-box}.layui-clear{clear:both;*zoom:1}.layui-clear:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.layui-edge{position:relative;display:inline-block;vertical-align:middle;width:0;height:0;border-width:6px;border-style:dashed;border-color:transparent;overflow:hidden}.layui-edge-top{top:-4px;border-bottom-color:#999;border-bottom-style:solid}.layui-edge-right{border-left-color:#999;border-left-style:solid}.layui-edge-bottom{top:2px;border-top-color:#999;border-top-style:solid}.layui-edge-left{border-right-color:#999;border-right-style:solid}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-disabled,.layui-icon,.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:hover{color:#d2d2d2!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-show-v{visibility:visible!important}.layui-hide-v{visibility:hidden!important}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=256);src:url(../font/iconfont.eot?v=256#iefix) format('embedded-opentype'),url(../font/iconfont.woff2?v=256) format('woff2'),url(../font/iconfont.woff?v=256) format('woff'),url(../font/iconfont.ttf?v=256) format('truetype'),url(../font/iconfont.svg?v=256#layui-icon) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-icon-reply-fill:before{content:"\e611"}.layui-icon-set-fill:before{content:"\e614"}.layui-icon-menu-fill:before{content:"\e60f"}.layui-icon-search:before{content:"\e615"}.layui-icon-share:before{content:"\e641"}.layui-icon-set-sm:before{content:"\e620"}.layui-icon-engine:before{content:"\e628"}.layui-icon-close:before{content:"\1006"}.layui-icon-close-fill:before{content:"\1007"}.layui-icon-chart-screen:before{content:"\e629"}.layui-icon-star:before{content:"\e600"}.layui-icon-circle-dot:before{content:"\e617"}.layui-icon-chat:before{content:"\e606"}.layui-icon-release:before{content:"\e609"}.layui-icon-list:before{content:"\e60a"}.layui-icon-chart:before{content:"\e62c"}.layui-icon-ok-circle:before{content:"\1005"}.layui-icon-layim-theme:before{content:"\e61b"}.layui-icon-table:before{content:"\e62d"}.layui-icon-right:before{content:"\e602"}.layui-icon-left:before{content:"\e603"}.layui-icon-cart-simple:before{content:"\e698"}.layui-icon-face-cry:before{content:"\e69c"}.layui-icon-face-smile:before{content:"\e6af"}.layui-icon-survey:before{content:"\e6b2"}.layui-icon-tree:before{content:"\e62e"}.layui-icon-ie:before{content:"\e7bb"}.layui-icon-upload-circle:before{content:"\e62f"}.layui-icon-add-circle:before{content:"\e61f"}.layui-icon-download-circle:before{content:"\e601"}.layui-icon-templeate-1:before{content:"\e630"}.layui-icon-util:before{content:"\e631"}.layui-icon-face-surprised:before{content:"\e664"}.layui-icon-edit:before{content:"\e642"}.layui-icon-speaker:before{content:"\e645"}.layui-icon-down:before{content:"\e61a"}.layui-icon-file:before{content:"\e621"}.layui-icon-layouts:before{content:"\e632"}.layui-icon-rate-half:before{content:"\e6c9"}.layui-icon-add-circle-fine:before{content:"\e608"}.layui-icon-prev-circle:before{content:"\e633"}.layui-icon-read:before{content:"\e705"}.layui-icon-404:before{content:"\e61c"}.layui-icon-carousel:before{content:"\e634"}.layui-icon-help:before{content:"\e607"}.layui-icon-code-circle:before{content:"\e635"}.layui-icon-windows:before{content:"\e67f"}.layui-icon-water:before{content:"\e636"}.layui-icon-username:before{content:"\e66f"}.layui-icon-find-fill:before{content:"\e670"}.layui-icon-about:before{content:"\e60b"}.layui-icon-location:before{content:"\e715"}.layui-icon-up:before{content:"\e619"}.layui-icon-pause:before{content:"\e651"}.layui-icon-date:before{content:"\e637"}.layui-icon-layim-uploadfile:before{content:"\e61d"}.layui-icon-delete:before{content:"\e640"}.layui-icon-play:before{content:"\e652"}.layui-icon-top:before{content:"\e604"}.layui-icon-firefox:before{content:"\e686"}.layui-icon-friends:before{content:"\e612"}.layui-icon-refresh-3:before{content:"\e9aa"}.layui-icon-ok:before{content:"\e605"}.layui-icon-layer:before{content:"\e638"}.layui-icon-face-smile-fine:before{content:"\e60c"}.layui-icon-dollar:before{content:"\e659"}.layui-icon-group:before{content:"\e613"}.layui-icon-layim-download:before{content:"\e61e"}.layui-icon-picture-fine:before{content:"\e60d"}.layui-icon-link:before{content:"\e64c"}.layui-icon-diamond:before{content:"\e735"}.layui-icon-log:before{content:"\e60e"}.layui-icon-key:before{content:"\e683"}.layui-icon-rate-solid:before{content:"\e67a"}.layui-icon-fonts-del:before{content:"\e64f"}.layui-icon-unlink:before{content:"\e64d"}.layui-icon-fonts-clear:before{content:"\e639"}.layui-icon-triangle-r:before{content:"\e623"}.layui-icon-circle:before{content:"\e63f"}.layui-icon-radio:before{content:"\e643"}.layui-icon-align-center:before{content:"\e647"}.layui-icon-align-right:before{content:"\e648"}.layui-icon-align-left:before{content:"\e649"}.layui-icon-loading-1:before{content:"\e63e"}.layui-icon-return:before{content:"\e65c"}.layui-icon-fonts-strong:before{content:"\e62b"}.layui-icon-upload:before{content:"\e67c"}.layui-icon-dialogue:before{content:"\e63a"}.layui-icon-video:before{content:"\e6ed"}.layui-icon-headset:before{content:"\e6fc"}.layui-icon-cellphone-fine:before{content:"\e63b"}.layui-icon-add-1:before{content:"\e654"}.layui-icon-face-smile-b:before{content:"\e650"}.layui-icon-fonts-html:before{content:"\e64b"}.layui-icon-screen-full:before{content:"\e622"}.layui-icon-form:before{content:"\e63c"}.layui-icon-cart:before{content:"\e657"}.layui-icon-camera-fill:before{content:"\e65d"}.layui-icon-tabs:before{content:"\e62a"}.layui-icon-heart-fill:before{content:"\e68f"}.layui-icon-fonts-code:before{content:"\e64e"}.layui-icon-ios:before{content:"\e680"}.layui-icon-at:before{content:"\e687"}.layui-icon-fire:before{content:"\e756"}.layui-icon-set:before{content:"\e716"}.layui-icon-fonts-u:before{content:"\e646"}.layui-icon-triangle-d:before{content:"\e625"}.layui-icon-tips:before{content:"\e702"}.layui-icon-picture:before{content:"\e64a"}.layui-icon-more-vertical:before{content:"\e671"}.layui-icon-bluetooth:before{content:"\e689"}.layui-icon-flag:before{content:"\e66c"}.layui-icon-loading:before{content:"\e63d"}.layui-icon-fonts-i:before{content:"\e644"}.layui-icon-refresh-1:before{content:"\e666"}.layui-icon-rmb:before{content:"\e65e"}.layui-icon-addition:before{content:"\e624"}.layui-icon-home:before{content:"\e68e"}.layui-icon-time:before{content:"\e68d"}.layui-icon-user:before{content:"\e770"}.layui-icon-notice:before{content:"\e667"}.layui-icon-chrome:before{content:"\e68a"}.layui-icon-edge:before{content:"\e68b"}.layui-icon-login-weibo:before{content:"\e675"}.layui-icon-voice:before{content:"\e688"}.layui-icon-upload-drag:before{content:"\e681"}.layui-icon-login-qq:before{content:"\e676"}.layui-icon-snowflake:before{content:"\e6b1"}.layui-icon-heart:before{content:"\e68c"}.layui-icon-logout:before{content:"\e682"}.layui-icon-file-b:before{content:"\e655"}.layui-icon-template:before{content:"\e663"}.layui-icon-transfer:before{content:"\e691"}.layui-icon-auz:before{content:"\e672"}.layui-icon-console:before{content:"\e665"}.layui-icon-app:before{content:"\e653"}.layui-icon-prev:before{content:"\e65a"}.layui-icon-website:before{content:"\e7ae"}.layui-icon-next:before{content:"\e65b"}.layui-icon-component:before{content:"\e857"}.layui-icon-android:before{content:"\e684"}.layui-icon-more:before{content:"\e65f"}.layui-icon-login-wechat:before{content:"\e677"}.layui-icon-shrink-right:before{content:"\e668"}.layui-icon-spread-left:before{content:"\e66b"}.layui-icon-camera:before{content:"\e660"}.layui-icon-note:before{content:"\e66e"}.layui-icon-refresh:before{content:"\e669"}.layui-icon-female:before{content:"\e661"}.layui-icon-male:before{content:"\e662"}.layui-icon-screen-restore:before{content:"\e758"}.layui-icon-password:before{content:"\e673"}.layui-icon-senior:before{content:"\e674"}.layui-icon-theme:before{content:"\e66a"}.layui-icon-tread:before{content:"\e6c5"}.layui-icon-praise:before{content:"\e6c6"}.layui-icon-star-fill:before{content:"\e658"}.layui-icon-rate:before{content:"\e67b"}.layui-icon-template-1:before{content:"\e656"}.layui-icon-vercode:before{content:"\e679"}.layui-icon-service:before{content:"\e626"}.layui-icon-cellphone:before{content:"\e678"}.layui-icon-print:before{content:"\e66d"}.layui-icon-cols:before{content:"\e610"}.layui-icon-wifi:before{content:"\e7e0"}.layui-icon-export:before{content:"\e67d"}.layui-icon-rss:before{content:"\e808"}.layui-icon-slider:before{content:"\e714"}.layui-icon-email:before{content:"\e618"}.layui-icon-subtraction:before{content:"\e67e"}.layui-icon-mike:before{content:"\e6dc"}.layui-icon-light:before{content:"\e748"}.layui-icon-gift:before{content:"\e627"}.layui-icon-mute:before{content:"\e685"}.layui-icon-reduce-circle:before{content:"\e616"}.layui-icon-music:before{content:"\e690"}.layui-main{position:relative;width:1160px;margin:0 auto}.layui-header{position:relative;z-index:1000;height:60px}.layui-header a:hover{transition:all .5s;-webkit-transition:all .5s}.layui-side{position:fixed;left:0;top:0;bottom:0;z-index:999;width:200px;overflow-x:hidden}.layui-side-scroll{position:relative;width:220px;height:100%;overflow-x:hidden}.layui-body{position:relative;left:200px;right:0;top:0;bottom:0;z-index:900;width:auto;box-sizing:border-box}.layui-layout-body{overflow-x:hidden}.layui-layout-admin .layui-header{position:fixed;top:0;left:0;right:0;background-color:#23262e}.layui-layout-admin .layui-side{top:60px;width:200px;overflow-x:hidden}.layui-layout-admin .layui-body{position:absolute;top:60px;padding-bottom:44px}.layui-layout-admin .layui-main{width:auto;margin:0 15px}.layui-layout-admin .layui-footer{position:fixed;left:200px;right:0;bottom:0;z-index:990;height:44px;line-height:44px;padding:0 15px;box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:#fafafa}.layui-layout-admin .layui-logo{position:absolute;left:0;top:0;width:200px;height:100%;line-height:60px;text-align:center;color:#009688;font-size:16px;box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)}.layui-layout-admin .layui-header .layui-nav{background:0 0}.layui-layout-left{position:absolute!important;left:200px;top:0}.layui-layout-right{position:absolute!important;right:0;top:0}.layui-container{position:relative;margin:0 auto;box-sizing:border-box}.layui-fluid{position:relative;margin:0 auto;padding:0 15px}.layui-row:after,.layui-row:before{content:"";display:block;clear:both}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9,.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9,.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9,.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{position:relative;display:block;box-sizing:border-box}.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{float:left}.layui-col-xs1{width:8.33333333%}.layui-col-xs2{width:16.66666667%}.layui-col-xs3{width:25%}.layui-col-xs4{width:33.33333333%}.layui-col-xs5{width:41.66666667%}.layui-col-xs6{width:50%}.layui-col-xs7{width:58.33333333%}.layui-col-xs8{width:66.66666667%}.layui-col-xs9{width:75%}.layui-col-xs10{width:83.33333333%}.layui-col-xs11{width:91.66666667%}.layui-col-xs12{width:100%}.layui-col-xs-offset1{margin-left:8.33333333%}.layui-col-xs-offset2{margin-left:16.66666667%}.layui-col-xs-offset3{margin-left:25%}.layui-col-xs-offset4{margin-left:33.33333333%}.layui-col-xs-offset5{margin-left:41.66666667%}.layui-col-xs-offset6{margin-left:50%}.layui-col-xs-offset7{margin-left:58.33333333%}.layui-col-xs-offset8{margin-left:66.66666667%}.layui-col-xs-offset9{margin-left:75%}.layui-col-xs-offset10{margin-left:83.33333333%}.layui-col-xs-offset11{margin-left:91.66666667%}.layui-col-xs-offset12{margin-left:100%}@media screen and (max-width:767.98px){.layui-container{padding:0 15px}.layui-hide-xs{display:none!important}.layui-show-xs-block{display:block!important}.layui-show-xs-inline{display:inline!important}.layui-show-xs-inline-block{display:inline-block!important}}@media screen and (min-width:768px){.layui-container{width:720px}.layui-hide-sm{display:none!important}.layui-show-sm-block{display:block!important}.layui-show-sm-inline{display:inline!important}.layui-show-sm-inline-block{display:inline-block!important}.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9{float:left}.layui-col-sm1{width:8.33333333%}.layui-col-sm2{width:16.66666667%}.layui-col-sm3{width:25%}.layui-col-sm4{width:33.33333333%}.layui-col-sm5{width:41.66666667%}.layui-col-sm6{width:50%}.layui-col-sm7{width:58.33333333%}.layui-col-sm8{width:66.66666667%}.layui-col-sm9{width:75%}.layui-col-sm10{width:83.33333333%}.layui-col-sm11{width:91.66666667%}.layui-col-sm12{width:100%}.layui-col-sm-offset1{margin-left:8.33333333%}.layui-col-sm-offset2{margin-left:16.66666667%}.layui-col-sm-offset3{margin-left:25%}.layui-col-sm-offset4{margin-left:33.33333333%}.layui-col-sm-offset5{margin-left:41.66666667%}.layui-col-sm-offset6{margin-left:50%}.layui-col-sm-offset7{margin-left:58.33333333%}.layui-col-sm-offset8{margin-left:66.66666667%}.layui-col-sm-offset9{margin-left:75%}.layui-col-sm-offset10{margin-left:83.33333333%}.layui-col-sm-offset11{margin-left:91.66666667%}.layui-col-sm-offset12{margin-left:100%}}@media screen and (min-width:992px){.layui-container{width:960px}.layui-hide-md{display:none!important}.layui-show-md-block{display:block!important}.layui-show-md-inline{display:inline!important}.layui-show-md-inline-block{display:inline-block!important}.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9{float:left}.layui-col-md1{width:8.33333333%}.layui-col-md2{width:16.66666667%}.layui-col-md3{width:25%}.layui-col-md4{width:33.33333333%}.layui-col-md5{width:41.66666667%}.layui-col-md6{width:50%}.layui-col-md7{width:58.33333333%}.layui-col-md8{width:66.66666667%}.layui-col-md9{width:75%}.layui-col-md10{width:83.33333333%}.layui-col-md11{width:91.66666667%}.layui-col-md12{width:100%}.layui-col-md-offset1{margin-left:8.33333333%}.layui-col-md-offset2{margin-left:16.66666667%}.layui-col-md-offset3{margin-left:25%}.layui-col-md-offset4{margin-left:33.33333333%}.layui-col-md-offset5{margin-left:41.66666667%}.layui-col-md-offset6{margin-left:50%}.layui-col-md-offset7{margin-left:58.33333333%}.layui-col-md-offset8{margin-left:66.66666667%}.layui-col-md-offset9{margin-left:75%}.layui-col-md-offset10{margin-left:83.33333333%}.layui-col-md-offset11{margin-left:91.66666667%}.layui-col-md-offset12{margin-left:100%}}@media screen and (min-width:1200px){.layui-container{width:1150px}.layui-hide-lg{display:none!important}.layui-show-lg-block{display:block!important}.layui-show-lg-inline{display:inline!important}.layui-show-lg-inline-block{display:inline-block!important}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9{float:left}.layui-col-lg1{width:8.33333333%}.layui-col-lg2{width:16.66666667%}.layui-col-lg3{width:25%}.layui-col-lg4{width:33.33333333%}.layui-col-lg5{width:41.66666667%}.layui-col-lg6{width:50%}.layui-col-lg7{width:58.33333333%}.layui-col-lg8{width:66.66666667%}.layui-col-lg9{width:75%}.layui-col-lg10{width:83.33333333%}.layui-col-lg11{width:91.66666667%}.layui-col-lg12{width:100%}.layui-col-lg-offset1{margin-left:8.33333333%}.layui-col-lg-offset2{margin-left:16.66666667%}.layui-col-lg-offset3{margin-left:25%}.layui-col-lg-offset4{margin-left:33.33333333%}.layui-col-lg-offset5{margin-left:41.66666667%}.layui-col-lg-offset6{margin-left:50%}.layui-col-lg-offset7{margin-left:58.33333333%}.layui-col-lg-offset8{margin-left:66.66666667%}.layui-col-lg-offset9{margin-left:75%}.layui-col-lg-offset10{margin-left:83.33333333%}.layui-col-lg-offset11{margin-left:91.66666667%}.layui-col-lg-offset12{margin-left:100%}}.layui-col-space1{margin:-.5px}.layui-col-space1>*{padding:.5px}.layui-col-space2{margin:-1px}.layui-col-space2>*{padding:1px}.layui-col-space4{margin:-2px}.layui-col-space4>*{padding:2px}.layui-col-space5{margin:-2.5px}.layui-col-space5>*{padding:2.5px}.layui-col-space6{margin:-3px}.layui-col-space6>*{padding:3px}.layui-col-space8{margin:-4px}.layui-col-space8>*{padding:4px}.layui-col-space10{margin:-5px}.layui-col-space10>*{padding:5px}.layui-col-space12{margin:-6px}.layui-col-space12>*{padding:6px}.layui-col-space14{margin:-7px}.layui-col-space14>*{padding:7px}.layui-col-space15{margin:-7.5px}.layui-col-space15>*{padding:7.5px}.layui-col-space16{margin:-8px}.layui-col-space16>*{padding:8px}.layui-col-space18{margin:-9px}.layui-col-space18>*{padding:9px}.layui-col-space20{margin:-10px}.layui-col-space20>*{padding:10px}.layui-col-space22{margin:-11px}.layui-col-space22>*{padding:11px}.layui-col-space24{margin:-12px}.layui-col-space24>*{padding:12px}.layui-col-space25{margin:-12.5px}.layui-col-space25>*{padding:12.5px}.layui-col-space26{margin:-13px}.layui-col-space26>*{padding:13px}.layui-col-space28{margin:-14px}.layui-col-space28>*{padding:14px}.layui-col-space30{margin:-15px}.layui-col-space30>*{padding:15px}.layui-btn,.layui-input,.layui-select,.layui-textarea,.layui-upload-button{outline:0;-webkit-appearance:none;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-elem-quote{margin-bottom:10px;padding:15px;line-height:1.6;border-left:5px solid #5fb878;border-radius:0 2px 2px 0;background-color:#fafafa}.layui-quote-nm{border-style:solid;border-width:1px;border-left-width:5px;background:0 0}.layui-elem-field{margin-bottom:10px;padding:0;border-width:1px;border-style:solid}.layui-elem-field legend{margin-left:20px;padding:0 10px;font-size:20px;font-weight:300}.layui-field-title{margin:10px 0 20px;border-width:0;border-top-width:1px}.layui-field-box{padding:15px}.layui-field-title .layui-field-box{padding:10px 0}.layui-progress{position:relative;height:6px;border-radius:20px;background-color:#eee}.layui-progress-bar{position:absolute;left:0;top:0;width:0;max-width:100%;height:6px;border-radius:20px;text-align:right;background-color:#5fb878;transition:all .3s;-webkit-transition:all .3s}.layui-progress-big,.layui-progress-big .layui-progress-bar{height:18px;line-height:18px}.layui-progress-text{position:relative;top:-20px;line-height:18px;font-size:12px;color:#5f5f5f}.layui-progress-big .layui-progress-text{position:static;padding:0 10px;color:#fff}.layui-collapse{border-width:1px;border-style:solid;border-radius:2px}.layui-colla-content,.layui-colla-item{border-top-width:1px;border-top-style:solid}.layui-colla-item:first-child{border-top:none}.layui-colla-title{position:relative;height:42px;line-height:42px;padding:0 15px 0 35px;color:#333;background-color:#fafafa;cursor:pointer;font-size:14px;overflow:hidden}.layui-colla-content{display:none;padding:10px 15px;line-height:1.6;color:#5f5f5f}.layui-colla-icon{position:absolute;left:15px;top:0;font-size:14px}.layui-card{margin-bottom:15px;border-radius:2px;background-color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.layui-card:last-child{margin-bottom:0}.layui-card-header{position:relative;height:42px;line-height:42px;padding:0 15px;border-bottom:1px solid #f6f6f6;color:#333;border-radius:2px 2px 0 0;font-size:14px}.layui-card-body{position:relative;padding:10px 15px;line-height:24px}.layui-card-body[pad15]{padding:15px}.layui-card-body[pad20]{padding:20px}.layui-card-body .layui-table{margin:5px 0}.layui-card .layui-tab{margin:0}.layui-panel{position:relative;border-width:1px;border-style:solid;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);background-color:#fff;color:#5f5f5f}.layui-panel-window{position:relative;padding:15px;border-radius:0;border-top:5px solid #eee;background-color:#fff}.layui-auxiliar-moving{position:fixed;left:0;right:0;top:0;bottom:0;width:100%;height:100%;background:0 0;z-index:9999999999}.layui-bg-red{background-color:#ff5722!important;color:#fff!important}.layui-bg-orange{background-color:#ffb800!important;color:#fff!important}.layui-bg-green{background-color:#009688!important;color:#fff!important}.layui-bg-cyan{background-color:#2f4056!important;color:#fff!important}.layui-bg-blue{background-color:#1e9fff!important;color:#fff!important}.layui-bg-black{background-color:#393d49!important;color:#fff!important}.layui-bg-gray{background-color:#fafafa!important;color:#5f5f5f!important}.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-layedit,.layui-layedit-tool,.layui-panel,.layui-quote-nm,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color:#eee}.layui-border{border-width:1px;border-style:solid;color:#5f5f5f!important}.layui-border-red{border-width:1px;border-style:solid;border-color:#ff5722!important;color:#ff5722!important}.layui-border-orange{border-width:1px;border-style:solid;border-color:#ffb800!important;color:#ffb800!important}.layui-border-green{border-width:1px;border-style:solid;border-color:#009688!important;color:#009688!important}.layui-border-cyan{border-width:1px;border-style:solid;border-color:#2f4056!important;color:#2f4056!important}.layui-border-blue{border-width:1px;border-style:solid;border-color:#1e9fff!important;color:#1e9fff!important}.layui-border-black{border-width:1px;border-style:solid;border-color:#393d49!important;color:#393d49!important}.layui-timeline-item:before{background-color:#eee}.layui-text{line-height:1.6;font-size:14px;color:#5f5f5f}.layui-text h1,.layui-text h2,.layui-text h3,.layui-text h4,.layui-text h5,.layui-text h6{font-weight:500;color:#333}.layui-text h1{font-size:32px}.layui-text h2{font-size:24px}.layui-text h3{font-size:18px}.layui-text h4{font-size:16px}.layui-text h5{font-size:14px}.layui-text h6{font-size:13px}.layui-text a:not(.layui-btn){color:#01aaed}.layui-text a:not(.layui-btn):hover{text-decoration:underline}.layui-text ol,.layui-text ul{padding:5px 0 5px 15px}.layui-text ul li{margin-top:5px;list-style-type:disc}.layui-text ol li{margin-top:5px;list-style-type:decimal}.layui-text em,.layui-word-aux{color:#999!important;padding-left:5px!important;padding-right:5px!important}.layui-text p{margin:15px 0}.layui-text p:first-child{margin-top:0}.layui-text p:last-child{margin-bottom:0}.layui-text blockquote:not(.layui-elem-quote){padding:5px 15px;border-left:5px solid #eee}.layui-text pre:not(.layui-code){padding:15px;font-family:Lucida Console,Consolas,Courier New;background-color:#fafafa}.layui-font-12{font-size:12px!important}.layui-font-14{font-size:14px!important}.layui-font-16{font-size:16px!important}.layui-font-18{font-size:18px!important}.layui-font-20{font-size:20px!important}.layui-font-red{color:#ff5722!important}.layui-font-orange{color:#ffb800!important}.layui-font-green{color:#009688!important}.layui-font-cyan{color:#2f4056!important}.layui-font-blue{color:#01aaed!important}.layui-font-black{color:#000!important}.layui-font-gray{color:#c2c2c2!important}.layui-btn{display:inline-block;vertical-align:middle;height:38px;line-height:38px;border:1px solid transparent;padding:0 18px;background-color:#009688;color:#fff;white-space:nowrap;text-align:center;font-size:14px;border-radius:2px;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-btn:hover{opacity:.8;filter:alpha(opacity=80);color:#fff}.layui-btn:active{opacity:1;filter:alpha(opacity=100)}.layui-btn+.layui-btn{margin-left:10px}.layui-btn-container{font-size:0}.layui-btn-container .layui-btn{margin-right:10px;margin-bottom:10px}.layui-btn-container .layui-btn+.layui-btn{margin-left:0}.layui-table .layui-btn-container .layui-btn{margin-bottom:9px}.layui-btn-radius{border-radius:100px}.layui-btn .layui-icon{padding:0 2px;vertical-align:middle\0;vertical-align:bottom}.layui-btn-primary{border-color:#d2d2d2;background:0 0;color:#5f5f5f}.layui-btn-primary:hover{border-color:#009688;color:#333}.layui-btn-normal{background-color:#1e9fff}.layui-btn-warm{background-color:#ffb800}.layui-btn-danger{background-color:#ff5722}.layui-btn-checked{background-color:#5fb878}.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color:#eee!important;background-color:#fbfbfb!important;color:#d2d2d2!important;cursor:not-allowed!important;opacity:1}.layui-btn-lg{height:44px;line-height:44px;padding:0 25px;font-size:16px}.layui-btn-sm{height:30px;line-height:30px;padding:0 10px;font-size:12px}.layui-btn-xs{height:22px;line-height:22px;padding:0 5px;font-size:12px}.layui-btn-xs i{font-size:12px!important}.layui-btn-group{display:inline-block;vertical-align:middle;font-size:0}.layui-btn-group .layui-btn{margin-left:0!important;margin-right:0!important;border-left:1px solid rgba(255,255,255,.5);border-radius:0}.layui-btn-group .layui-btn-primary{border-left:none}.layui-btn-group .layui-btn-primary:hover{border-color:#d2d2d2;color:#009688}.layui-btn-group .layui-btn:first-child{border-left:none;border-radius:2px 0 0 2px}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid #d2d2d2}.layui-btn-group .layui-btn:last-child{border-radius:0 2px 2px 0}.layui-btn-group .layui-btn+.layui-btn{margin-left:0}.layui-btn-group+.layui-btn-group{margin-left:10px}.layui-btn-fluid{width:100%}.layui-input,.layui-select,.layui-textarea{height:38px;line-height:1.3;line-height:38px\9;border-width:1px;border-style:solid;background-color:#fff;color:rgba(0,0,0,.85);border-radius:2px}.layui-input::-webkit-input-placeholder,.layui-select::-webkit-input-placeholder,.layui-textarea::-webkit-input-placeholder{line-height:1.3}.layui-input,.layui-textarea{display:block;width:100%;padding-left:10px}.layui-input:hover,.layui-textarea:hover{border-color:#eee!important}.layui-input:focus,.layui-textarea:focus{border-color:#d2d2d2!important}.layui-textarea{position:relative;min-height:100px;height:auto;line-height:20px;padding:6px 10px;resize:vertical}.layui-select{padding:0 10px}.layui-form input[type=checkbox],.layui-form input[type=radio],.layui-form select{display:none}.layui-form [lay-ignore]{display:initial}.layui-form-item{margin-bottom:15px;clear:both;*zoom:1}.layui-form-item:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-form-label{position:relative;float:left;display:block;padding:9px 15px;width:80px;font-weight:400;line-height:20px;text-align:right}.layui-form-label-col{display:block;float:none;padding:9px 0;line-height:20px;text-align:left}.layui-form-item .layui-inline{margin-bottom:5px;margin-right:10px}.layui-input-block,.layui-input-inline{position:relative}.layui-input-block{margin-left:110px;min-height:36px}.layui-input-inline{display:inline-block;vertical-align:middle}.layui-form-item .layui-input-inline{float:left;width:190px;margin-right:10px}.layui-form-text .layui-input-inline{width:auto}.layui-form-mid{position:relative;float:left;display:block;padding:9px 0!important;line-height:20px;margin-right:10px}.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:#ff5722!important}.layui-form-select{position:relative}.layui-form-select .layui-input{padding-right:30px;cursor:pointer}.layui-form-select .layui-edge{position:absolute;right:10px;top:50%;margin-top:-3px;cursor:pointer;border-width:6px;border-top-color:#c2c2c2;border-top-style:solid;transition:all .3s;-webkit-transition:all .3s}.layui-form-select dl{display:none;position:absolute;left:0;top:42px;padding:5px 0;z-index:899;min-width:100%;border:1px solid #eee;max-height:300px;overflow-y:auto;background-color:#fff;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);box-sizing:border-box}.layui-form-select dl dd,.layui-form-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.layui-form-select dl dt{font-size:12px;color:#999}.layui-form-select dl dd{cursor:pointer}.layui-form-select dl dd:hover{background-color:#f6f6f6;-webkit-transition:.5s all;transition:.5s all}.layui-form-select .layui-select-group dd{padding-left:20px}.layui-form-select dl dd.layui-select-tips{padding-left:10px!important;color:#999}.layui-form-select dl dd.layui-this{background-color:#5fb878;color:#fff}.layui-form-select dl dd.layui-disabled{background-color:#fff}.layui-form-selected dl{display:block}.layui-form-selected .layui-edge{margin-top:-9px;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.layui-form-selected .layui-edge{margin-top:-3px\0}:root .layui-form-selected .layui-edge{margin-top:-9px\0/IE9}.layui-form-selectup dl{top:auto;bottom:42px}.layui-select-none{margin:5px 0;text-align:center;color:#999}.layui-select-disabled .layui-disabled{border-color:#eee!important}.layui-select-disabled .layui-edge{border-top-color:#d2d2d2}.layui-form-checkbox{position:relative;display:inline-block;vertical-align:middle;height:30px;line-height:30px;margin-right:10px;padding-right:30px;background-color:#fff;cursor:pointer;font-size:0;-webkit-transition:.1s linear;transition:.1s linear;box-sizing:border-box}.layui-form-checkbox *{display:inline-block;vertical-align:middle}.layui-form-checkbox span{padding:0 10px;height:100%;font-size:14px;border-radius:2px 0 0 2px;background-color:#d2d2d2;color:#fff;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.layui-form-checkbox:hover span{background-color:#c2c2c2}.layui-form-checkbox i{position:absolute;right:0;top:0;width:30px;height:28px;border:1px solid #d2d2d2;border-left:none;border-radius:0 2px 2px 0;color:#fff;font-size:20px;text-align:center}.layui-form-checkbox:hover i{border-color:#c2c2c2;color:#c2c2c2}.layui-form-checked,.layui-form-checked:hover{border-color:#5fb878}.layui-form-checked span,.layui-form-checked:hover span{background-color:#5fb878}.layui-form-checked i,.layui-form-checked:hover i{color:#5fb878}.layui-form-item .layui-form-checkbox{margin-top:4px}.layui-form-checkbox[lay-skin=primary]{height:auto!important;line-height:normal!important;min-width:18px;min-height:18px;border:none!important;margin-right:0;padding-left:28px;padding-right:0;background:0 0}.layui-form-checkbox[lay-skin=primary] span{padding-left:0;padding-right:15px;line-height:18px;background:0 0;color:#5f5f5f}.layui-form-checkbox[lay-skin=primary] i{right:auto;left:0;width:16px;height:16px;line-height:16px;border:1px solid #d2d2d2;font-size:12px;border-radius:2px;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-checkbox[lay-skin=primary]:hover i{border-color:#5fb878;color:#fff}.layui-form-checked[lay-skin=primary] i{border-color:#5fb878!important;background-color:#5fb878;color:#fff}.layui-checkbox-disabled[lay-skin=primary] span{background:0 0!important;color:#c2c2c2!important}.layui-form-checked.layui-checkbox-disabled[lay-skin=primary] i{background:#eee!important;border-color:#eee!important}.layui-checkbox-disabled[lay-skin=primary]:hover i{border-color:#d2d2d2}.layui-form-item .layui-form-checkbox[lay-skin=primary]{margin-top:10px}.layui-form-switch{position:relative;display:inline-block;vertical-align:middle;height:22px;line-height:22px;min-width:35px;padding:0 5px;margin-top:8px;border:1px solid #d2d2d2;border-radius:20px;cursor:pointer;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch i{position:absolute;left:5px;top:3px;width:16px;height:16px;border-radius:20px;background-color:#d2d2d2;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch em{position:relative;top:0;width:25px;margin-left:21px;padding:0!important;text-align:center!important;color:#999!important;font-style:normal!important;font-size:12px}.layui-form-onswitch{border-color:#5fb878;background-color:#5fb878}.layui-form-onswitch i{left:100%;margin-left:-21px;background-color:#fff}.layui-form-onswitch em{margin-left:5px;margin-right:21px;color:#fff!important}.layui-checkbox-disabled{border-color:#eee!important}.layui-checkbox-disabled span{background-color:#eee!important}.layui-checkbox-disabled i{border-color:#eee!important}.layui-checkbox-disabled em{color:#d2d2d2!important}.layui-checkbox-disabled:hover i{color:#fff!important}[lay-radio]{display:none}.layui-form-radio{display:inline-block;vertical-align:middle;line-height:28px;margin:6px 10px 0 0;padding-right:10px;cursor:pointer;font-size:0}.layui-form-radio *{display:inline-block;vertical-align:middle;font-size:14px}.layui-form-radio>i{margin-right:8px;font-size:22px;color:#c2c2c2}.layui-form-radio:hover *,.layui-form-radioed,.layui-form-radioed>i{color:#5fb878}.layui-radio-disabled>i{color:#eee!important}.layui-radio-disabled *{color:#c2c2c2!important}.layui-form-pane .layui-form-label{width:110px;padding:8px 15px;height:38px;line-height:20px;border-width:1px;border-style:solid;border-radius:2px 0 0 2px;text-align:center;background-color:#fafafa;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box}.layui-form-pane .layui-input-inline{margin-left:-1px}.layui-form-pane .layui-input-block{margin-left:110px;left:-1px}.layui-form-pane .layui-input{border-radius:0 2px 2px 0}.layui-form-pane .layui-form-text .layui-form-label{float:none;width:100%;border-radius:2px;box-sizing:border-box;text-align:left}.layui-form-pane .layui-form-text .layui-input-inline{display:block;margin:0;top:-1px;clear:both}.layui-form-pane .layui-form-text .layui-input-block{margin:0;left:0;top:-1px}.layui-form-pane .layui-form-text .layui-textarea{min-height:100px;border-radius:0 0 2px 2px}.layui-form-pane .layui-form-checkbox{margin:4px 0 4px 10px}.layui-form-pane .layui-form-radio,.layui-form-pane .layui-form-switch{margin-top:6px;margin-left:10px}.layui-form-pane .layui-form-item[pane]{position:relative;border-width:1px;border-style:solid}.layui-form-pane .layui-form-item[pane] .layui-form-label{position:absolute;left:0;top:0;height:100%;border-width:0;border-right-width:1px}.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left:110px}@media screen and (max-width:450px){.layui-form-item .layui-form-label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-form-item .layui-inline{display:block;margin-right:0;margin-bottom:20px;clear:both}.layui-form-item .layui-inline:after{content:'\20';clear:both;display:block;height:0}.layui-form-item .layui-input-inline{display:block;float:none;left:-3px;width:auto!important;margin:0 0 10px 112px}.layui-form-item .layui-input-inline+.layui-form-mid{margin-left:110px;top:-5px;padding:0}.layui-form-item .layui-form-checkbox{margin-right:5px;margin-bottom:5px}}.layui-layedit{border-width:1px;border-style:solid;border-radius:2px}.layui-layedit-tool{padding:3px 5px;border-bottom-width:1px;border-bottom-style:solid;font-size:0}.layedit-tool-fixed{position:fixed;top:0;border-top:1px solid #eee}.layui-layedit-tool .layedit-tool-mid,.layui-layedit-tool .layui-icon{display:inline-block;vertical-align:middle;text-align:center;font-size:14px}.layui-layedit-tool .layui-icon{position:relative;width:32px;height:30px;line-height:30px;margin:3px 5px;border-radius:2px;color:#777;cursor:pointer;border-radius:2px}.layui-layedit-tool .layui-icon:hover{color:#393d49}.layui-layedit-tool .layui-icon:active{color:#000}.layui-layedit-tool .layedit-tool-active{background-color:#eee;color:#000}.layui-layedit-tool .layui-disabled,.layui-layedit-tool .layui-disabled:hover{color:#d2d2d2;cursor:not-allowed}.layui-layedit-tool .layedit-tool-mid{width:1px;height:18px;margin:0 10px;background-color:#d2d2d2}.layedit-tool-html{width:50px!important;font-size:30px!important}.layedit-tool-b,.layedit-tool-code,.layedit-tool-help{font-size:16px!important}.layedit-tool-d,.layedit-tool-face,.layedit-tool-image,.layedit-tool-unlink{font-size:18px!important}.layedit-tool-image input{position:absolute;font-size:0;left:0;top:0;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-layedit-iframe iframe{display:block;width:100%}#LAY_layedit_code{overflow:hidden}.layui-laypage{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;margin:10px 0;font-size:0}.layui-laypage>a:first-child,.layui-laypage>a:first-child em{border-radius:2px 0 0 2px}.layui-laypage>a:last-child,.layui-laypage>a:last-child em{border-radius:0 2px 2px 0}.layui-laypage>:first-child{margin-left:0!important}.layui-laypage>:last-child{margin-right:0!important}.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid #eee}.layui-laypage a,.layui-laypage span{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding:0 15px;height:28px;line-height:28px;margin:0 -1px 5px 0;background-color:#fff;color:#333;font-size:12px}.layui-laypage a:hover{color:#009688}.layui-laypage em{font-style:normal}.layui-laypage .layui-laypage-spr{color:#999;font-weight:700}.layui-laypage a{text-decoration:none}.layui-laypage .layui-laypage-curr{position:relative}.layui-laypage .layui-laypage-curr em{position:relative;color:#fff}.layui-laypage .layui-laypage-curr .layui-laypage-em{position:absolute;left:-1px;top:-1px;padding:1px;width:100%;height:100%;background-color:#009688}.layui-laypage-em{border-radius:2px}.layui-laypage-next em,.layui-laypage-prev em{font-family:Sim sun;font-size:16px}.layui-laypage .layui-laypage-count,.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh,.layui-laypage .layui-laypage-skip{margin-left:10px;margin-right:10px;padding:0;border:none}.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh{vertical-align:top}.layui-laypage .layui-laypage-refresh i{font-size:18px;cursor:pointer}.layui-laypage select{height:22px;padding:3px;border-radius:2px;cursor:pointer}.layui-laypage .layui-laypage-skip{height:30px;line-height:30px;color:#999}.layui-laypage button,.layui-laypage input{height:30px;line-height:30px;border-radius:2px;vertical-align:top;background-color:#fff;box-sizing:border-box}.layui-laypage input{display:inline-block;width:40px;margin:0 10px;padding:0 3px;text-align:center}.layui-laypage input:focus,.layui-laypage select:focus{border-color:#009688!important}.layui-laypage button{margin-left:10px;padding:0 10px;cursor:pointer}.layui-flow-more{margin:10px 0;text-align:center;color:#999;font-size:14px}.layui-flow-more a{height:32px;line-height:32px}.layui-flow-more a *{display:inline-block;vertical-align:top}.layui-flow-more a cite{padding:0 20px;border-radius:3px;background-color:#eee;color:#333;font-style:normal}.layui-flow-more a cite:hover{opacity:.8}.layui-flow-more a i{font-size:30px;color:#737383}.layui-table{width:100%;margin:10px 0;background-color:#fff;color:#5f5f5f}.layui-table tr{transition:all .3s;-webkit-transition:all .3s}.layui-table th{text-align:left;font-weight:400}.layui-table tbody tr:hover,.layui-table thead tr,.layui-table-click,.layui-table-header,.layui-table-hover,.layui-table-mend,.layui-table-patch,.layui-table-tool,.layui-table-total,.layui-table-total tr{background-color:#fafafa}.layui-table[lay-even] tr:nth-child(even){background-color:#f2f2f2}.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-width:1px;border-style:solid;border-color:#eee}.layui-table td,.layui-table th{position:relative;padding:9px 15px;min-height:20px;line-height:20px;font-size:14px}.layui-table[lay-skin=line] td,.layui-table[lay-skin=line] th{border-width:0;border-bottom-width:1px}.layui-table[lay-skin=row] td,.layui-table[lay-skin=row] th{border-width:0;border-right-width:1px}.layui-table[lay-skin=nob] td,.layui-table[lay-skin=nob] th{border:none}.layui-table img{max-width:100px}.layui-table[lay-size=lg] td,.layui-table[lay-size=lg] th{padding-top:15px;padding-right:30px;padding-bottom:15px;padding-left:30px}.layui-table-view .layui-table[lay-size=lg] .layui-table-cell{height:50px;line-height:40px}.layui-table[lay-size=sm] td,.layui-table[lay-size=sm] th{padding-top:5px;padding-right:10px;padding-bottom:5px;padding-left:10px;font-size:12px}.layui-table-view .layui-table[lay-size=sm] .layui-table-cell{height:30px;line-height:20px;padding-top:5px;padding-right:5px}.layui-table[lay-data]{display:none}.layui-table-box{position:relative;overflow:hidden}.layui-table-view{margin:10px 0}.layui-table-view .layui-table{position:relative;width:auto;margin:0;border:0;border-collapse:separate}.layui-table-view .layui-table[lay-skin=line]{border-width:0;border-right-width:1px}.layui-table-view .layui-table[lay-skin=row]{border-width:0;border-bottom-width:1px}.layui-table-view .layui-table td,.layui-table-view .layui-table th{padding:0;border-top:none;border-left:none}.layui-table-view .layui-table th.layui-unselect .layui-table-cell span{cursor:pointer}.layui-table-view .layui-table td{cursor:default}.layui-table-view .layui-table td[data-edit=text]{cursor:text}.layui-table-view .layui-form-checkbox[lay-skin=primary] i{width:18px;height:18px}.layui-table-view .layui-form-radio{line-height:0;padding:0}.layui-table-view .layui-form-radio>i{margin:0;font-size:20px}.layui-table-init{position:absolute;left:0;top:0;width:100%;height:100%;text-align:center;z-index:110}.layui-table-init .layui-icon{position:absolute;left:50%;top:50%;margin:-15px 0 0 -15px;font-size:30px;color:#c2c2c2}.layui-table-header{border-width:0;border-bottom-width:1px;overflow:hidden}.layui-table-header .layui-table{margin-bottom:-1px}.layui-table-column{position:relative;width:100%;min-height:41px;padding:8px 16px;border-width:0;border-bottom-width:1px}.layui-table-column .layui-btn-container{margin-bottom:-8px}.layui-table-column .layui-btn-container .layui-btn{margin-right:8px;margin-bottom:8px}.layui-table-tool .layui-inline[lay-event]{position:relative;width:26px;height:26px;padding:5px;line-height:16px;margin-right:10px;text-align:center;color:#333;border:1px solid #ccc;cursor:pointer;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid #999}.layui-table-tool-temp{padding-right:120px}.layui-table-tool-self{position:absolute;right:17px;top:10px}.layui-table-tool .layui-table-tool-self .layui-inline[lay-event]{margin:0 0 0 10px}.layui-table-tool-panel{position:absolute;top:29px;left:-1px;padding:5px 0;min-width:150px;min-height:40px;border:1px solid #d2d2d2;text-align:left;overflow-y:auto;background-color:#fff;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-table-tool-panel li{padding:0 10px;line-height:30px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{width:100%}.layui-table-tool-panel li:hover{background-color:#f6f6f6}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{padding-left:28px}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i{position:absolute;left:0;top:0}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span{padding:0}.layui-table-tool .layui-table-tool-self .layui-table-tool-panel{left:auto;right:-1px}.layui-table-col-set{position:absolute;right:0;top:0;width:20px;height:100%;border-width:0;border-left-width:1px;background-color:#fff}.layui-table-sort{width:10px;height:20px;margin-left:5px;cursor:pointer!important}.layui-table-sort .layui-edge{position:absolute;left:5px;border-width:5px}.layui-table-sort .layui-table-sort-asc{top:3px;border-top:none;border-bottom-style:solid;border-bottom-color:#b2b2b2}.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:#5f5f5f}.layui-table-sort .layui-table-sort-desc{bottom:5px;border-bottom:none;border-top-style:solid;border-top-color:#b2b2b2}.layui-table-sort .layui-table-sort-desc:hover{border-top-color:#5f5f5f}.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:#000}.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:#000}.layui-table-cell{height:38px;line-height:28px;padding:6px 15px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.layui-table-cell .layui-form-checkbox[lay-skin=primary]{top:-1px;padding:0}.layui-table-cell .layui-table-link{color:#01aaed}.layui-table-cell .layui-btn{vertical-align:inherit}.layui-table-cell[align=center]{-webkit-box-pack:center}.layui-table-cell[align=right]{-webkit-box-pack:end}.laytable-cell-checkbox,.laytable-cell-numbers,.laytable-cell-radio,.laytable-cell-space{text-align:center;-webkit-box-pack:center}.layui-table-body{position:relative;overflow:auto;margin-right:-1px;margin-bottom:-1px}.layui-table-body .layui-none{line-height:26px;padding:30px 15px;text-align:center;color:#999}.layui-table-fixed{position:absolute;left:0;top:0;z-index:101}.layui-table-fixed .layui-table-body{overflow:hidden}.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r{left:auto;right:-1px;border-width:0;border-left-width:1px;box-shadow:-1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r .layui-table-header{position:relative;overflow:visible}.layui-table-mend{position:absolute;right:-49px;top:0;height:100%;width:50px}.layui-table-tool{position:relative;z-index:890;width:100%;min-height:50px;line-height:30px;padding:10px 15px;border-width:0;border-bottom-width:1px}.layui-table-tool .layui-btn-container{margin-bottom:-10px}.layui-table-total{margin-bottom:-1px;border-width:0;border-top-width:1px;overflow:hidden}.layui-table-page{z-index:880;border-width:0;border-top-width:1px;margin-bottom:-1px;white-space:nowrap;overflow:hidden}.layui-table-page>div{height:26px}.layui-table-page .layui-laypage{margin:0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span{height:26px;line-height:26px;margin-bottom:10px;border:none;background:0 0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span.layui-laypage-curr{padding:0 12px}.layui-table-page .layui-laypage span{margin-left:0;padding:0}.layui-table-page .layui-laypage .layui-laypage-prev{margin-left:-11px!important}.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em{left:0;top:0;padding:0}.layui-table-page .layui-laypage button,.layui-table-page .layui-laypage input{height:26px;line-height:26px}.layui-table-page .layui-laypage input{width:40px}.layui-table-page .layui-laypage button{padding:0 10px}.layui-table-page select{height:18px}.layui-table-pagebar{float:right;line-height:23px}.layui-table-pagebar .layui-btn-sm{margin-top:-1px}.layui-table-pagebar .layui-btn-xs{margin-top:2px}.layui-table-view select[lay-ignore]{display:inline-block}.layui-table-patch .layui-table-cell{padding:0;width:30px}.layui-table-edit{position:absolute;left:0;top:0;z-index:900;min-width:100%;min-height:100%;padding:5px 14px;border-radius:0;box-shadow:1px 1px 20px rgba(0,0,0,.15);background-color:#fff}.layui-table-edit:focus{border-color:#5fb878!important}input.layui-input.layui-table-edit{height:100%}select.layui-table-edit{padding:0 0 0 10px;border-color:#d2d2d2}.layui-table-view .layui-form-checkbox,.layui-table-view .layui-form-radio,.layui-table-view .layui-form-switch{top:0;margin:0;box-sizing:content-box}.layui-table-view .layui-form-checkbox{top:-1px;height:26px;line-height:26px}.layui-table-view .layui-form-checkbox i{height:26px}.layui-table-grid .layui-table-cell{overflow:visible}.layui-table-grid-down{position:absolute;top:0;right:0;width:26px;height:100%;padding:5px 0;border-width:0;border-left-width:1px;text-align:center;background-color:#fff;color:#999;cursor:pointer}.layui-table-grid-down .layui-icon{position:absolute;top:50%;left:50%;margin:-8px 0 0 -8px}.layui-table-grid-down:hover{background-color:#fbfbfb}body .layui-table-tips .layui-layer-content{background:0 0;padding:0;box-shadow:0 1px 6px rgba(0,0,0,.12)}.layui-table-tips-main{margin:-49px 0 0 -1px;max-height:150px;padding:8px 15px;font-size:14px;overflow-y:scroll;background-color:#fff;color:#5f5f5f}.layui-table-tips-c{position:absolute;right:-3px;top:-13px;width:20px;height:20px;padding:3px;cursor:pointer;background-color:#5f5f5f;border-radius:50%;color:#fff}.layui-table-tips-c:hover{background-color:#777}.layui-table-tips-c:before{position:relative;right:-2px}.layui-upload-file{display:none!important;opacity:.01;filter:Alpha(opacity=1)}.layui-upload-list{margin:10px 0}.layui-upload-choose{max-width:200px;padding:0 10px;color:#999;font-size:14px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-upload-drag{position:relative;display:inline-block;padding:30px;border:1px dashed #e2e2e2;background-color:#fff;text-align:center;cursor:pointer;color:#999}.layui-upload-drag .layui-icon{font-size:50px;color:#009688}.layui-upload-drag[lay-over]{border-color:#009688}.layui-upload-form{display:inline-block}.layui-upload-iframe{position:absolute;width:0;height:0;border:0;visibility:hidden}.layui-upload-wrap{position:relative;display:inline-block;vertical-align:middle}.layui-upload-wrap .layui-upload-file{display:block!important;position:absolute;left:0;top:0;z-index:10;font-size:100px;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-btn-container .layui-upload-choose{padding-left:0}.layui-menu{position:relative;margin:5px 0;background-color:#fff;box-sizing:border-box}.layui-menu *{box-sizing:border-box}.layui-menu li,.layui-menu-body-title a{padding:5px 15px}.layui-menu li{position:relative;margin:1px 0;width:calc(100% + 1px);line-height:26px;color:rgba(0,0,0,.8);font-size:14px;white-space:nowrap;cursor:pointer;transition:all .3s}.layui-menu li:hover{background-color:#f6f6f6}.layui-menu-item-parent:hover>.layui-menu-body-panel{display:block;animation-name:layui-fadein;animation-duration:.3s;animation-fill-mode:both;animation-delay:.2s}.layui-menu-item-group .layui-menu-body-title,.layui-menu-item-parent .layui-menu-body-title{padding-right:25px}.layui-menu .layui-menu-item-divider:hover,.layui-menu .layui-menu-item-group:hover,.layui-menu .layui-menu-item-none:hover{background:0 0;cursor:default}.layui-menu .layui-menu-item-group>ul{margin:5px 0 -5px}.layui-menu .layui-menu-item-group>.layui-menu-body-title{color:rgba(0,0,0,.35);user-select:none}.layui-menu .layui-menu-item-none{color:rgba(0,0,0,.35);cursor:default}.layui-menu .layui-menu-item-none{text-align:center}.layui-menu .layui-menu-item-divider{margin:5px 0;padding:0;height:0;line-height:0;border-bottom:1px solid #eee;overflow:hidden}.layui-menu .layui-menu-item-down:hover,.layui-menu .layui-menu-item-up:hover{cursor:pointer}.layui-menu .layui-menu-item-up>.layui-menu-body-title{color:rgba(0,0,0,.8)}.layui-menu .layui-menu-item-up>ul{visibility:hidden;height:0;overflow:hidden}.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color:#000}.layui-menu .layui-menu-item-down>ul{visibility:visible;height:auto}.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:#f6f6f6!important;color:#5fb878}.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:#5fb878}.layui-menu .layui-menu-item-checked:after{position:absolute;right:0;top:0;bottom:0;border-right:3px solid #5fb878;content:""}.layui-menu-body-title{position:relative;overflow:hidden;text-overflow:ellipsis}.layui-menu-body-title a{display:block;margin:-5px -15px;color:rgba(0,0,0,.8)}.layui-menu-body-title a:hover{transition:all .3s}.layui-menu-body-title>.layui-icon{position:absolute;right:0;top:0;font-size:14px}.layui-menu-body-title>.layui-icon:hover{transition:all .3s}.layui-menu-body-title>.layui-icon-right{right:-1px}.layui-menu-body-panel{display:none;position:absolute;top:-7px;left:100%;z-index:1000;margin-left:13px;padding:5px 0}.layui-menu-body-panel:before{content:"";position:absolute;width:20px;left:-16px;top:0;bottom:0}.layui-menu-body-panel-left{left:auto;right:100%;margin:0 13px 0}.layui-menu-body-panel-left:before{left:auto;right:-16px}.layui-menu-lg li{line-height:32px}.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{background:0 0;color:#5fb878}.layui-menu-lg li .layui-menu-body-panel{margin-left:14px}.layui-menu-lg li .layui-menu-body-panel-left{margin:0 15px 0}.layui-dropdown{position:absolute;left:-999999px;top:-999999px;z-index:77777777;margin:5px 0;min-width:100px}.layui-dropdown:before{content:"";position:absolute;width:100%;height:6px;left:0;top:-6px}.layui-nav{position:relative;padding:0 20px;background-color:#393d49;color:#fff;border-radius:2px;font-size:0;box-sizing:border-box}.layui-nav *{font-size:14px}.layui-nav .layui-nav-item{position:relative;display:inline-block;*display:inline;*zoom:1;vertical-align:middle;line-height:60px}.layui-nav .layui-nav-item a{display:block;padding:0 20px;color:#fff;color:rgba(255,255,255,.7);transition:all .3s;-webkit-transition:all .3s}.layui-nav .layui-this:after,.layui-nav-bar{content:"";position:absolute;left:0;top:0;width:0;height:5px;background-color:#5fb878;transition:all .2s;-webkit-transition:all .2s;pointer-events:none}.layui-nav-bar{z-index:1000}.layui-nav[lay-bar=disabled] .layui-nav-bar{display:none}.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color:#fff}.layui-nav .layui-this:after{top:auto;bottom:0;width:100%}.layui-nav-img{width:30px;height:30px;margin-right:10px;border-radius:50%}.layui-nav .layui-nav-more{position:absolute;top:0;right:3px;left:auto!important;margin-top:0;font-size:12px;cursor:pointer;transition:all .2s;-webkit-transition:all .2s}.layui-nav .layui-nav-mored,.layui-nav-itemed>a .layui-nav-more{transform:rotate(180deg)}.layui-nav-child{display:none;position:absolute;left:0;top:65px;min-width:100%;line-height:36px;padding:5px 0;box-shadow:0 2px 4px rgba(0,0,0,.12);border:1px solid #eee;background-color:#fff;z-index:100;border-radius:2px;white-space:nowrap}.layui-nav .layui-nav-child a{color:#5f5f5f;color:rgba(0,0,0,.8)}.layui-nav .layui-nav-child a:hover{background-color:#f6f6f6;color:rgba(0,0,0,.8)}.layui-nav-child dd{margin:1px 0;position:relative}.layui-nav-child dd.layui-this{background-color:#f6f6f6;color:#000}.layui-nav-child dd.layui-this:after{display:none}.layui-nav-child-r{left:auto;right:0}.layui-nav-child-c{text-align:center}.layui-nav-tree{width:200px;padding:0}.layui-nav-tree .layui-nav-item{display:block;width:100%;line-height:40px}.layui-nav-tree .layui-nav-item a{position:relative;height:40px;line-height:40px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-nav-tree .layui-nav-item>a{padding-top:5px;padding-bottom:5px}.layui-nav-tree .layui-nav-more{right:15px}.layui-nav-tree .layui-nav-item>a .layui-nav-more{padding:5px 0}.layui-nav-tree .layui-nav-bar{width:5px;height:0}.layui-side .layui-nav-tree .layui-nav-bar{width:2px}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color:#009688;color:#fff}.layui-nav-tree .layui-this:after{display:none}.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color:#fff!important}.layui-nav-tree .layui-nav-bar{background-color:#009688}.layui-nav-tree .layui-nav-child{position:relative;z-index:0;top:0;border:none;box-shadow:none}.layui-nav-tree .layui-nav-child dd{margin:0}.layui-nav-tree .layui-nav-child a{color:#fff;color:rgba(255,255,255,.7)}.layui-nav-tree .layui-nav-child,.layui-nav-tree .layui-nav-child a:hover{background:0 0;color:#fff}.layui-nav-itemed>.layui-nav-child{display:block;background-color:rgba(0,0,0,.3)!important}.layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display:block}.layui-nav-side{position:fixed;top:0;bottom:0;left:0;overflow-x:hidden;z-index:999}.layui-breadcrumb{visibility:hidden;font-size:0}.layui-breadcrumb>*{font-size:14px}.layui-breadcrumb a{color:#999!important}.layui-breadcrumb a:hover{color:#5fb878!important}.layui-breadcrumb a cite{color:#5f5f5f;font-style:normal}.layui-breadcrumb span[lay-separator]{margin:0 10px;color:#999}.layui-tab{margin:10px 0;text-align:left!important}.layui-tab[overflow]>.layui-tab-title{overflow:hidden}.layui-tab-title{position:relative;left:0;height:40px;white-space:nowrap;font-size:0;border-bottom-width:1px;border-bottom-style:solid;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;font-size:14px;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li{position:relative;line-height:40px;min-width:65px;padding:0 15px;text-align:center;cursor:pointer}.layui-tab-title li a{display:block;padding:0 15px;margin:0 -15px}.layui-tab-title .layui-this{color:#000}.layui-tab-title .layui-this:after{position:absolute;left:0;top:0;content:"";width:100%;height:41px;border-width:1px;border-style:solid;border-bottom-color:#fff;border-radius:2px 2px 0 0;box-sizing:border-box;pointer-events:none}.layui-tab-bar{position:absolute;right:0;top:0;z-index:10;width:30px;height:39px;line-height:39px;border-width:1px;border-style:solid;border-radius:2px;text-align:center;background-color:#fff;cursor:pointer}.layui-tab-bar .layui-icon{position:relative;display:inline-block;top:3px;transition:all .3s;-webkit-transition:all .3s}.layui-tab-item{display:none}.layui-tab-more{padding-right:30px;height:auto!important;white-space:normal!important}.layui-tab-more li.layui-this:after{border-bottom-color:#eee;border-radius:2px}.layui-tab-more .layui-tab-bar .layui-icon{top:-2px;top:3px\0;-webkit-transform:rotate(180deg);transform:rotate(180deg)}:root .layui-tab-more .layui-tab-bar .layui-icon{top:-2px\0/IE9}.layui-tab-content{padding:15px 0}.layui-tab-title li .layui-tab-close{position:relative;display:inline-block;width:18px;height:18px;line-height:20px;margin-left:8px;top:1px;text-align:center;font-size:14px;color:#c2c2c2;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li .layui-tab-close:hover{border-radius:2px;background-color:#ff5722;color:#fff}.layui-tab-brief>.layui-tab-title .layui-this{color:#009688}.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border:none;border-radius:0;border-bottom:2px solid #5fb878}.layui-tab-brief[overflow]>.layui-tab-title .layui-this:after{top:-1px}.layui-tab-card{border-width:1px;border-style:solid;border-radius:2px;box-shadow:0 2px 5px 0 rgba(0,0,0,.1)}.layui-tab-card>.layui-tab-title{background-color:#fafafa}.layui-tab-card>.layui-tab-title li{margin-right:-1px;margin-left:-1px}.layui-tab-card>.layui-tab-title .layui-this{background-color:#fff}.layui-tab-card>.layui-tab-title .layui-this:after{border-top:none;border-width:1px;border-bottom-color:#fff}.layui-tab-card>.layui-tab-title .layui-tab-bar{height:40px;line-height:40px;border-radius:0;border-top:none;border-right:none}.layui-tab-card>.layui-tab-more .layui-this{background:0 0;color:#5fb878}.layui-tab-card>.layui-tab-more .layui-this:after{border:none}.layui-timeline{padding-left:5px}.layui-timeline-item{position:relative;padding-bottom:20px}.layui-timeline-axis{position:absolute;left:-5px;top:0;z-index:10;width:20px;height:20px;line-height:20px;background-color:#fff;color:#5fb878;border-radius:50%;text-align:center;cursor:pointer}.layui-timeline-axis:hover{color:#ff5722}.layui-timeline-item:before{content:"";position:absolute;left:5px;top:0;z-index:0;width:1px;height:100%}.layui-timeline-item:first-child:before{display:block}.layui-timeline-item:last-child:before{display:none}.layui-timeline-content{padding-left:25px}.layui-timeline-title{position:relative;margin-bottom:10px;line-height:22px}.layui-badge,.layui-badge-dot,.layui-badge-rim{position:relative;display:inline-block;padding:0 6px;font-size:12px;text-align:center;background-color:#ff5722;color:#fff;border-radius:2px}.layui-badge{height:18px;line-height:18px}.layui-badge-dot{width:8px;height:8px;padding:0;border-radius:50%}.layui-badge-rim{height:18px;line-height:18px;border-width:1px;border-style:solid;background-color:#fff;color:#5f5f5f}.layui-btn .layui-badge,.layui-btn .layui-badge-dot{margin-left:5px}.layui-nav .layui-badge,.layui-nav .layui-badge-dot{position:absolute;top:50%;margin:-5px 6px 0}.layui-nav .layui-badge{margin-top:-10px}.layui-tab-title .layui-badge,.layui-tab-title .layui-badge-dot{left:5px;top:-2px}.layui-carousel{position:relative;left:0;top:0;background-color:#f8f8f8}.layui-carousel>[carousel-item]{position:relative;width:100%;height:100%;overflow:hidden}.layui-carousel>[carousel-item]:before{position:absolute;content:'\e63d';left:50%;top:50%;width:100px;line-height:20px;margin:-10px 0 0 -50px;text-align:center;color:#c2c2c2;font-family:layui-icon!important;font-size:30px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-carousel>[carousel-item]>*{display:none;position:absolute;left:0;top:0;width:100%;height:100%;background-color:#f8f8f8;transition-duration:.3s;-webkit-transition-duration:.3s}.layui-carousel-updown>*{-webkit-transition:.3s ease-in-out up;transition:.3s ease-in-out up}.layui-carousel-arrow{display:none\0;opacity:0;position:absolute;left:10px;top:50%;margin-top:-18px;width:36px;height:36px;line-height:36px;text-align:center;font-size:20px;border:none 0;border-radius:50%;background-color:rgba(0,0,0,.2);color:#fff;-webkit-transition-duration:.3s;transition-duration:.3s;cursor:pointer}.layui-carousel-arrow[lay-type=add]{left:auto!important;right:10px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow{opacity:1;left:20px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel[lay-arrow=none] .layui-carousel-arrow{display:none}.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:rgba(0,0,0,.35)}.layui-carousel:hover .layui-carousel-arrow{display:block\0;opacity:1;left:20px}.layui-carousel:hover .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel-ind{position:relative;top:-35px;width:100%;line-height:0!important;text-align:center;font-size:0}.layui-carousel[lay-indicator=outside]{margin-bottom:30px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind{top:10px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:rgba(0,0,0,.5)}.layui-carousel[lay-indicator=none] .layui-carousel-ind{display:none}.layui-carousel-ind ul{display:inline-block;padding:5px;background-color:rgba(0,0,0,.2);border-radius:10px;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind li{display:inline-block;width:10px;height:10px;margin:0 3px;font-size:14px;background-color:#eee;background-color:rgba(255,255,255,.5);border-radius:50%;cursor:pointer;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind li:hover{background-color:rgba(255,255,255,.7)}.layui-carousel-ind li.layui-this{background-color:#fff}.layui-carousel>[carousel-item]>.layui-carousel-next,.layui-carousel>[carousel-item]>.layui-carousel-prev,.layui-carousel>[carousel-item]>.layui-this{display:block}.layui-carousel>[carousel-item]>.layui-this{left:0}.layui-carousel>[carousel-item]>.layui-carousel-prev{left:-100%}.layui-carousel>[carousel-item]>.layui-carousel-next{left:100%}.layui-carousel>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel>[carousel-item]>.layui-carousel-prev.layui-carousel-right{left:0}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-left{left:-100%}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-right{left:100%}.layui-carousel[lay-anim=updown] .layui-carousel-arrow{left:50%!important;top:20px;margin:0 0 0 -18px}.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add]{top:auto!important;bottom:20px}.layui-carousel[lay-anim=updown] .layui-carousel-ind{position:absolute;top:50%;right:20px;width:auto;height:auto}.layui-carousel[lay-anim=updown] .layui-carousel-ind ul{padding:3px 5px}.layui-carousel[lay-anim=updown] .layui-carousel-ind li{display:block;margin:6px 0}.layui-carousel[lay-anim=updown]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next{top:100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-left{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-right{top:100%}.layui-carousel[lay-anim=fade]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev{opacity:0}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{opacity:1}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-right{opacity:0}.layui-fixbar{position:fixed;right:15px;bottom:15px;z-index:999999}.layui-fixbar li{width:50px;height:50px;line-height:50px;margin-bottom:1px;text-align:center;cursor:pointer;font-size:30px;background-color:#9f9f9f;color:#fff;border-radius:2px;opacity:.95}.layui-fixbar li:hover{opacity:.85}.layui-fixbar li:active{opacity:1}.layui-fixbar .layui-fixbar-top{display:none;font-size:40px}body .layui-util-face{border:none;background:0 0}body .layui-util-face .layui-layer-content{padding:0;background-color:#fff;color:#5f5f5f;box-shadow:none}.layui-util-face .layui-layer-TipsG{display:none}.layui-util-face ul{position:relative;width:372px;padding:10px;border:1px solid #d9d9d9;background-color:#fff;box-shadow:0 0 20px rgba(0,0,0,.2)}.layui-util-face ul li{cursor:pointer;float:left;border:1px solid #e8e8e8;height:22px;width:26px;overflow:hidden;margin:-1px 0 0 -1px;padding:4px 2px;text-align:center}.layui-util-face ul li:hover{position:relative;z-index:2;border:1px solid #eb7350;background:#fff9ec}.layui-code{position:relative;margin:10px 0;padding:15px;line-height:20px;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New;font-size:12px}.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-width:0;border-style:solid;border-color:#eee}.layui-transfer-box{position:relative;display:inline-block;vertical-align:middle;border-width:1px;width:200px;height:360px;border-radius:2px;background-color:#fff}.layui-transfer-box .layui-form-checkbox{width:100%;margin:0!important}.layui-transfer-header{height:38px;line-height:38px;padding:0 10px;border-bottom-width:1px}.layui-transfer-search{position:relative;padding:10px;border-bottom-width:1px}.layui-transfer-search .layui-input{height:32px;padding-left:30px;font-size:12px}.layui-transfer-search .layui-icon-search{position:absolute;left:20px;top:50%;margin-top:-8px;color:#5f5f5f}.layui-transfer-active{margin:0 15px;display:inline-block;vertical-align:middle}.layui-transfer-active .layui-btn{display:block;margin:0;padding:0 15px;background-color:#5fb878;border-color:#5fb878;color:#fff}.layui-transfer-active .layui-btn-disabled{background-color:#fbfbfb;border-color:#eee;color:#d2d2d2}.layui-transfer-active .layui-btn:first-child{margin-bottom:15px}.layui-transfer-active .layui-btn .layui-icon{margin:0;font-size:14px!important}.layui-transfer-data{padding:5px 0;overflow:auto}.layui-transfer-data li{height:32px;line-height:32px;padding:0 10px}.layui-transfer-data li:hover{background-color:#f6f6f6;transition:.5s all}.layui-transfer-data .layui-none{padding:15px 10px;text-align:center;color:#999}.layui-rate,.layui-rate *{display:inline-block;vertical-align:middle}.layui-rate{padding:10px 5px 10px 0;font-size:0}.layui-rate li i.layui-icon{font-size:20px;color:#ffb800}.layui-rate li i.layui-icon{margin-right:5px;transition:all .3s;-webkit-transition:all .3s}.layui-rate li i:hover{cursor:pointer;transform:scale(1.12);-webkit-transform:scale(1.12)}.layui-rate[readonly] li i:hover{cursor:default;transform:scale(1)}.layui-colorpicker{width:26px;height:26px;border:1px solid #eee;padding:5px;border-radius:2px;line-height:24px;display:inline-block;cursor:pointer;transition:all .3s;-webkit-transition:all .3s}.layui-colorpicker:hover{border-color:#d2d2d2}.layui-colorpicker.layui-colorpicker-lg{width:34px;height:34px;line-height:32px}.layui-colorpicker.layui-colorpicker-sm{width:24px;height:24px;line-height:22px}.layui-colorpicker.layui-colorpicker-xs{width:22px;height:22px;line-height:20px}.layui-colorpicker-trigger-bgcolor{display:block;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);border-radius:2px}.layui-colorpicker-trigger-span{display:block;height:100%;box-sizing:border-box;border:1px solid rgba(0,0,0,.15);border-radius:2px;text-align:center}.layui-colorpicker-trigger-i{display:inline-block;color:#fff;font-size:12px}.layui-colorpicker-trigger-i.layui-icon-close{color:#999}.layui-colorpicker-main{position:absolute;left:-999999px;top:-999999px;z-index:77777777;width:280px;margin:5px 0;padding:7px;background:#fff;border:1px solid #d2d2d2;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-colorpicker-main-wrapper{height:180px;position:relative}.layui-colorpicker-basis{width:260px;height:100%;position:relative}.layui-colorpicker-basis-white{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.layui-colorpicker-basis-black{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(0deg,#000,transparent)}.layui-colorpicker-basis-cursor{width:10px;height:10px;border:1px solid #fff;border-radius:50%;position:absolute;top:-3px;right:-3px;cursor:pointer}.layui-colorpicker-side{position:absolute;top:0;right:0;width:12px;height:100%;background:linear-gradient(red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.layui-colorpicker-side-slider{width:100%;height:5px;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;left:0}.layui-colorpicker-main-alpha{display:none;height:12px;margin-top:7px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-alpha-bgcolor{height:100%;position:relative}.layui-colorpicker-alpha-slider{width:5px;height:100%;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;top:0}.layui-colorpicker-main-pre{padding-top:7px;font-size:0}.layui-colorpicker-pre{width:20px;height:20px;border-radius:2px;display:inline-block;margin-left:6px;margin-bottom:7px;cursor:pointer}.layui-colorpicker-pre:nth-child(11n+1){margin-left:0}.layui-colorpicker-pre-isalpha{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-pre.layui-this{box-shadow:0 0 3px 2px rgba(0,0,0,.15)}.layui-colorpicker-pre>div{height:100%;border-radius:2px}.layui-colorpicker-main-input{text-align:right;padding-top:7px}.layui-colorpicker-main-input .layui-btn-container .layui-btn{margin:0 0 0 10px}.layui-colorpicker-main-input div.layui-inline{float:left;margin-right:10px;font-size:14px}.layui-colorpicker-main-input input.layui-input{width:150px;height:30px;color:#5f5f5f}.layui-slider{height:4px;background:#eee;border-radius:3px;position:relative;cursor:pointer}.layui-slider-bar{border-radius:3px;position:absolute;height:100%}.layui-slider-step{position:absolute;top:0;width:4px;height:4px;border-radius:50%;background:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.layui-slider-wrap{width:36px;height:36px;position:absolute;top:-16px;-webkit-transform:translateX(-50%);transform:translateX(-50%);z-index:10;text-align:center}.layui-slider-wrap-btn{width:12px;height:12px;border-radius:50%;background:#fff;display:inline-block;vertical-align:middle;cursor:pointer;transition:.3s}.layui-slider-wrap:after{content:"";height:100%;display:inline-block;vertical-align:middle}.layui-slider-wrap-btn.layui-slider-hover,.layui-slider-wrap-btn:hover{transform:scale(1.2)}.layui-slider-wrap-btn.layui-disabled:hover{transform:scale(1)!important}.layui-slider-tips{position:absolute;top:-42px;z-index:77777777;white-space:nowrap;display:none;-webkit-transform:translateX(-50%);transform:translateX(-50%);color:#fff;background:#000;border-radius:3px;height:25px;line-height:25px;padding:0 10px}.layui-slider-tips:after{content:"";position:absolute;bottom:-12px;left:50%;margin-left:-6px;width:0;height:0;border-width:6px;border-style:solid;border-color:#000 transparent transparent transparent}.layui-slider-input{width:70px;height:32px;border:1px solid #eee;border-radius:3px;font-size:16px;line-height:32px;position:absolute;right:0;top:-14px}.layui-slider-input-btn{position:absolute;top:0;right:0;width:20px;height:100%;border-left:1px solid #eee}.layui-slider-input-btn i{cursor:pointer;position:absolute;right:0;bottom:0;width:20px;height:50%;font-size:12px;line-height:16px;text-align:center;color:#999}.layui-slider-input-btn i:first-child{top:0;border-bottom:1px solid #eee}.layui-slider-input-txt{height:100%;font-size:14px}.layui-slider-input-txt input{height:100%;border:none}.layui-slider-input-btn i:hover{color:#009688}.layui-slider-vertical{width:4px;margin-left:33px}.layui-slider-vertical .layui-slider-bar{width:4px}.layui-slider-vertical .layui-slider-step{top:auto;left:0;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-wrap{top:auto;left:-16px;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-tips{top:auto;left:2px}@media \0screen{.layui-slider-wrap-btn{margin-left:-20px}.layui-slider-vertical .layui-slider-wrap-btn{margin-left:0;margin-bottom:-20px}.layui-slider-vertical .layui-slider-tips{margin-left:-8px}.layui-slider>span{margin-left:8px}}.layui-tree{line-height:22px}.layui-tree .layui-form-checkbox{margin:0!important}.layui-tree-set{width:100%;position:relative}.layui-tree-pack{display:none;padding-left:20px;position:relative}.layui-tree-line .layui-tree-pack{padding-left:27px}.layui-tree-line .layui-tree-set .layui-tree-set:after{content:"";position:absolute;top:14px;left:-9px;width:17px;height:0;border-top:1px dotted #c0c4cc}.layui-tree-entry{position:relative;padding:3px 0;height:20px;white-space:nowrap}.layui-tree-entry:hover{background-color:#eee}.layui-tree-line .layui-tree-entry:hover{background-color:rgba(0,0,0,0)}.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:#999;text-decoration:underline;transition:.3s}.layui-tree-main{display:inline-block;vertical-align:middle;cursor:pointer;padding-right:10px}.layui-tree-line .layui-tree-set:before{content:"";position:absolute;top:0;left:-9px;width:0;height:100%;border-left:1px dotted #c0c4cc}.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before{height:13px}.layui-tree-line .layui-tree-set.layui-tree-setHide:before{height:0}.layui-tree-iconClick{display:inline-block;vertical-align:middle;position:relative;height:20px;line-height:20px;margin:0 10px;color:#c0c4cc}.layui-tree-icon{height:12px;line-height:12px;width:12px;text-align:center;border:1px solid #c0c4cc}.layui-tree-iconClick .layui-icon{font-size:18px}.layui-tree-icon .layui-icon{font-size:12px;color:#5f5f5f}.layui-tree-iconArrow{padding:0 5px}.layui-tree-iconArrow:after{content:"";position:absolute;left:4px;top:3px;z-index:100;width:0;height:0;border-width:5px;border-style:solid;border-color:transparent transparent transparent #c0c4cc;transition:.5s}.layui-tree-spread>.layui-tree-entry .layui-tree-iconClick>.layui-tree-iconArrow:after{transform:rotate(90deg) translate(3px,4px)}.layui-tree-txt{display:inline-block;vertical-align:middle;color:#555}.layui-tree-search{margin-bottom:15px;color:#5f5f5f}.layui-tree-btnGroup{visibility:hidden;display:inline-block;vertical-align:middle;position:relative}.layui-tree-btnGroup .layui-icon{display:inline-block;vertical-align:middle;padding:0 2px;cursor:pointer}.layui-tree-btnGroup .layui-icon:hover{color:#999;transition:.3s}.layui-tree-entry:hover .layui-tree-btnGroup{visibility:visible}.layui-tree-editInput{position:relative;display:inline-block;vertical-align:middle;height:20px;line-height:20px;padding:0 3px;border:none;background-color:rgba(0,0,0,.05)}.layui-tree-emptyText{text-align:center;color:#999}.layui-anim{-webkit-animation-duration:.3s;-webkit-animation-fill-mode:both;animation-duration:.3s;animation-fill-mode:both}.layui-anim.layui-icon{display:inline-block}.layui-anim-loop{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.layui-trans,.layui-trans a{transition:all .2s;-webkit-transition:all .2s}@-webkit-keyframes layui-rotate{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@keyframes layui-rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.layui-anim-rotate{-webkit-animation-name:layui-rotate;animation-name:layui-rotate;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes layui-up{from{-webkit-transform:translate3d(0,100%,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-up{from{transform:translate3d(0,100%,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-up{-webkit-animation-name:layui-up;animation-name:layui-up}@-webkit-keyframes layui-upbit{from{-webkit-transform:translate3d(0,15px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-upbit{from{transform:translate3d(0,15px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-upbit{-webkit-animation-name:layui-upbit;animation-name:layui-upbit}@keyframes layui-down{0%{opacity:.3;transform:translate3d(0,-100%,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-down{animation-name:layui-down}@keyframes layui-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-downbit{animation-name:layui-downbit}@-webkit-keyframes layui-scale{0%{opacity:.3;-webkit-transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale{0%{opacity:.3;-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-ms-transform:scale(1);transform:scale(1)}}.layui-anim-scale{-webkit-animation-name:layui-scale;animation-name:layui-scale}@-webkit-keyframes layui-scale-spring{0%{opacity:.5;-webkit-transform:scale(.5)}80%{opacity:.8;-webkit-transform:scale(1.1)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale-spring{0%{opacity:.5;transform:scale(.5)}80%{opacity:.8;transform:scale(1.1)}100%{opacity:1;transform:scale(1)}}.layui-anim-scaleSpring{-webkit-animation-name:layui-scale-spring;animation-name:layui-scale-spring}@keyframes layui-scalesmall{0%{opacity:.3;transform:scale(1.5)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall{animation-name:layui-scalesmall}@keyframes layui-scalesmall-spring{0%{opacity:.3;transform:scale(1.5)}80%{opacity:.8;transform:scale(.9)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall-spring{animation-name:layui-scalesmall-spring}@-webkit-keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}@keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}.layui-anim-fadein{-webkit-animation-name:layui-fadein;animation-name:layui-fadein}@-webkit-keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}.layui-anim-fadeout{-webkit-animation-name:layui-fadeout;animation-name:layui-fadeout} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/code.css b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/code.css new file mode 100644 index 0000000..f7c9d01 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/code.css @@ -0,0 +1 @@ +html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-view{display:block;position:relative;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New;font-size:13px}.layui-code-title{position:relative;padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee;font-size:12px}.layui-code-title>.layui-code-about{position:absolute;right:10px;top:0;color:#b7b7b7}.layui-code-about>a{padding-left:10px}.layui-code-view>.layui-code-ol,.layui-code-view>.layui-code-ul{position:relative;overflow:auto}.layui-code-view>.layui-code-ol>li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view>.layui-code-ol>li:first-child,.layui-code-view>.layui-code-ul>li:first-child{padding-top:10px}.layui-code-view>.layui-code-ol>li:last-child,.layui-code-view>.layui-code-ul>li:last-child{padding-bottom:10px}.layui-code-view>.layui-code-ul>li{position:relative;line-height:20px;padding:0 10px;list-style-type:none;*list-style-type:none;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-dark{border:1px solid #0c0c0c;border-left-color:#3f3f3f;background-color:#0c0c0c;color:#c2be9e}.layui-code-dark>.layui-code-title{border-bottom:none}.layui-code-dark>.layui-code-ol>li,.layui-code-dark>.layui-code-ul>li{background-color:#3f3f3f;border-left:none}.layui-code-dark>.layui-code-ul>li{margin-left:6px}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/laydate/default/laydate.css b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/laydate/default/laydate.css new file mode 100644 index 0000000..da8acbd --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/laydate/default/laydate.css @@ -0,0 +1 @@ +html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate,.layui-laydate *{box-sizing:border-box}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate{animation-name:laydate-downbit}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;padding:0 5px;color:#999;font-size:18px;cursor:pointer}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-set-ym span{padding:0 10px;cursor:pointer}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content th{font-weight:400}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.laydate-day-holidays:before{position:absolute;left:0;top:0;font-size:12px;transform:scale(.7)}.laydate-day-holidays:before{content:'\4F11';color:#ff5722}.laydate-day-holidays[type=work]:before{content:'\73ED';color:inherit}.layui-laydate .layui-this .laydate-day-holidays:before{color:#fff}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px}.layui-laydate-footer span{display:inline-block;vertical-align:top;height:26px;line-height:24px;padding:0 10px;border:1px solid #c9c9c9;border-radius:2px;background-color:#fff;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .3s}.layui-laydate-footer span:hover{color:#5fb878}.layui-laydate-footer span.layui-laydate-preview{cursor:default;border-color:transparent!important}.layui-laydate-footer span.layui-laydate-preview:hover{color:#666}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{margin:0 0 0 -1px}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;box-sizing:border-box;background-color:#fff}.layui-laydate-list>li{position:relative;display:inline-block;width:33.3%;height:36px;line-height:36px;margin:3px 0;vertical-align:middle;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;height:30px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px;color:#ff5722}.layui-laydate-range{width:546px}.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5fb878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#b5fff8}.laydate-selected:hover{background-color:#00f7de!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#ff5722}.laydate-day-mark::after{background-color:#5fb878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5fb878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/icon-ext.png b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/icon-ext.png new file mode 100644 index 0000000000000000000000000000000000000000..bbbb669bb311514baa5db3a6a00b4644d0e280f1 GIT binary patch literal 5911 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 bWW^%>x7XlHV^#Q1uOX^B?ki3(VEg|7!QHuF literal 0 HcmV?d00001 diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/loading-1.gif b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/css/modules/layer/default/loading-1.gif new file mode 100644 index 0000000000000000000000000000000000000000..db3a483e4b74971fbfb1cc0fb6499852cedfe650 GIT binary patch literal 701 zcmZ?wbhEHbRAo?Qn8?Ji_w)@mZNLBj|1&T!DE{a6a}5c0b_{Se(lcOY1PT3QVdY|A zV$cDyff`g97?`@J^shYqmS1s(LX_+4yGox$4el*+Jm?ved2^25GBru=T^dGm#<906 za&AQCZ08H8P;Bd&{NT;vl&}c_^L4%p?g_hjBu{YB29{c>Ob}p@z~Ks3xCw+@!HClp xtZ<(QPf3`00FNu+VbOvoEE+h73k#4LIKl$IE8t;)<_eUs!0QU6uz&iJhvXcHF*h)T1OnEW1i^?zgDfop1p?usL*#PMGT;HQkSO{q6FlJyb$PWkPf|h*eTST}7h8z$}MF(XD(aQ)ZLZ zM?v0rT<1C4XHn<6PbNA{XL@>1^)apdD_@tcYDrW#m`k#MmslI7p^P;Az74wGs`!SI zLs$GEZHsafXsu1i-WleMzAL(yw$-LK{0hv;6hrx8kx!!4$``dAyBnY9Jz&DqJo2$A z!(L$H=KqBeY~CF_viHPz^tTglc?D97CqEBjzUwH}7GI zapg8YZM~>2Wk%E$d&r@9ly9b4Q zJpM7T@}r63I(OExUlG%Xcjz3MU+9U^r!SkpjNThDtaP)7>j6L5z%o5|^hlVOyI*uY zt^UU6NTuY?(Lb4ZIU2Zb5Vz}Pb7KF%ivf&j^CL>$cDz?rMNTQQ|NqDVD7mhghUp%h zhIA{gi{S8y9YhIIbSv$`B!JiPi!0#4#Jge0)p&YVPHchWcyAn zQhvb8ggXGXs9;k`u9Uq*YB>O+Q3Rq=2hlLFcG{Q3ORH_}JnY8C+r%@}6|%ySP%bWG zV~mA;?P`Q2L_Ss})nrJ{$TmeA9Tt*4=}X5x%RioM@_?ZsKSEST-f+GBv~Ya)xX3O{ z8!d=YthI-13OI;RN~`>|6u5L{z20oBp%9MIj)n$!Aw{Wpq&Rtr4~*_74Gjo@3el>B zz(Rk;;>2lp73<2;d=r*8z%WkdsG=vRuG_fvxO#uN^El|+5Qoz^X!2MfxJ3m}vyi?> zMLLDi8+${Z6YbUg?8GNR>-+SwHKdFyr%HqWcs|X_l*-DAC^bG&KCqWg7-_`UlwQ`EdOp_LJkr`L$mHHs75uP?fSgVfsDjuE#ft2b8HDt0yFt!+;C zEgL=)G9ZFt4wa+N3Xg7FGc0~`&EEt6_%7tyzmnb9B_h1~7~GD4V-Bhx7~QKRkF>&aT>(-!Us@aJxAY@8E?HW$G8g zSz@7Jcp>iCp;lU1ieF6n7!oAa-1E!rS0 zF1lBFVS%G#ZO}b@*+bIk+7@Q|iG60vIDVpV%4tW8rKyzwRo_<25;8*Ky@n z-sX>W*b;M){5lB_Edc@m1`VHy0@dg$PTR9uE$O2&a?KAe?xRlCj&Z$iZYwOz$7E`+5{W^fETbyi(43DY#i1$R+rxIR*mGrVgKGed)|5HyitD@ zZryw9rZ0cDwBi9m?zo>2N*ED;jL6)%K+45bT+LhH-v8z3B;)qgO`rYyUsCs9MaTxS znw&*WBgc^rz|rI+av~o3$)V&}vJUCu`9`F~$P%P%B&Q;m$kRl6NGIvWlYdkP9*LJ5 zWQ1_iJ@c@|Q+L_-{St}ekvjE|!@7Fcj?BFY_nUFQ%9Tt5nEUVp--GoPKZ@Bg5_S1~eA zZ#e1b)lXJyXkc&!(vCS{^_eF#mA`@OIPy20xcY=+@BLECe2l0U`OiQ3q*FIppZ)0) zLhibh5H%*+&PVo*kQMT`_r1UGGr7;{4T>K4yT?gEzJLF0)2l}XCjOonlJoG*>6J!t zA5>#v7s9jOJx^{Q%-rBRZ@7I1(`(WZv{Q_ zbN|-Rzw-|-FhMsoQ0X)Xd6W#2$;1a%&;k|^Abn&CIf%@{SlonBnM9_6Y)Is8;w9fE zWztMSq>YRx(@6?+r$CM(2ZLc8Pp&6-5*4F&G+0KEgh>NQk_^VLNXB7Y1=FaKVKSdA zCCkYwatc{Q4j}`WksMh729qaWAPd2M4kIU!BgqWV$YaS|vXWHD1oCCFf}BUL153Jw zOeJ3-UnPsl8nTIeoqUsAMlL5`Bw6w$u&A@h#pF_Q75N4^ncPS&0juf-%esJEL9Qg5 z$u@Ekxq<8;bI7&iaB>T|oph14WGgwB%qCwWcae!;d|SZe&L-!O?c@w{Iyr{y0u782 zi^RzYNsw=mt4WFMBu9{CV34ikHjMmnWG1>PiE&vBf4U&uiU?Zs|TmW8@T7wI~P*Q^=A^^BbYDpJ>wWOAE0r*R5 zVoU+RWKzqx0GuYZCKrTMQOmjjJSVlB3&40%%ew&FCpGat0H^?|iF^Ri15zux0LnmW zB^N*=NKK480Mvri#2mrkzwTcTu+^tnz01YEGF?Ikl zjPrmCplhTy!39t_QWI+t09r?C;L!reDxAgK13>>s4OBt^C?Tnd^$Gw@B(-4|KpjbK ziVK2s)uy@tib-l>-2gy4NlnZjKnU!$gIoYTCAAqYfU=U>Ocy|7NlmO*0H`gg&2|BF zm(=FC018ZMb6o%}CbfAkfGU%k=qEtPur)FF08naD6YU0oW|Nv|69Ckk)WrJ$pyQ+_ z-Uk3hCpGat0BAd@iT(pX&Cy8s?QYGQl=;0C02gbUycq_)fj za0pTp;|>6?AT?1h09=FAM4JHMAEYMw1^_1^wWC}BPa(BcE`Ym`ns^@oe1_CS82~sA zsU7VCcn_%^;{v!4sfn=wfFF_CS{J~XNNt@9;8CQu-UV+UYKUbCTK_E`W!U+L`U?OYeYu}Mv=4*+;KsfjrNfQysb z`7VH;lbYx!0GyrF#C!n2<4H}dIRLmlsfo1$0N*FIe{lg40I7*}1Ar_*Y8ScyseshP zI{=UmNKLF203-!c6XODa%s^^lUICCENKMQiK{H?QRz!WsurE zE|3wN?{xu^2dO>d0%QbeRsoQ6$eywbka)T%35tA(wITqr6!|&UhX5f}Ie#l?H(f=4 zz~cNCsaaYkT`j#LZNug3Q#E=+vV(BE)vV|U|{#)p&r$+J`a zsjsJM=~e01GoDOSrjog#sW)59em(oU+=AR4d4GOE{^Ih_1r*%&I`t*CpL_OjU*&i><^gXgTB^Yq+v=XKA!dfq4Vi$eC; z_XvNA9|WnZ1nxHg@uiYxR?N>-KP#3xX|+&MbSVu~4WK3XP4W5(+dnqK;zGk(u^=pFhZ}z~*y6 z!M==kmpb`mS}AtXP8y(o9K}^B?-zHxixw4;nxSbN#g!UOi#r~mN=&3qrb9T2E3{wS z@eGYsM5?IANukwpCzVm@5UnDcAGPCz8zlKDzifs-p{br$57RS7$~)lA#M>l;S^jpv z#S9*5DEkMzDI=pZPpc+*vw<1@Fr{Jt|E!q3a?TpY*35B_$I-!#jzQ`kANyZ_nSVwg z{<*HD69>BX^8<~Tv*wNiZJ>h!fyMfI4C`weB>Vs*InY2c^!rCm&PKB|Th12B*(f8A z+p=sw?i}s8^kX~XLj7{~A)mVc37-EdXJ3%}RxUSM{}1^~{4h||W=O`92`S{9)!JXh zyi|HEyebw^@lJ)0c`?N@saj$+JLibvOmWpxA{Kpc&h#nACR3^8u~VjBHf`#$N&Fo< zb=ur7?vkWkUp#*o=ey|ST;iI-wVs6Oxw3er)m`7*l%v_EVsGzR$ctiQY7m!6b`u{h zdj1!8?Y*B`DCRK}o@)!&B&K)MGny7IU)WUa{|e}^&>!~wp6}pO1&5?LMJ-kOOIUAM zmF_}QBbHc%Zg+YsRawDO9$ki3EU1Y<``n|=hN_MfBUo7~&%gec`m zpYGn$-dt)+w9DF@Zbsf|%P3toP1DYc#;BVm5j)o~+^l%$%;(GeKAr&1eM;(7Lks&I zlmmjf*jLO2Xt&ZuyPf2=QEcl`72FFPbg@lUFed^HQxw?eAYf$wGt|>7@DS-%U$29L zND|p_EfBoekF&tcvKn!)+ASHw2@gv}RjG)|l{TuBoK}p!Srpxm(72q08v3wIP?__f zf;Ws-JV<+;HjTa$Csa4urf6ZzLgHhn0l(MuFHtn=m9%b^>Ek^O+AOapr*c1w`R4k< zIBRLur%(1bYJCRN$EgyNJlycl_nWjh$CM?eYMmZQ>oHRPDV~5F^Qg?H=7yp%=4Xo1 zsCkuPU!%9j$CO@)d1c?CV4$GzL;VrSkf_qDsNI^L2uBiejWzkXmwKldcm-CzCmC$e zrpP+)@_5GSisDnE#(XdJNVENxV(4avrgwStVXL7rE_?{ zcscj9=@L4h_D|5gvSEr2aw|9`uX?#pmrSoQ#hXO`nbsvUO)|7YnyBetkHEsP0CQY}@j(L=c}8nddF>Ksr5z2)PNweD<7e}7B1TU&P9JF@)FZKprfyVe@&J2>Cc zyl_?Ls)fxh%?I}nSwpSL%$Z6nF8U8f(%469dmlQT9@m*EQrf?upVDH6-iV4&9XtK# z!ItJj`oE4lK-}A(;v9^!$J~pE$Nsg*7*J`@{R*H^*&4IvAU z8q!ApsYNfwnMm>pPP4&aKYTQoN>e{q>6J7016^^9pj@Ci2~O z>pS(Ij(x5M-Mm5dddK#I!_&-mcv==*r>vTJaIw6ZkK!2ZE9c7`+>K*C#Xq&gpDuiC z|LaH1^q%E!EW43r?RV%!fphNKwlZj%3UV}-uz#;AFX>S NqtXTTr(IH0bTL$Q#&Rt$( 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 WEo6sg2$g9lKpdZ$$_>);_x}MD5#CJz literal 0 HcmV?d00001 diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.svg b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.svg new file mode 100644 index 0000000..c757472 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.svg @@ -0,0 +1,554 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.ttf b/src/parsers/Telegram/telegram_media_downloader/module/static/layui/font/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..06e30f9e2a856cbfefff25111ceb4b9c034f35fd GIT binary patch literal 46508 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
_X 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.timeout/4?g(u+" is not a valid module","error"):void(m.status[u]?c():setTimeout(r,4))}())}function c(){e.push(layui[u]),11e3*m.timeout/4?g(u+" is not a valid module","error"):void("string"==typeof m.modules[u]&&m.status[u]?c():setTimeout(f,4))}():((p=h.createElement("script"))["async"]=!0,p.charset="utf-8",p.src=y+((i=!0===m.version?m.v||(new Date).getTime():m.version||"")?"?v="+i:""),a.appendChild(p),!p.attachEvent||p.attachEvent.toString&&p.attachEvent.toString().indexOf("[native code")<0||b?p.addEventListener("load",function(t){s(t,y)},!1):p.attachEvent("onreadystatechange",function(t){s(t,y)}),m.modules[u]=y),n},r.prototype.disuse=function(t){var o=this;return t=o.isArray(t)?t:[t],o.each(t,function(t,e){m.status[e],delete o[e],delete N[e],delete o.modules[e],delete m.status[e],delete m.modules[e]}),o},r.prototype.getStyle=function(t,e){t=t.currentStyle||d.getComputedStyle(t,null);return t[t.getPropertyValue?"getPropertyValue":"getAttribute"](e)},r.prototype.link=function(o,r,t){var n=this,e=h.getElementsByTagName("head")[0],i=h.createElement("link"),t=((t="string"==typeof r?r:t)||o).replace(/\.|\//g,""),a=i.id="layuicss-"+t,u="creating",l=0;return i.rel="stylesheet",i.href=o+(m.debug?"?v="+(new Date).getTime():""),i.media="all",h.getElementById(a)||e.appendChild(i),"function"!=typeof r||function s(t){var e=h.getElementById(a);return++l>1e3*m.timeout/100?g(o+" timeout"):void(1989===parseInt(n.getStyle(e,"width"))?(t===u&&e.removeAttribute("lay-status"),e.getAttribute("lay-status")===u?setTimeout(s,100):r()):(e.setAttribute("lay-status",u),setTimeout(function(){s(u)},100)))}(),n},r.prototype.addcss=function(t,e,o){return layui.link(m.dir+"css/"+t,e,o)},m.callback={},r.prototype.factory=function(t){if(layui[t])return"function"==typeof m.callback[t]?m.callback[t]:null},r.prototype.img=function(t,e,o){var r=new Image;if(r.src=t,r.complete)return e(r);r.onload=function(){r.onload=null,"function"==typeof e&&e(r)},r.onerror=function(t){r.onerror=null,"function"==typeof o&&o(t)}},r.prototype.config=function(t){for(var e in t=t||{})m[e]=t[e];return this},r.prototype.modules=function(){var t,e={};for(t in N)e[t]=N[t];return e}(),r.prototype.extend=function(t){for(var e in t=t||{})this[e]||this.modules[e]?g(e+" Module already exists","error"):this.modules[e]=t[e];return this},r.prototype.router=r.prototype.hash=function(t){var o={path:[],search:{},hash:((t=t||location.hash).match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(t)&&(t=t.replace(/^#\//,""),o.href="/"+t,t=t.replace(/([^#])(#.*$)/,"$1").split("/")||[],this.each(t,function(t,e){/^\w+=/.test(e)?(e=e.split("="),o.search[e[0]]=e[1]):o.path.push(e)})),o},r.prototype.url=function(t){var n,e,o=this;return{pathname:(t?((t.match(/\.[^.]+?\/.+/)||[])[0]||"").replace(/^[^\/]+/,"").replace(/\?.+/,""):location.pathname).replace(/^\//,"").split("/"),search:(n={},e=(t?((t.match(/\?.+/)||[])[0]||"").replace(/\#.+/,""):location.search).replace(/^\?+/,"").split("&"),o.each(e,function(t,e){var o=e.indexOf("="),r=o<0?e.substr(0,e.length):0!==o&&e.substr(0,o);r&&(n[r]=0(l.innerHeight||f.documentElement.clientHeight)},h.position=function(t,e,n){var o,i,r,c,u,a,s;e&&(n=n||{},t!==f&&t!==h("body")[0]||(n.clickType="right"),u="right"===n.clickType?{left:(u=n.e||l.event||{}).clientX,top:u.clientY,right:u.clientX,bottom:u.clientY}:t.getBoundingClientRect(),a=e.offsetWidth,s=e.offsetHeight,o=function(t){return f.body[t=t?"scrollLeft":"scrollTop"]|f.documentElement[t]},r=u.left,c=u.bottom,"center"===n.align?r-=(a-t.offsetWidth)/2:"right"===n.align&&(r=r-a+t.offsetWidth),(r=r+a+5>(i=function(t){return f.documentElement[t?"clientWidth":"clientHeight"]})("width")?i("width")-a-5:r)<5&&(r=5),c+s+5>i()&&(u.top>s+5?c=u.top-s-10:"right"===n.clickType?(c=i()-s-10)<0&&(c=0):c=5),(a=n.position)&&(e.style.position=a),e.style.left=r+("fixed"===a?0:o(1))+"px",e.style.top=c+("fixed"===a?0:o())+"px",h.hasScrollbar()||(s=e.getBoundingClientRect(),!n.SYSTEM_RELOAD&&s.bottom+5>i()&&(n.SYSTEM_RELOAD=!0,setTimeout(function(){h.position(t,e,n)},50))))},h.options=function(t,e){t=h(t),e=e||"lay-options";try{return new Function("return "+(t.attr(e)||"{}"))()}catch(n){return hint.error("parseerror\uff1a"+n,"error"),{}}},h.isTopElem=function(n){var t=[f,h("body")[0]],o=!1;return h.each(t,function(t,e){if(e===n)return o=!0}),o},i.addStr=function(n,t){return n=n.replace(/\s+/," "),t=t.replace(/\s+/," ").split(" "),h.each(t,function(t,e){new RegExp("\\b"+e+"\\b").test(n)||(n=n+" "+e)}),n.replace(/^\s|\s$/,"")},i.removeStr=function(n,t){return n=n.replace(/\s+/," "),t=t.replace(/\s+/," ").split(" "),h.each(t,function(t,e){e=new RegExp("\\b"+e+"\\b");e.test(n)&&(n=n.replace(e,""))}),n.replace(/\s+/," ").replace(/^\s|\s$/,"")},i.prototype.find=function(o){var i=this,r=0,c=[],u="object"==typeof o;return this.each(function(t,e){for(var n=u?e.contains(o):e.querySelectorAll(o||null);r]|&(?=#[a-zA-Z0-9]+)/g.test(e+="")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):e},error:function(e,r){var n="Laytpl Error: ";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e}},l=a.exp,r=function(e){this.tpl=e},n=(r.pt=r.prototype,window.errors=0,r.pt.parse=function(e,r){var n=e,c=l("^"+p.open+"#",""),t=l(p.close+"$","");e='"use strict";var view = "'+(e=e.replace(/\s+|\r|\t|\n/g," ").replace(l(p.open+"#"),p.open+"# ").replace(l(p.close+"}"),"} "+p.close).replace(/\\/g,"\\\\").replace(l(p.open+"!(.+?)!"+p.close),function(e){return e=e.replace(l("^"+p.open+"!"),"").replace(l("!"+p.close),"").replace(l(p.open+"|"+p.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(a.query(),function(e){return'";'+(e=e.replace(c,"").replace(t,"")).replace(/\\(.)/g,"$1")+';view+="'}).replace(a.query(1),function(e){var r='"+laytpl.escape(';return e.replace(/\s/g,"")===p.open+p.close?"":(e=e.replace(l(p.open+"|"+p.close),""),/^=/.test(e)?e=e.replace(/^=/,""):/^-/.test(e)&&(e=e.replace(/^-/,""),r='"+('),r+e.replace(/\\(.)/g,"$1")+')+"')}))+'";return view;';try{return this.cache=e=new Function("d, laytpl",e),e(r,a)}catch(o){return delete this.cache,a.error(o,n)}},r.pt.render=function(e,r){var n=this;return e?(e=n.cache?n.cache(e,a):n.parse(n.tpl,e),r?void r(e):e):a.error("no data")},function(e){return"string"!=typeof e?a.error("Template not found"):new r(e)});n.config=function(e){for(var r in e=e||{})p[r]=e[r]},n.v="1.2.0",e("laytpl",n)});layui.define(function(e){"use strict";var n=document,u="getElementById",c="getElementsByTagName",a="layui-disabled",t=function(e){var a=this;a.config=e||{},a.config.index=++o.index,a.render(!0)},o=(t.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return e.elem.length===undefined?2:3},t.prototype.view=function(){var t,i,r=this.config,n=r.groups="groups"in r?Number(r.groups)||0:5,u=(r.layout="object"==typeof r.layout?r.layout:["prev","page","next"],r.count=Number(r.count)||0,r.curr=Number(r.curr)||1,r.limits="object"==typeof r.limits?r.limits:[10,20,30,40,50],r.limit=Number(r.limit)||10,r.pages=Math.ceil(r.count/r.limit)||1,r.curr>r.pages?r.curr=r.pages:r.curr<1&&(r.curr=1),n<0?n=1:n>r.pages&&(n=r.pages),r.prev="prev"in r?r.prev:"上一页",r.next="next"in r?r.next:"下一页",r.pages>n?Math.ceil((r.curr+(1'+r.prev+"":"",page:function(){var e=[];if(r.count<1)return"";1'+(r.first||1)+"");var a=Math.floor((n-1)/2),t=1r.pages?r.pages:a:n;for(i-t…');t<=i;t++)t===r.curr?e.push('"+t+""):e.push(''+t+"");return r.pages>n&&r.pages>i&&!1!==r.last&&(i+1…'),0!==n&&e.push(''+(r.last||r.pages)+"")),e.join("")}(),next:r.next?''+r.next+"":"",count:'\u5171 '+r.count+" \u6761",limit:(t=['"),refresh:['','',""].join(""),skip:['到第','','页',""].join("")};return['
',(i=[],layui.each(r.layout,function(e,a){s[a]&&i.push(s[a])}),i.join("")),"
"].join("")},t.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,n=e[c]("button")[0],u=e[c]("input")[0],e=e[c]("select")[0],s=function(){var e=Number(u.value.replace(/\s|\D/g,""));e&&(i.curr=e,t.render())};if(a)return s();for(var l=0,p=r.length;li.pages||(i.curr=e,t.render())});e&&o.on(e,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),n&&o.on(n,"click",function(){s()})}},t.prototype.skip=function(t){var i,e;t&&(i=this,(e=t[c]("input")[0])&&o.on(e,"keyup",function(e){var a=this.value,e=e.keyCode;/^(37|38|39|40)$/.test(e)||(/\D/.test(a)&&(this.value=a.replace(/\D/,"")),13===e&&i.jump(t,!0))}))},t.prototype.render=function(e){var a=this,t=a.config,i=a.type(),r=a.view(),i=(2===i?t.elem&&(t.elem.innerHTML=r):3===i?t.elem.html(r):n[u](t.elem)&&(n[u](t.elem).innerHTML=r),t.jump&&t.jump(t,e),n[u]("layui-laypage-"+t.index));a.jump(i),t.hash&&!e&&(location.hash="!"+t.hash+"="+t.curr),a.skip(i)},{render:function(e){return new t(e).index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(a,e,t){return a.attachEvent?a.attachEvent("on"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1),this}});e("laypage",o)});!function(i,r){"use strict";var n=i.layui&&layui.define,l={getPath:i.lay&&lay.getPath?lay.getPath:"",link:function(e,t,a){u.path&&i.lay&&lay.layui&&lay.layui.link(u.path+e,t,a)}},e=i.LAYUI_GLOBAL||{},u={v:"5.3.1",config:{weekStart:0},index:i.laydate&&i.laydate.v?1e5:0,path:e.laydate_dir||l.getPath,set:function(e){var t=this;return t.config=lay.extend({},t.config,e),t},ready:function(e){var t="laydate",a=(n?"modules/laydate/":"theme/")+"default/laydate.css?v="+u.v;return n?layui.addcss(a,e,t):l.link(a,e,t),this}},s=function(){var t=this,e=t.config.id;return{hint:function(e){t.hint.call(t,e)},config:(s.that[e]=t).config}},a="laydate",w="layui-this",x="laydate-disabled",h=[100,2e5],p="layui-laydate-static",M="layui-laydate-list",o="layui-laydate-hint",E=".laydate-btns-confirm",C="laydate-time-text",k="laydate-btns-time",f="layui-laydate-preview",g=function(e){var t=this,a=(t.index=++u.index,t.config=lay.extend({},t.config,u.config,e),lay(e.elem||t.config.elem));if(1\u8bf7\u91cd\u65b0\u9009\u62e9",invalidDate:"\u4e0d\u5728\u6709\u6548\u65e5\u671f\u6216\u65f6\u95f4\u8303\u56f4\u5185",formatError:["\u65e5\u671f\u683c\u5f0f\u4e0d\u5408\u6cd5
\u5fc5\u987b\u9075\u5faa\u4e0b\u8ff0\u683c\u5f0f\uff1a
","
\u5df2\u4e3a\u4f60\u91cd\u7f6e"],preview:"\u5f53\u524d\u9009\u4e2d\u7684\u7ed3\u679c"},en:{weeks:["Su","Mo","Tu","We","Th","Fr","Sa"],time:["Hours","Minutes","Seconds"],timeTips:"Select Time",startTime:"Start Time",endTime:"End Time",dateTips:"Select Date",month:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],tools:{confirm:"Confirm",clear:"Clear",now:"Now"},timeout:"End time cannot be less than start Time
Please re-select",invalidDate:"Invalid date",formatError:["The date format error
Must be followed\uff1a
","
It has been reset"],preview:"The selected result"}};return e[this.config.lang]||e.cn},g.prototype.init=function(){var r=this,o=r.config,e="static"===o.position,t={year:"yyyy",month:"yyyy-MM",date:"yyyy-MM-dd",time:"HH:mm:ss",datetime:"yyyy-MM-dd HH:mm:ss"};o.elem=lay(o.elem),o.eventElem=lay(o.eventElem),o.elem[0]&&(r.rangeStr=o.range?"string"==typeof o.range?o.range:"-":"","array"===layui.type(o.range)&&(r.rangeElem=[lay(o.range[0]),lay(o.range[1])]),t[o.type]||(i.console&&console.error&&console.error("laydate type error:'"+o.type+"' is not supported"),o.type="date"),o.format===t.date&&(o.format=t[o.type]||t.date),r.format=s.formatArr(o.format),o.weekStart&&!/^[0-6]$/.test(o.weekStart)&&(t=r.lang(),o.weekStart=t.weeks.indexOf(o.weekStart),-1===o.weekStart&&(o.weekStart=0)),r.EXP_IF="",r.EXP_SPLIT="",lay.each(r.format,function(e,t){e=new RegExp(y).test(t)?"\\d{"+(new RegExp(y).test(r.format[0===e?e+1:e-1]||"")?/^yyyy|y$/.test(t)?4:t.length:/^yyyy$/.test(t)?"1,4":/^y$/.test(t)?"1,308":"1,2")+"}":"\\"+t;r.EXP_IF=r.EXP_IF+e,r.EXP_SPLIT=r.EXP_SPLIT+"("+e+")"}),r.EXP_IF_ONE=new RegExp("^"+r.EXP_IF+"$"),r.EXP_IF=new RegExp("^"+(o.range?r.EXP_IF+"\\s\\"+r.rangeStr+"\\s"+r.EXP_IF:r.EXP_IF)+"$"),r.EXP_SPLIT=new RegExp("^"+r.EXP_SPLIT+"$",""),r.isInput(o.elem[0])||"focus"===o.trigger&&(o.trigger="click"),o.elem.attr("lay-key")||(o.elem.attr("lay-key",r.index),o.eventElem.attr("lay-key",r.index)),o.mark=lay.extend({},o.calendar&&"cn"===o.lang?{"0-1-1":"\u5143\u65e6","0-2-14":"\u60c5\u4eba","0-3-8":"\u5987\u5973","0-3-12":"\u690d\u6811","0-4-1":"\u611a\u4eba","0-5-1":"\u52b3\u52a8","0-5-4":"\u9752\u5e74","0-6-1":"\u513f\u7ae5","0-9-10":"\u6559\u5e08","0-10-1":"\u56fd\u5e86","0-12-25":"\u5723\u8bde"}:{},o.mark),lay.each(["min","max"],function(e,t){var a,n,i=[],l=[];l="number"==typeof o[t]?(n=o[t],a=new Date,a=r.newDate({year:a.getFullYear(),month:a.getMonth(),date:a.getDate(),hours:"23",minutes:"59",seconds:"59"}).getTime(),i=[(n=new Date(n?n<864e5?a+864e5*n:n:a)).getFullYear(),n.getMonth()+1,n.getDate()],[n.getHours(),n.getMinutes(),n.getSeconds()]):(i=(o[t].match(/\d+-\d+-\d+/)||[""])[0].split("-"),(o[t].match(/\d+:\d+:\d+/)||[""])[0].split(":")),o[t]={year:0|i[0]||(new Date).getFullYear(),month:i[1]?(0|i[1])-1:(new Date).getMonth(),date:0|i[2]||(new Date).getDate(),hours:0|l[0],minutes:0|l[1],seconds:0|l[2]}}),r.elemID="layui-laydate"+o.elem.attr("lay-key"),(o.show||e)&&r.render(),e||r.events(),o.value&&o.isInitValue&&("date"===layui.type(o.value)?r.setValue(r.parse(0,r.systemDate(o.value))):r.setValue(o.value)))},g.prototype.render=function(){var n,e,t=this,o=t.config,s=t.lang(),i="static"===o.position,a=t.elem=lay.elem("div",{id:t.elemID,"class":["layui-laydate",o.range?" layui-laydate-range":"",i?" "+p:"",o.theme&&"default"!==o.theme&&!/^#/.test(o.theme)?" laydate-theme-"+o.theme:""].join("")}),y=t.elemMain=[],d=t.elemHeader=[],m=t.elemCont=[],c=t.table=[],l=t.footer=lay.elem("div",{"class":"layui-laydate-footer"});o.zIndex&&(a.style.zIndex=o.zIndex),lay.each(new Array(2),function(e){if(!o.range&&0'+s.timeTips+""),!o.range&&"datetime"===o.type||e.push(''),lay.each(o.btns,function(e,t){var a=s.tools[t]||"btn";o.range&&"now"===t||(i&&"clear"===t&&(a="cn"===o.lang?"\u91cd\u7f6e":"Reset"),n.push(''+a+""))}),e.push('"),e.join(""))),lay.each(y,function(e,t){a.appendChild(t)}),o.showBottom&&a.appendChild(l),/^#/.test(o.theme)&&(e=lay.elem("style"),l=["#{{id}} .layui-laydate-header{background-color:{{theme}};}","#{{id}} .layui-this{background-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,t.elemID).replace(/{{theme}}/g,o.theme),"styleSheet"in e?(e.setAttribute("type","text/css"),e.styleSheet.cssText=l):e.innerHTML=l,lay(a).addClass("laydate-theme-molv"),a.appendChild(e)),t.remove(g.thisElemDate),u.thisId=o.id,i?o.elem.append(a):(r.body.appendChild(a),t.position()),t.checkDate().calendar(null,0,"init"),t.changeEvent(),g.thisElemDate=t.elemID,"function"==typeof o.ready&&o.ready(lay.extend({},o.dateTime,{month:o.dateTime.month+1})),t.preview()},g.prototype.remove=function(e){var t=this,a=t.config,n=lay("#"+(e||t.elemID));return n[0]&&(n.hasClass(p)||t.checkDate(function(){n.remove(),delete u.thisId,"function"==typeof a.close&&a.close(t)})),t},g.prototype.position=function(){var e=this.config;return lay.position(this.bindElem||e.elem[0],this.elem,{position:e.position}),this},g.prototype.hint=function(e){var t=this,a=(t.config,lay.elem("div",{"class":o}));t.elem&&(a.innerHTML=e||"",lay(t.elem).find("."+o).remove(),t.elem.appendChild(a),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){lay(t.elem).find("."+o).remove()},3e3))},g.prototype.getAsYM=function(e,t,a){return a?t--:t++,t<0&&(t=11,e--),11h[1]&&(e.year=h[1],o=!0),11t&&(e.date=t,o=!0)},r=function(n,i,l){var r=["startTime","endTime"];i=(i.match(s.EXP_SPLIT)||[]).slice(1),l=l||0,y.range&&(s[r[l]]=s[r[l]]||{}),lay.each(s.format,function(e,t){var a=parseFloat(i[e]);i[e].lengths.getDateTime(y.max)?n=y.dateTime=lay.extend({},y.max):s.getDateTime(n)s.getDateTime(y.max))&&(s.endDate=lay.extend({},y.max)),s.startTime={hours:y.dateTime.hours,minutes:y.dateTime.minutes,seconds:y.dateTime.seconds},s.endTime={hours:s.endDate.hours,minutes:s.endDate.minutes,seconds:s.endDate.seconds}),e&&e(),s},g.prototype.mark=function(e,a){var n,t=this.config;return lay.each(t.mark,function(e,t){e=e.split("-");e[0]!=a[0]&&0!=e[0]||e[1]!=a[1]&&0!=e[1]||e[2]!=a[2]||(n=t||a[2])}),n&&e.html(''+n+""),this},g.prototype.holidays=function(n,i){var e=this.config,l=["","work"];return"array"!==layui.type(e.holidays)||lay.each(e.holidays,function(a,e){lay.each(e,function(e,t){t===n.attr("lay-ymd")&&n.html('"+i[2]+"")})}),this},g.prototype.limit=function(e,t,a,i){var l=this,n=l.config,r={},a=(i?0:41)r.max,e&&e[t?"addClass":"removeClass"](x),t},g.prototype.thisDateTime=function(e){var t=this.config;return e?this.endDate:t.dateTime},g.prototype.calendar=function(e,t,a){var i,l,r,o=this,n=o.config,t=t?1:0,s=e||o.thisDateTime(t),y=new Date,d=o.lang(),m="date"!==n.type&&"datetime"!==n.type,c=lay(o.table[t]).find("td"),t=lay(o.elemHeader[t][2]).find("span");return s.yearh[1]&&(s.year=h[1],o.hint(d.invalidDate)),o.firstDate||(o.firstDate=lay.extend({},s)),y.setFullYear(s.year,s.month,1),i=(y.getDay()+(7-n.weekStart))%7,l=u.getEndDate(s.month||12,s.year),r=u.getEndDate(s.month+1,s.year),lay.each(c,function(e,t){var a=[s.year,s.month],n=0;(t=lay(t)).removeAttr("class"),e"+d.time[t]+"

    "];lay.each(new Array(e),function(e){n.push(""+lay.digit(e,2)+"")}),a.innerHTML=n.join("")+"
",m.appendChild(a)}),l()),p&&h.removeChild(p),h.appendChild(m),"year"===t||"month"===t?(lay(o.elemMain[n]).addClass("laydate-ym-show"),lay(m).find("li").on("click",function(){var e=0|lay(this).attr("lay-ym");lay(this).hasClass(x)||(0===n?(y[t]=e,o.limit(lay(o.footer).find(E),null,0)):o.endDate[t]=e,"year"===s.type||"month"===s.type?(lay(m).find("."+w).removeClass(w),lay(this).addClass(w),"month"===s.type&&"year"===t&&(o.listYM[n][0]=e,a&&((n?o.endDate:y).year=e),o.list("month",n))):(o.checkDate("limit").calendar(null,n),o.closeList()),o.setBtnStatus(),s.range||("month"===s.type&&"month"===t||"year"===s.type&&"year"===t)&&o.setValue(o.parse()).remove().done(),o.done(null,"change"),lay(o.footer).find("."+k).removeClass(x))})):(e=lay.elem("span",{"class":C}),r=function(){lay(m).find("ol").each(function(e){var a=this,t=lay(a).find("li");a.scrollTop=30*(o[D][T[e]]-2),a.scrollTop<=0&&t.each(function(e,t){if(!lay(this).hasClass(x))return a.scrollTop=30*(e-2),!0})})},u=lay(c[2]).find("."+C),r(),e.innerHTML=s.range?[d.startTime,d.endTime][n]:d.timeTips,lay(o.elemMain[n]).addClass("laydate-time-show"),u[0]&&u.remove(),c[2].appendChild(e),lay(m).find("ol").each(function(t){var a=this;lay(a).find("li").on("click",function(){var e=0|this.innerHTML;lay(this).hasClass(x)||(s.range?o[D][T[t]]=e:y[T[t]]=e,lay(a).find("."+w).removeClass(w),lay(this).addClass(w),l(),r(),!o.endDate&&"time"!==s.type||o.done(null,"change"),o.setBtnStatus())})})),o},g.prototype.listYM=[],g.prototype.closeList=function(){var a=this;a.config;lay.each(a.elemCont,function(e,t){lay(this).find("."+M).remove(),lay(a.elemMain[e]).removeClass("laydate-ym-show laydate-time-show")}),lay(a.elem).find("."+C).remove()},g.prototype.setBtnStatus=function(e,t,a){var n=this,i=n.config,l=n.lang(),r=lay(n.footer).find(E);i.range&&"time"!==i.type&&(t=t||i.dateTime,a=a||n.endDate,i=n.newDate(t).getTime()>n.newDate(a).getTime(),n.limit(null,t)||n.limit(null,a)?r.addClass(x):r[i?"addClass":"removeClass"](x),e&&i&&n.hint("string"==typeof e?l.timeout.replace(/\u65e5\u671f/g,e):l.timeout))},g.prototype.parse=function(e,t){var a=this,n=a.config,t=t||("end"==e?lay.extend({},a.endDate,a.endTime):n.range?lay.extend({},n.dateTime,a.startTime):n.dateTime),t=u.parse(t,a.format,1);return n.range&&e===undefined?t+" "+a.rangeStr+" "+a.parse("end"):t},g.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},g.prototype.getDateTime=function(e){return this.newDate(e).getTime()},g.prototype.setValue=function(e){var t=this,a=t.config,n=t.bindElem||a.elem[0];return"static"===a.position||(e=e||"",t.isInput(n)?lay(n).val(e):(a=t.rangeElem)?("array"!==layui.type(e)&&(e=e.split(" "+t.rangeStr+" ")),a[0].val(e[0]||""),a[1].val(e[1]||"")):(0===lay(n).find("*").length&&lay(n).html(e),lay(n).attr("lay-date",e))),t},g.prototype.preview=function(){var e,t=this,a=t.config;a.isPreview&&(e=lay(t.elem).find("."+f),a=!a.range||t.endDate?t.parse():"",e.html(a).css({color:"#5FB878"}),setTimeout(function(){e.css({color:"#666"})},300))},g.prototype.done=function(e,t){var a=this,n=a.config,i=lay.extend({},lay.extend(n.dateTime,a.startTime)),l=lay.extend({},lay.extend(a.endDate,a.endTime));return lay.each([i,l],function(e,t){"month"in t&&lay.extend(t,{month:t.month+1})}),a.preview(),e=e||[a.parse(),i,l],"function"==typeof n[t||"done"]&&n[t||"done"].apply(n,e),a},g.prototype.choose=function(e,a){var n=this,i=n.config,l=n.thisDateTime(a),t=(lay(n.elem).find("td"),{year:0|(t=e.attr("lay-ymd").split("-"))[0],month:(0|t[1])-1,date:0|t[2]});e.hasClass(x)||(lay.extend(l,t),i.range?(lay.each(["startTime","endTime"],function(e,t){n[t]=n[t]||{hours:e?23:0,minutes:e?59:0,seconds:e?59:0},a===e&&(n.getDateTime(lay.extend({},l,n[t]))n.getDateTime(i.max)&&(n[t]={hours:i.max.hours,minutes:i.max.minutes,seconds:i.max.seconds},lay.extend(l,n[t])))}),n.calendar(null,a).done(null,"change")):"static"===i.position?n.calendar().done().done(null,"change"):"date"===i.type?n.setValue(n.parse()).remove().done():"datetime"===i.type&&n.calendar().done(null,"change"))},g.prototype.tool=function(e,t){var a=this,n=a.config,i=a.lang(),l=n.dateTime,r="static"===n.position,o={datetime:function(){lay(e).hasClass(x)||(a.list("time",0),n.range&&a.list("time",1),lay(e).attr("lay-type","date").html(a.lang().dateTips))},date:function(){a.closeList(),lay(e).attr("lay-type","datetime").html(a.lang().timeTips)},clear:function(){r&&(lay.extend(l,a.firstDate),a.calendar()),n.range&&(delete n.dateTime,delete a.endDate,delete a.startTime,delete a.endTime),a.setValue("").remove(),a.done(["",{},{}])},now:function(){var e=new Date;lay.extend(l,a.systemDate(),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()}),a.setValue(a.parse()).remove(),r&&a.calendar(),a.done()},confirm:function(){if(n.range){if(lay(e).hasClass(x))return a.hint("time"===n.type?i.timeout.replace(/\u65e5\u671f/g,"\u65f6\u95f4"):i.timeout)}else if(lay(e).hasClass(x))return a.hint(i.invalidDate);a.setValue(a.parse()).remove(),a.done()}};o[t]&&o[t]()},g.prototype.change=function(n){var i=this,l=i.config,r=i.thisDateTime(n),o=l.range&&("year"===l.type||"month"===l.type),s=i.elemCont[n||0],y=i.listYM[n],e=function(e){var t=lay(s).find(".laydate-year-list")[0],a=lay(s).find(".laydate-month-list")[0];return t&&(y[0]=e?y[0]-15:y[0]+15,i.list("year",n)),a&&(e?y[0]--:y[0]++,i.list("month",n)),(t||a)&&(lay.extend(r,{year:y[0]}),o&&(r.year=y[0]),l.range||i.done(null,"change"),l.range||i.limit(lay(i.footer).find(E),{year:y[0]})),i.setBtnStatus(),t||a};return{prevYear:function(){e("sub")||(r.year--,i.checkDate("limit").calendar(null,n),i.done(null,"change"))},prevMonth:function(){var e=i.getAsYM(r.year,r.month,"sub");lay.extend(r,{year:e[0],month:e[1]}),i.checkDate("limit").calendar(null,n),i.done(null,"change")},nextMonth:function(){var e=i.getAsYM(r.year,r.month);lay.extend(r,{year:e[0],month:e[1]}),i.checkDate("limit").calendar(null,n),i.done(null,"change")},nextYear:function(){e()||(r.year++,i.checkDate("limit").calendar(null,n),i.done(null,"change"))}}},g.prototype.changeEvent=function(){var i=this;i.config;lay(i.elem).on("click",function(e){lay.stope(e)}).on("mousedown",function(e){lay.stope(e)}),lay.each(i.elemHeader,function(n,e){lay(e[0]).on("click",function(e){i.change(n).prevYear()}),lay(e[1]).on("click",function(e){i.change(n).prevMonth()}),lay(e[2]).find("span").on("click",function(e){var t=lay(this),a=t.attr("lay-ym"),t=t.attr("lay-type");a&&(a=a.split("-"),i.listYM[n]=[0|a[0],0|a[1]],i.list(t,n),lay(i.footer).find("."+k).addClass(x))}),lay(e[3]).on("click",function(e){i.change(n).nextMonth()}),lay(e[4]).on("click",function(e){i.change(n).nextYear()})}),lay.each(i.table,function(e,t){lay(t).find("td").on("click",function(){i.choose(lay(this),e)})}),lay(i.footer).find("span").on("click",function(){var e=lay(this).attr("lay-type");i.tool(this,e)})},g.prototype.isInput=function(e){return/input|textarea/.test(e.tagName.toLocaleLowerCase())||/INPUT|TEXTAREA/.test(e.tagName)},g.prototype.events=function(){var a=this,n=a.config,e=function(e,t){e.on(n.trigger,function(){u.thisId!==n.id&&(t&&(a.bindElem=this),a.render())})};n.elem[0]&&!n.elem[0].eventHandler&&(e(n.elem,"bind"),e(n.eventElem),n.elem[0].eventHandler=!0)},s.that={},s.getThis=function(e){var t=s.that[e];return!t&&n&&layui.hint().error(e?a+" instance with ID '"+e+"' not found":"ID argument required"),t},l.run=function(n){n(r).on("mousedown",function(e){var t,a;!u.thisId||(t=s.getThis(u.thisId))&&(a=t.config,e.target!==a.elem[0]&&e.target!==a.eventElem[0]&&e.target!==n(a.closeStop)[0]&&t.remove())}).on("keydown",function(e){var t;!u.thisId||(t=s.getThis(u.thisId))&&"static"!==t.config.position&&13===e.keyCode&&n("#"+t.elemID)[0]&&t.elemID===g.thisElemDate&&(e.preventDefault(),n(t.footer).find(E)[0].click())}),n(i).on("resize",function(){if(u.thisId){var e=s.getThis(u.thisId);if(e)return!(!e.elem||!n(".layui-laydate")[0])&&void e.position()}})},u.render=function(e){e=new g(e);return s.call(e)},u.parse=function(a,n,i){return a=a||{},n=((n="string"==typeof n?s.formatArr(n):n)||[]).concat(),lay.each(n,function(e,t){/yyyy|y/.test(t)?n[e]=lay.digit(a.year,t.length):/MM|M/.test(t)?n[e]=lay.digit(a.month+(i||0),t.length):/dd|d/.test(t)?n[e]=lay.digit(a.date,t.length):/HH|H/.test(t)?n[e]=lay.digit(a.hours,t.length):/mm|m/.test(t)?n[e]=lay.digit(a.minutes,t.length):/ss|s/.test(t)&&(n[e]=lay.digit(a.seconds,t.length))}),n.join("")},u.getEndDate=function(e,t){var a=new Date;return a.setFullYear(t||a.getFullYear(),e||a.getMonth()+1,1),new Date(a.getTime()-864e5).getDate()},u.close=function(e){e=s.getThis(e||u.thisId);if(e)return e.remove()},n?(u.ready(),layui.define("lay",function(e){u.path=layui.cache.dir,l.run(lay),e(a,u)})):"function"==typeof define&&define.amd?define(function(){return l.run(lay),u}):(u.ready(),l.run(i.lay),i.laydate=u)}(window,window.document);!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e):function(e){if(e.document)return t(e);throw new Error("jQuery requires a window with a document")}:t(e)}("undefined"!=typeof window?window:this,function(T,M){var f=[],g=T.document,c=f.slice,O=f.concat,R=f.push,P=f.indexOf,B={},W=B.toString,m=B.hasOwnProperty,y={},e="1.12.4",C=function(e,t){return new C.fn.init(e,t)},I=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,$=/^-ms-/,z=/-([\da-z])/gi,X=function(e,t){return t.toUpperCase()};function U(e){var t=!!e&&"length"in e&&e.length,n=C.type(e);return"function"!==n&&!C.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+a+")"+a+"*"),ee=new RegExp("="+a+"*([^\\]'\"]*?)"+a+"*\\]","g"),te=new RegExp(G),ne=new RegExp("^"+s+"$"),f={ID:new RegExp("^#("+s+")"),CLASS:new RegExp("^\\.("+s+")"),TAG:new RegExp("^("+s+"|[*])"),ATTR:new RegExp("^"+J),PSEUDO:new RegExp("^"+G),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+a+"*(even|odd|(([+-]|)(\\d*)n|)"+a+"*(?:([+-]|)"+a+"*(\\d+)|))"+a+"*\\)|)","i"),bool:new RegExp("^(?:"+Y+")$","i"),needsContext:new RegExp("^"+a+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+a+"*((?:-\\d)?\\d*)"+a+"*\\)|)(?=[^-]|$)","i")},re=/^(?:input|select|textarea|button)$/i,ie=/^h\d$/i,c=/^[^{]+\{\s*\[native \w/,oe=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ae=/[+~]/,se=/'|\\/g,d=new RegExp("\\\\([\\da-f]{1,6}"+a+"?|("+a+")|.)","ig"),p=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(65536+r):String.fromCharCode(r>>10|55296,1023&r|56320)},ue=function(){C()};try{D.apply(n=V.call(v.childNodes),v.childNodes),n[v.childNodes.length].nodeType}catch(F){D={apply:n.length?function(e,t){U.apply(e,V.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function H(e,t,n,r){var i,o,a,s,u,l,c,f,d=t&&t.ownerDocument,p=t?t.nodeType:9;if(n=n||[],"string"!=typeof e||!e||1!==p&&9!==p&&11!==p)return n;if(!r&&((t?t.ownerDocument||t:v)!==E&&C(t),t=t||E,N)){if(11!==p&&(l=oe.exec(e)))if(i=l[1]){if(9===p){if(!(a=t.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(d&&(a=d.getElementById(i))&&y(t,a)&&a.id===i)return n.push(a),n}else{if(l[2])return D.apply(n,t.getElementsByTagName(e)),n;if((i=l[3])&&g.getElementsByClassName&&t.getElementsByClassName)return D.apply(n,t.getElementsByClassName(i)),n}if(g.qsa&&!A[e+" "]&&(!m||!m.test(e))){if(1!==p)d=t,f=e;else if("object"!==t.nodeName.toLowerCase()){for((s=t.getAttribute("id"))?s=s.replace(se,"\\$&"):t.setAttribute("id",s=k),o=(c=w(e)).length,u=ne.test(s)?"#"+s:"[id='"+s+"']";o--;)c[o]=u+" "+_(c[o]);f=c.join(","),d=ae.test(e)&&de(t.parentNode)||t}if(f)try{return D.apply(n,d.querySelectorAll(f)),n}catch(h){}finally{s===k&&t.removeAttribute("id")}}}return P(e.replace(L,"$1"),t,n,r)}function le(){var n=[];function r(e,t){return n.push(e+" ")>b.cacheLength&&delete r[n.shift()],r[e+" "]=t}return r}function q(e){return e[k]=!0,e}function h(e){var t=E.createElement("div");try{return!!e(t)}catch(F){return!1}finally{t.parentNode&&t.parentNode.removeChild(t)}}function ce(e,t){for(var n=e.split("|"),r=n.length;r--;)b.attrHandle[n[r]]=t}function fe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||1<<31)-(~e.sourceIndex||1<<31);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function x(a){return q(function(o){return o=+o,q(function(e,t){for(var n,r=a([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function de(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in g=H.support={},O=H.isXML=function(e){e=e&&(e.ownerDocument||e).documentElement;return!!e&&"HTML"!==e.nodeName},C=H.setDocument=function(e){var e=e?e.ownerDocument||e:v;return e!==E&&9===e.nodeType&&e.documentElement&&(t=(E=e).documentElement,N=!O(E),(e=E.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",ue,!1):e.attachEvent&&e.attachEvent("onunload",ue)),g.attributes=h(function(e){return e.className="i",!e.getAttribute("className")}),g.getElementsByTagName=h(function(e){return e.appendChild(E.createComment("")),!e.getElementsByTagName("*").length}),g.getElementsByClassName=c.test(E.getElementsByClassName),g.getById=h(function(e){return t.appendChild(e).id=k,!E.getElementsByName||!E.getElementsByName(k).length}),g.getById?(b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&N)return(e=t.getElementById(e))?[e]:[]},b.filter.ID=function(e){var t=e.replace(d,p);return function(e){return e.getAttribute("id")===t}}):(delete b.find.ID,b.filter.ID=function(e){var t=e.replace(d,p);return function(e){e="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return e&&e.value===t}}),b.find.TAG=g.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):g.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},b.find.CLASS=g.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&N)return t.getElementsByClassName(e)},r=[],m=[],(g.qsa=c.test(E.querySelectorAll))&&(h(function(e){t.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&m.push("[*^$]="+a+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||m.push("\\["+a+"*(?:value|"+Y+")"),e.querySelectorAll("[id~="+k+"-]").length||m.push("~="),e.querySelectorAll(":checked").length||m.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||m.push(".#.+[+~]")}),h(function(e){var t=E.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&m.push("name"+a+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||m.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),m.push(",.*:")})),(g.matchesSelector=c.test(i=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.msMatchesSelector))&&h(function(e){g.disconnectedMatch=i.call(e,"div"),i.call(e,"[s!='']:x"),r.push("!=",G)}),m=m.length&&new RegExp(m.join("|")),r=r.length&&new RegExp(r.join("|")),e=c.test(t.compareDocumentPosition),y=e||c.test(t.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,t=t&&t.parentNode;return e===t||!(!t||1!==t.nodeType||!(n.contains?n.contains(t):e.compareDocumentPosition&&16&e.compareDocumentPosition(t)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},$=e?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!g.sortDetached&&t.compareDocumentPosition(e)===n?e===E||e.ownerDocument===v&&y(v,e)?-1:t===E||t.ownerDocument===v&&y(v,t)?1:u?j(u,e)-j(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===E?-1:t===E?1:i?-1:o?1:u?j(u,e)-j(u,t):0;if(i===o)return fe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?fe(a[r],s[r]):a[r]===v?-1:s[r]===v?1:0}),E},H.matches=function(e,t){return H(e,null,null,t)},H.matchesSelector=function(e,t){if((e.ownerDocument||e)!==E&&C(e),t=t.replace(ee,"='$1']"),g.matchesSelector&&N&&!A[t+" "]&&(!r||!r.test(t))&&(!m||!m.test(t)))try{var n=i.call(e,t);if(n||g.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(F){}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(d,p),e[3]=(e[3]||e[4]||e[5]||"").replace(d,p),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||H.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&H.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return f.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&te.test(n)&&(t=w(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(d,p).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=W[e+" "];return t||(t=new RegExp("(^|"+a+")"+e+"("+a+"|$)"))&&W(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(t,n,r){return function(e){e=H.attr(e,t);return null==e?"!="===n:!n||(e+="","="===n?e===r:"!="===n?e!==r:"^="===n?r&&0===e.indexOf(r):"*="===n?r&&-1(?:<\/\1>|)$/,G=/^.[^:#\[\.,]*$/;function K(e,n,r){if(C.isFunction(n))return C.grep(e,function(e,t){return!!n.call(e,t,e)!==r});if(n.nodeType)return C.grep(e,function(e){return e===n!==r});if("string"==typeof n){if(G.test(n))return C.filter(n,e,r);n=C.filter(n,e)}return C.grep(e,function(e){return-1)[^>]*|#([\w-]*))$/,ee=((C.fn.init=function(e,t,n){if(!e)return this;if(n=n||Q,"string"!=typeof e)return e.nodeType?(this.context=this[0]=e,this.length=1,this):C.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(C):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),C.makeArray(e,this));if(!(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&3<=e.length?[null,e,null]:Z.exec(e))||!r[1]&&t)return(!t||t.jquery?t||n:this.constructor(t)).find(e);if(r[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:g,!0)),J.test(r[1])&&C.isPlainObject(t))for(var r in t)C.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if((n=g.getElementById(r[2]))&&n.parentNode){if(n.id!==r[2])return Q.find(e);this.length=1,this[0]=n}return this.context=g,this.selector=e,this}).prototype=C.fn,Q=C(g),/^(?:parents|prev(?:Until|All))/),te={children:!0,contents:!0,next:!0,prev:!0};function ne(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t,n=C(e,this),r=n.length;return this.filter(function(){for(t=0;t
a",y.leadingWhitespace=3===S.firstChild.nodeType,y.tbody=!S.getElementsByTagName("tbody").length,y.htmlSerialize=!!S.getElementsByTagName("link").length,y.html5Clone="<:nav>"!==g.createElement("nav").cloneNode(!0).outerHTML,q.type="checkbox",q.checked=!0,k.appendChild(q),y.appendChecked=q.checked,S.innerHTML="",y.noCloneChecked=!!S.cloneNode(!0).lastChild.defaultValue,k.appendChild(S),(q=g.createElement("input")).setAttribute("type","radio"),q.setAttribute("checked","checked"),q.setAttribute("name","t"),S.appendChild(q),y.checkClone=S.cloneNode(!0).cloneNode(!0).lastChild.checked,y.noCloneEvent=!!S.addEventListener,S[C.expando]=1,y.attributes=!S.getAttribute(C.expando);var x={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:y.htmlSerialize?[0,"",""]:[1,"X
","
"]};function b(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):undefined;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||C.nodeName(r,t)?o.push(r):C.merge(o,b(r,t));return t===undefined||t&&C.nodeName(e,t)?C.merge([e],o):o}function we(e,t){for(var n,r=0;null!=(n=e[r]);r++)C._data(n,"globalEval",!t||C._data(t[r],"globalEval"))}x.optgroup=x.option,x.tbody=x.tfoot=x.colgroup=x.caption=x.thead,x.th=x.td;var Te=/<|&#?\w+;/,Ce=/"!==f[1]||Ce.test(a)?0:u:u.firstChild)&&a.childNodes.length;o--;)C.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(C.merge(h,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=p.lastChild}else h.push(t.createTextNode(a));for(u&&p.removeChild(u),y.appendChecked||C.grep(b(h,"input"),Ee),g=0;a=h[g++];)if(r&&-1]","i"),Pe=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,Be=/\s*$/g,ze=be(g).appendChild(g.createElement("div"));function Xe(e,t){return C.nodeName(e,"table")&&C.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ue(e){return e.type=(null!==C.find.attr(e,"type"))+"/"+e.type,e}function Ve(e){var t=Ie.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Ye(e,t){if(1===t.nodeType&&C.hasData(e)){var n,r,i,e=C._data(e),o=C._data(t,e),a=e.events;if(a)for(n in delete o.handle,o.events={},a)for(r=0,i=a[n].length;r")},clone:function(e,t,n){var r,i,o,a,s,u=C.contains(e.ownerDocument,e);if(y.html5Clone||C.isXMLDoc(e)||!Re.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(ze.innerHTML=e.outerHTML,ze.removeChild(o=ze.firstChild)),!(y.noCloneEvent&&y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||C.isXMLDoc(e)))for(r=b(o),s=b(e),a=0;null!=(i=s[a]);++a)if(r[a]){f=c=l=p=d=void 0;var l,c,f,d=i,p=r[a];if(1===p.nodeType){if(l=p.nodeName.toLowerCase(),!y.noCloneEvent&&p[C.expando]){for(c in(f=C._data(p)).events)C.removeEvent(p,c,f.handle);p.removeAttribute(C.expando)}"script"===l&&p.text!==d.text?(Ue(p).text=d.text,Ve(p)):"object"===l?(p.parentNode&&(p.outerHTML=d.outerHTML),y.html5Clone&&d.innerHTML&&!C.trim(p.innerHTML)&&(p.innerHTML=d.innerHTML)):"input"===l&&ge.test(d.type)?(p.defaultChecked=p.checked=d.checked,p.value!==d.value&&(p.value=d.value)):"option"===l?p.defaultSelected=p.selected=d.defaultSelected:"input"!==l&&"textarea"!==l||(p.defaultValue=d.defaultValue)}}if(t)if(n)for(s=s||b(e),r=r||b(o),a=0;null!=(i=s[a]);a++)Ye(i,r[a]);else Ye(e,o);return 0<(r=b(o,"script")).length&&we(r,!u&&b(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=C.expando,u=C.cache,l=y.attributes,c=C.event.special;null!=(n=e[a]);a++)if((t||v(n))&&(o=(i=n[s])&&u[i])){if(o.events)for(r in o.events)c[r]?C.event.remove(n,r):C.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=undefined:n.removeAttribute(s),f.push(i))}}}),C.fn.extend({domManip:w,detach:function(e){return Je(this,e,!0)},remove:function(e){return Je(this,e)},text:function(e){return d(this,function(e){return e===undefined?C.text(this):this.empty().append((this[0]&&this[0].ownerDocument||g).createTextNode(e))},null,e,arguments.length)},append:function(){return w(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Xe(this,e).appendChild(e)})},prepend:function(){return w(this,arguments,function(e){var t;1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(t=Xe(this,e)).insertBefore(e,t.firstChild)})},before:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&C.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&C.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return C.clone(this,e,t)})},html:function(e){return d(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined)return 1===t.nodeType?t.innerHTML.replace(Oe,""):undefined;if("string"==typeof e&&!Be.test(e)&&(y.htmlSerialize||!Re.test(e))&&(y.leadingWhitespace||!ve.test(e))&&!x[(me.exec(e)||["",""])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n")).appendTo(t.documentElement))[0].contentWindow||Ge[0].contentDocument).document).write(),t.close(),n=Qe(e,t),Ge.detach()),Ke[e]=n),n}var n,et,tt,nt,rt,it,ot,a,at=/^margin/,st=new RegExp("^("+e+")(?!px)[a-z%]+$","i"),ut=function(e,t,n,r){var i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.apply(e,r||[]),t)e.style[i]=o[i];return r},lt=g.documentElement;function t(){var e,t=g.documentElement;t.appendChild(ot),a.style.cssText="-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",n=tt=it=!1,et=rt=!0,T.getComputedStyle&&(e=T.getComputedStyle(a),n="1%"!==(e||{}).top,it="2px"===(e||{}).marginLeft,tt="4px"===(e||{width:"4px"}).width,a.style.marginRight="50%",et="4px"===(e||{marginRight:"4px"}).marginRight,(e=a.appendChild(g.createElement("div"))).style.cssText=a.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",e.style.marginRight=e.style.width="0",a.style.width="1px",rt=!parseFloat((T.getComputedStyle(e)||{}).marginRight),a.removeChild(e)),a.style.display="none",(nt=0===a.getClientRects().length)&&(a.style.display="",a.innerHTML="
t
",a.childNodes[0].style.borderCollapse="separate",(e=a.getElementsByTagName("td"))[0].style.cssText="margin:0;border:0;padding:0;display:none",(nt=0===e[0].offsetHeight)&&(e[0].style.display="",e[1].style.display="none",nt=0===e[0].offsetHeight)),t.removeChild(ot)}ot=g.createElement("div"),(a=g.createElement("div")).style&&(a.style.cssText="float:left;opacity:.5",y.opacity="0.5"===a.style.opacity,y.cssFloat=!!a.style.cssFloat,a.style.backgroundClip="content-box",a.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===a.style.backgroundClip,(ot=g.createElement("div")).style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",a.innerHTML="",ot.appendChild(a),y.boxSizing=""===a.style.boxSizing||""===a.style.MozBoxSizing||""===a.style.WebkitBoxSizing,C.extend(y,{reliableHiddenOffsets:function(){return null==n&&t(),nt},boxSizingReliable:function(){return null==n&&t(),tt},pixelMarginRight:function(){return null==n&&t(),et},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),rt},reliableMarginLeft:function(){return null==n&&t(),it}}));var l,p,ct=/^(top|right|bottom|left)$/;function ft(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}T.getComputedStyle?(l=function(e){var t=e.ownerDocument.defaultView;return(t=t&&t.opener?t:T).getComputedStyle(e)},p=function(e,t,n){var r,i,o=e.style;return""!==(i=(n=n||l(e))?n.getPropertyValue(t)||n[t]:undefined)&&i!==undefined||C.contains(e.ownerDocument,e)||(i=C.style(e,t)),n&&!y.pixelMarginRight()&&st.test(i)&&at.test(t)&&(e=o.width,t=o.minWidth,r=o.maxWidth,o.minWidth=o.maxWidth=o.width=i,i=n.width,o.width=e,o.minWidth=t,o.maxWidth=r),i===undefined?i:i+""}):lt.currentStyle&&(l=function(e){return e.currentStyle},p=function(e,t,n){var r,i,o,a=e.style;return null==(n=(n=n||l(e))?n[t]:undefined)&&a&&a[t]&&(n=a[t]),st.test(n)&&!ct.test(t)&&(r=a.left,(o=(i=e.runtimeStyle)&&i.left)&&(i.left=e.currentStyle.left),a.left="fontSize"===t?"1em":n,n=a.pixelLeft+"px",a.left=r,o&&(i.left=o)),n===undefined?n:n+""||"auto"});var dt=/alpha\([^)]*\)/i,pt=/opacity\s*=\s*([^)]*)/i,ht=/^(none|table(?!-c[ea]).+)/,gt=new RegExp("^("+e+")(.*)$","i"),mt={position:"absolute",visibility:"hidden",display:"block"},yt={letterSpacing:"0",fontWeight:"400"},vt=["Webkit","O","Moz","ms"],xt=g.createElement("div").style;function bt(e){if(e in xt)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=vt.length;n--;)if((e=vt[n]+t)in xt)return e}function wt(e,t){for(var n,r,i,o=[],a=0,s=e.length;a
a",F=q.getElementsByTagName("a")[0],k.setAttribute("type","checkbox"),q.appendChild(k),(F=q.getElementsByTagName("a")[0]).style.cssText="top:1px",y.getSetAttribute="t"!==q.className,y.style=/top/.test(F.getAttribute("style")),y.hrefNormalized="/a"===F.getAttribute("href"),y.checkOn=!!k.value,y.optSelected=e.selected,y.enctype=!!g.createElement("form").enctype,S.disabled=!0,y.optDisabled=!e.disabled,(k=g.createElement("input")).setAttribute("value",""),y.input=""===k.getAttribute("value"),k.value="t",k.setAttribute("type","radio"),y.radioValue="t"===k.value;var Lt=/\r/g,Ht=/[\x20\t\r\n\f]+/g;C.fn.extend({val:function(t){var n,e,r,i=this[0];return arguments.length?(r=C.isFunction(t),this.each(function(e){1===this.nodeType&&(null==(e=r?t.call(this,e,C(this).val()):t)?e="":"number"==typeof e?e+="":C.isArray(e)&&(e=C.map(e,function(e){return null==e?"":e+""})),(n=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&"set"in n&&n.set(this,e,"value")!==undefined||(this.value=e))})):i?(n=C.valHooks[i.type]||C.valHooks[i.nodeName.toLowerCase()])&&"get"in n&&(e=n.get(i,"value"))!==undefined?e:"string"==typeof(e=i.value)?e.replace(Lt,""):null==e?"":e:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,"value");return null!=t?t:C.trim(C.text(e)).replace(Ht," ")}},select:{get:function(e){for(var t,n=e.options,r=e.selectedIndex,i="select-one"===e.type||r<0,o=i?null:[],a=i?r+1:n.length,s=r<0?a:i?r:0;s").append(C.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},C.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){C.fn[t]=function(e){return this.on(t,e)}}),C.expr.filters.animated=function(t){return C.grep(C.timers,function(e){return t===e.elem}).length},C.offset={setOffset:function(e,t,n){var r,i,o,a,s=C.css(e,"position"),u=C(e),l={};"static"===s&&(e.style.position="relative"),o=u.offset(),r=C.css(e,"top"),a=C.css(e,"left"),s=("absolute"===s||"fixed"===s)&&-1'+(o?n.title[0]:n.title)+"":"";return n.zIndex=a,t([n.shade?'
':"",'
'+(e&&2!=n.type?"":o)+'
'+(0==n.type&&-1!==n.icon?'':"")+((1!=n.type||!e)&&n.content||"")+'
'+(i=s?'':"",n.closeBtn&&(i+=''),i)+""+(n.btn?function(){var e="";"string"==typeof n.btn&&(n.btn=[n.btn]);for(var t=0,i=n.btn.length;t'+n.btn[t]+"";return'
'+e+"
"}():"")+(n.resize?'':"")+"
"],o,h('
')),this},t.pt.creat=function(){var e,n=this,a=n.config,o=n.index,s="object"==typeof(l=a.content),r=h("body");if(!a.id||!h("#"+a.id)[0]){switch("string"==typeof a.area&&(a.area="auto"===a.area?["",""]:[a.area,""]),a.shift&&(a.anim=a.shift),6==m.ie&&(a.fixed=!1),a.type){case 0:a.btn="btn"in a?a.btn:c.btn[0],m.closeAll("dialog");break;case 2:var l=a.content=s?a.content:[a.content||"","auto"];a.content='';break;case 3:delete a.title,delete a.closeBtn,-1===a.icon&&a.icon,m.closeAll("loading");break;case 4:s||(a.content=[a.content,"body"]),a.follow=a.content[1],a.content=a.content[0]+'',delete a.title,a.tips="object"==typeof a.tips?a.tips:[a.tips,!0],a.tipsMore||m.closeAll("tips")}n.vessel(s,function(e,t,i){r.append(e[0]),s?2==a.type||4==a.type?h("body").append(e[1]):l.parents("."+d[0])[0]||(l.data("display",l.css("display")).show().addClass("layui-layer-wrap").wrap(e[1]),h("#"+d[0]+o).find("."+d[5]).before(t)):r.append(e[1]),h("#"+d.MOVE)[0]||r.append(c.moveElem=i),n.layero=h("#"+d[0]+o),n.shadeo=h("#"+d.SHADE+o),a.scrollbar||d.html.css("overflow","hidden").attr("layer-full",o)}).auto(o),n.shadeo.css({"background-color":a.shade[1]||"#000",opacity:a.shade[0]||a.shade}),2==a.type&&6==m.ie&&n.layero.find("iframe").attr("src",l[0]),4==a.type?n.tips():(n.offset(),parseInt(c.getStyle(document.getElementById(d.MOVE),"z-index"))||(n.layero.css("visibility","hidden"),m.ready(function(){n.offset(),n.layero.css("visibility","visible")}))),a.fixed&&f.on("resize",function(){n.offset(),(/^\d+%$/.test(a.area[0])||/^\d+%$/.test(a.area[1]))&&n.auto(o),4==a.type&&n.tips()}),a.time<=0||setTimeout(function(){m.close(n.index)},a.time),n.move().callback(),d.anim[a.anim]&&(e="layer-anim "+d.anim[a.anim],n.layero.addClass(e).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){h(this).removeClass(e)})),a.isOutAnim&&n.layero.data("isOutAnim",!0)}},t.pt.auto=function(e){var t=this.config,i=h("#"+d[0]+e),n=(""===t.area[0]&&0t.maxWidth&&i.width(t.maxWidth)),[i.innerWidth(),i.innerHeight()]),a=i.find(d[1]).outerHeight()||0,o=i.find("."+d[6]).outerHeight()||0,e=function(e){(e=i.find(e)).height(n[1]-a-o-2*(0|parseFloat(e.css("padding-top"))))};return 2===t.type?e("iframe"):""===t.area[1]?0t.maxHeight?(n[1]=t.maxHeight,e("."+d[5])):t.fixed&&n[1]>=f.height()&&(n[1]=f.height(),e("."+d[5])):e("."+d[5]),this},t.pt.offset=function(){var e=this,t=e.config,i=e.layero,n=[i.outerWidth(),i.outerHeight()],a="object"==typeof t.offset;e.offsetTop=(f.height()-n[1])/2,e.offsetLeft=(f.width()-n[0])/2,a?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=f.width()-n[0]:"b"===t.offset?e.offsetTop=f.height()-n[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=f.height()-n[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=f.width()-n[0]):"rb"===t.offset?(e.offsetTop=f.height()-n[1],e.offsetLeft=f.width()-n[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?f.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?f.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=f.scrollTop(),e.offsetLeft+=f.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=f.height()-(i.find(d[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},t.pt.tips=function(){var e=this.config,t=this.layero,i=[t.outerWidth(),t.outerHeight()],n=h(e.follow),a={width:(n=n[0]?n:h("body")).outerWidth(),height:n.outerHeight(),top:n.offset().top,left:n.offset().left},o=t.find(".layui-layer-TipsG"),n=e.tips[0];e.tips[1]||o.remove(),a.autoLeft=function(){0":'',o=i.success;return delete i.success,m.open(h.extend({type:1,btn:["确定","取消"],content:t,skin:"layui-layer-prompt"+g("prompt"),maxWidth:f.width(),success:function(e){(a=e.find(".layui-layer-input")).val(i.value||"").focus(),"function"==typeof o&&o(e)},resize:!1,yes:function(e){var t=a.val();""===t?a.focus():t.length>(i.maxlength||500)?m.tips("最多输入"+(i.maxlength||500)+"个字数",a,{tips:1}):n&&n(t,e,a)}},i))},m.tab=function(n){var a=(n=n||{}).tab||{},o="layui-this",s=n.success;return delete n.success,m.open(h.extend({type:1,skin:"layui-layer-tab"+g("tab"),resize:!1,title:function(){var e=a.length,t=1,i="";if(0'+a[0].title+"";t"+a[t].title+"";return i}(),content:'
    '+function(){var e=a.length,t=1,i="";if(0'+(a[0].content||"no content")+"";t'+(a[t].content||"no content")+"";return i}()+"
",success:function(e){var t=e.find(".layui-layer-title").children(),i=e.find(".layui-layer-tabmain").children();t.on("mousedown",function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0;var e=h(this),t=e.index();e.addClass(o).siblings().removeClass(o),i.eq(t).show().siblings().hide(),"function"==typeof n.change&&n.change(t)}),"function"==typeof s&&s(e)}},n))},m.photos=function(i,e,n){var a={};if((i=i||{}).photos){var t=!("string"==typeof i.photos||i.photos instanceof h),o=t?i.photos:{},s=o.data||[],r=o.start||0,l=(a.imgIndex=1+(0|r),i.img=i.img||"img",i.success);if(delete i.success,t){if(0===s.length)return m.msg("没有图片")}else{var f=h(i.photos),c=function(){s=[],f.find(i.img).each(function(e){var t=h(this);t.attr("layer-index",e),s.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(c(),0===s.length)return;if(e||f.on("click",i.img,function(){c();var e=h(this).attr("layer-index");m.photos(h.extend(i,{photos:{start:e,data:s,tab:i.tab},full:i.full}),!0)}),!e)return}a.imgprev=function(e){a.imgIndex--,a.imgIndex<1&&(a.imgIndex=s.length),a.tabimg(e)},a.imgnext=function(e,t){a.imgIndex++,a.imgIndex>s.length&&(a.imgIndex=1,t)||a.tabimg(e)},a.keyup=function(e){var t;a.end||(t=e.keyCode,e.preventDefault(),37===t?a.imgprev(!0):39===t?a.imgnext(!0):27===t&&m.close(a.index))},a.tabimg=function(e){if(!(s.length<=1))return o.start=a.imgIndex-1,m.close(a.index),m.photos(i,!0,e)},a.event=function(){a.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),a.imgprev(!0)}),a.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),a.imgnext(!0)}),h(document).on("keyup",a.keyup)},a.loadi=m.load(1,{shade:!("shade"in i)&&.9,scrollbar:!1});var t=s[r].src,d=function(e){var t;m.close(a.loadi),n&&(i.anim=-1),a.index=m.open(h.extend({type:1,id:"layui-layer-photos",area:(e=[e.width,e.height],t=[h(p).width()-100,h(p).height()-100],!i.full&&(e[0]>t[0]||e[1]>t[1])&&((t=[e[0]/t[0],e[1]/t[1]])[1]'+(s[r].alt||'+(1
'+(s[r].alt||"")+""+a.imgIndex+" / "+s.length+"
":"")+"",success:function(e,t){a.bigimg=e.find(".layui-layer-phimg"),a.imgsee=e.find(".layui-layer-imgbar"),a.event(e),i.tab&&i.tab(s[r],e),"function"==typeof l&&l(e)},end:function(){a.end=!0,h(document).off("keyup",a.keyup)}},i))},u=function(){m.close(a.loadi),m.msg("当前图片地址异常
是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){1',t.bar1?'
  • '+l[0]+"
  • ":"",t.bar2?'
  • '+l[1]+"
  • ":"",'
  • '+l[2]+"
  • ",""].join("")),c=l.find("."+o),g=function(){a.scrollTop()>=t.showHeight?e||(c.show(),e=1):e&&(c.hide(),e=0)};u("."+n)[0]||("object"==typeof t.css&&l.css(t.css),r.append(l),g(),l.find("li").on("click",function(){var e=u(this).attr("lay-type");"top"===e&&u("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,e)}),a.on("scroll",function(){clearTimeout(i),i=setTimeout(function(){g()},100)}))},countdown:function(e,t,i){var n=this,o="function"==typeof t,a=new Date(e).getTime(),r=new Date(!t||o?(new Date).getTime():t).getTime(),a=a-r,l=[Math.floor(a/864e5),Math.floor(a/36e5)%24,Math.floor(a/6e4)%60,Math.floor(a/1e3)%60],o=(o&&(i=t),setTimeout(function(){n.countdown(e,r+1e3,i)},1e3));return i&&i(0]|&(?=#[a-zA-Z0-9]+)/g.test(e+="")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):e},unescape:function(e){return e!==undefined&&null!==e||(e=""),(e+="").replace(/\&/g,"&").replace(/\</g,"<").replace(/\>/g,">").replace(/\'/g,"'").replace(/\"/g,'"')},toVisibleArea:function(e){var t,i,n,o,a,r,l,c;(e=u.extend({margin:160,duration:200,type:"y"},e)).scrollElem[0]&&e.thisElem[0]&&(t=e.scrollElem,l=e.thisElem,n=(a="y"===e.type)?"top":"left",o=t[i=a?"scrollTop":"scrollLeft"](),a=t[a?"height":"width"](),r=t.offset()[n],c={},((l=l.offset()[n]-r)>a-e.margin||l."+y,k=function(e){var i=this;i.index=++c.index,i.config=s.extend({},i.config,c.config,e),i.init()};k.prototype.config={trigger:"click",content:"",className:"",style:"",show:!1,isAllowSpread:!0,isSpreadItem:!0,data:[],delay:300},k.prototype.reload=function(e){var i=this;i.config=s.extend({},i.config,e),i.init(!0)},k.prototype.init=function(e){var i=this,t=i.config,n=t.elem=s(t.elem);return 1",(t="href"in i?''+l+"":l,n?'
    '+t+("parent"===o?'':"group"===o&&u.isAllowSpread?'':"")+"
    ":'
    '+t+"
    "),""].join(""))).data("item",i),n&&(a=s('
    '),t=s("
      "),"parent"===o?(a.append(d(t,i.child)),l.append(a)):l.append(d(t,i.child))),r.append(l))}),r},t=['
      ',"
      "].join("");!(e="contextmenu"!==u.trigger&&!lay.isTopElem(u.elem[0])?e:!0)&&u.elem.data(r+"_opened")||(n.elemView=s(t),n.elemView.append(u.content||(e=s('
        '),0no menu'),e)),u.className&&n.elemView.addClass(u.className),u.style&&n.elemView.attr("style",u.style),c.thisId=u.id,n.remove(),i.append(n.elemView),u.elem.data(r+"_opened",!0),n.position(),(p.prevElem=n.elemView).data("prevElem",u.elem),n.elemView.find(".layui-menu").on(l,function(e){layui.stope(e)}),n.elemView.find(".layui-menu li").on("click",function(e){var i=s(this),t=i.data("item")||{};t.child&&0n.width()&&(t.addClass(C),(i=t[0].getBoundingClientRect()).left<0&&t.removeClass(C)),i.bottom>n.height()&&t.eq(0).css("margin-top",-(i.bottom-n.height()+5)))}).on("mouseleave",t,function(e){var i=s(this).children("."+w);i.removeClass(C),i.css("margin-top",0)}),c.reload=function(e,i){e=p.getThis(e);return e?(e.reload(i),p.call(e)):this},c.render=function(e){e=new k(e);return p.call(e)},e(o,c)});layui.define("jquery",function(e){"use strict";var h=layui.$,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var i=this;return i.config=h.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,a,e,i)}},a="slider",c="layui-disabled",y="layui-slider-bar",g="layui-slider-wrap",b="layui-slider-wrap-btn",x="layui-slider-tips",T="layui-slider-input-txt",w="layui-slider-hover",i=function(e){var i=this;i.index=++t.index,i.config=h.extend({},i.config,t.config,e),i.render()};i.prototype.config={type:"default",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:"#009688"},i.prototype.render=function(){var a,n=this,l=n.config,e=(l.step<1&&(l.step=1),l.maxl.min?i:l.min,l.value[1]=s>l.min?s:l.min,l.value[0]=l.value[0]>l.max?l.max:l.value[0],l.value[1]=l.value[1]>l.max?l.max:l.value[1],i=Math.floor((l.value[0]-l.min)/(l.max-l.min)*100),t=(s=Math.floor((l.value[1]-l.min)/(l.max-l.min)*100))-i+"%",i+="%",s+="%"):("object"==typeof l.value&&(l.value=Math.min.apply(null,l.value)),l.valuel.max&&(l.value=l.max),t=Math.floor((l.value-l.min)/(l.max-l.min)*100)+"%"),l.disabled?"#c2c2c2":l.theme),i='
        '+(l.tips?'
        ':"")+'
        '+(l.range?'
        ':"")+"
        ",t=h(l.elem),s=t.next(".layui-slider");if(s[0]&&s.remove(),n.elemTemp=h(i),l.range?(n.elemTemp.find("."+g).eq(0).data("value",l.value[0]),n.elemTemp.find("."+g).eq(1).data("value",l.value[1])):n.elemTemp.find("."+g).data("value",l.value),t.html(n.elemTemp),"vertical"===l.type&&n.elemTemp.height(l.height+"px"),l.showstep){for(var o=(l.max-l.min)/l.step,r="",u=1;u<1+o;u++){var d=100*u/o;d<100&&(r+='
        ')}n.elemTemp.append(r)}l.input&&!l.range&&(e=h('
        '),t.css("position","relative"),t.append(e),t.find("."+T).children("input").val(l.value),"vertical"===l.type?e.css({left:0,top:-48}):n.elemTemp.css("margin-right",e.outerWidth()+15)),l.disabled?(n.elemTemp.addClass(c),n.elemTemp.find("."+b).addClass(c)):n.slide(),n.elemTemp.find("."+b).on("mouseover",function(){var e="vertical"===l.type?l.height:n.elemTemp[0].offsetWidth,i=n.elemTemp.find("."+g),t=("vertical"===l.type?e-h(this).parent()[0].offsetTop-i.height():h(this).parent()[0].offsetLeft)/e*100,i=h(this).parent().data("value"),e=l.setTips?l.setTips(i):i;n.elemTemp.find("."+x).html(e),clearTimeout(a),a=setTimeout(function(){"vertical"===l.type?n.elemTemp.find("."+x).css({bottom:t+"%","margin-bottom":"20px",display:"inline-block"}):n.elemTemp.find("."+x).css({left:t+"%",display:"inline-block"})},300)}).on("mouseout",function(){clearTimeout(a),n.elemTemp.find("."+x).css("display","none")})},i.prototype.slide=function(e,i,t){var o=this.config,r=this.elemTemp,u=function(){return"vertical"===o.type?o.height:r[0].offsetWidth},d=r.find("."+g),s=r.next(".layui-slider-input"),c=s.children("."+T).children("input").val(),m=100/((o.max-o.min)/Math.ceil(o.step)),v=function(e,i){e=100<(e=100t[1]&&t.reverse(),o.change&&o.change(o.range?t:n)},p=function(e){var i=e/u()*100/m,t=Math.round(i)*m;return t=e==u()?Math.ceil(i)*m:t},f=h(['
        u()?u():i)/u()*100/m;v(i,l),s.addClass(w),r.find("."+x).show(),e.preventDefault()},i=function(){s.removeClass(w),r.find("."+x).hide()},t=function(){i&&i(),f.remove()},h("#LAY-slider-moving")[0]||h("body").append(f),f.on("mousemove",e),f.on("mouseup",t).on("mouseleave",t)})}),r.on("click",function(e){var i=h("."+b),t=h(this);!i.is(event.target)&&0===i.has(event.target).length&&i.length&&(t=(i=(i=(i="vertical"===o.type?u()-e.clientY+t.offset().top-h(window).scrollTop():e.clientX-t.offset().left-h(window).scrollLeft())<0?0:i)>u()?u():i)/u()*100/m,i=o.range?"vertical"===o.type?Math.abs(i-parseInt(h(d[0]).css("bottom")))>Math.abs(i-parseInt(h(d[1]).css("bottom")))?1:0:Math.abs(i-d[0].offsetLeft)>Math.abs(i-d[1].offsetLeft)?1:0:0,v(t,i),e.preventDefault())}),s.children(".layui-slider-input-btn").children("i").each(function(i){h(this).on("click",function(){c=s.children("."+T).children("input").val();var e=((c=1==i?c-o.stepo.max?o.max:Number(c)+o.step)-o.min)/(o.max-o.min)*100/m;v(e,0)})});var a=function(){var e=this.value,e=(e=(e=(e=isNaN(e)?0:e)o.max?o.max:e,((this.value=e)-o.min)/(o.max-o.min)*100/m);v(e,0)};s.children("."+T).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),a.call(this))}).on("change",a)},i.prototype.events=function(){this.config},t.render=function(e){e=new i(e);return function(){var t=this,a=t.config;return{setValue:function(e,i){return a.value=e,t.slide("set",e,i||0)},config:a}}.call(e)},e(a,t)});layui.define(["jquery","lay"],function(e){"use strict";var k=layui.jquery,n=layui.lay,r=layui.device().mobile?"click":"mousedown",l={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var i=this;return i.config=k.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,"colorpicker",e,i)}},t="layui-colorpicker",c=".layui-colorpicker-main",y="layui-icon-down",x="layui-icon-close",P="layui-colorpicker-trigger-span",C="layui-colorpicker-trigger-i",B="layui-colorpicker-side-slider",w="layui-colorpicker-basis",D="layui-colorpicker-alpha-bgcolor",j="layui-colorpicker-alpha-slider",E="layui-colorpicker-basis-cursor",F="layui-colorpicker-main-input",H=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),n=r-o;return i.b=r,i.s=0!=r?255*n/r:0,0!=i.s?e.r==r?i.h=(e.g-e.b)/n:e.g==r?i.h=2+(e.b-e.r)/n:i.h=4+(e.r-e.g)/n:i.h=-1,r==o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},M=function(e){var i,o={},r=e.h,n=255*e.s/100,e=255*e.b/100;return 0==n?o.r=o.g=o.b=e:(e=r%60*((i=e)-(n=(255-n)*e/255))/60,(r=360==r?0:r)<60?(o.r=i,o.b=n,o.g=n+e):r<120?(o.g=i,o.b=n,o.r=i-e):r<180?(o.g=i,o.r=n,o.b=n+e):r<240?(o.b=i,o.r=n,o.g=i-e):r<300?(o.b=i,o.g=n,o.r=n+e):r<360?(o.r=i,o.g=n,o.b=i-e):(o.r=0,o.g=0,o.b=0)),{r:Math.round(o.r),g:Math.round(o.g),b:Math.round(o.b)}},f=function(e){var e=M(e),o=[e.r.toString(16),e.g.toString(16),e.b.toString(16)];return k.each(o,function(e,i){1==i.length&&(o[e]="0"+i)}),o.join("")},Y=function(e){e=e.match(/[0-9]{1,3}/g)||[];return{r:e[0],g:e[1],b:e[2]}},I=k(window),a=k(document),s=function(e){this.index=++l.index,this.config=k.extend({},this.config,l.config,e),this.render()};s.prototype.config={color:"",size:null,alpha:!1,format:"hex",predefine:!1,colors:["#009688","#5FB878","#1E9FFF","#FF5722","#FFB800","#01AAED","#999","#c00","#ff8c00","#ffd700","#90ee90","#00ced1","#1e90ff","#c71585","rgb(0, 186, 189)","rgb(255, 120, 0)","rgb(250, 212, 0)","#393D49","rgba(0,0,0,.5)","rgba(255, 69, 0, 0.68)","rgba(144, 240, 144, 0.5)","rgba(31, 147, 255, 0.73)"]},s.prototype.render=function(){var e=this,i=e.config,o=k(i.elem);if(1',"",'','',"","","
        "].join("")),r=i.elem=k(i.elem);i.size&&o.addClass("layui-colorpicker-"+i.size),r.addClass("layui-inline").html(e.elemColorBox=o),e.color=e.elemColorBox.find("."+P)[0].style.background,e.events()},s.prototype.renderPicker=function(){var o,e=this,i=e.config,r=e.elemColorBox[0],i=e.elemPicker=k(['
        ','
        ','
        ','
        ','
        ','
        ',"
        ",'
        ','
        ',"
        ","
        ",'
        ','
        ','
        ',"
        ","
        ",i.predefine?(o=['
        '],layui.each(i.colors,function(e,i){o.push(['
        ','
        ',"
        "].join(""))}),o.push("
        "),o.join("")):"",'
        ','
        ','',"
        ",'
        ','','',"","
        "].join(""));e.elemColorBox.find("."+P)[0];k(c)[0]&&k(c).data("index")==e.index?e.removePicker(s.thisElemInd):(e.removePicker(s.thisElemInd),k("body").append(i)),s.thisElemInd=e.index,s.thisColor=r.style.background,e.position(),e.pickerEvents()},s.prototype.removePicker=function(e){this.config;return k("#layui-colorpicker"+(e||this.index)).remove(),this},s.prototype.position=function(){var e=this,i=e.config;return n.position(e.bindElem||e.elemColorBox[0],e.elemPicker[0],{position:i.position,align:"center"}),e},s.prototype.val=function(){var e,i=this,o=(i.config,i.elemColorBox.find("."+P)),r=i.elemPicker.find("."+F),n=o[0].style.backgroundColor;n?(e=H(Y(n)),o=o.attr("lay-type"),i.select(e.h,e.s,e.b),"torgb"===o&&r.find("input").val(n),"rgba"===o&&(e=Y(n),3==(n.match(/[0-9]{1,3}/g)||[]).length?(r.find("input").val("rgba("+e.r+", "+e.g+", "+e.b+", 1)"),i.elemPicker.find("."+j).css("left",280)):(r.find("input").val(n),o=280*n.slice(n.lastIndexOf(",")+1,n.length-1),i.elemPicker.find("."+j).css("left",o)),i.elemPicker.find("."+D)[0].style.background="linear-gradient(to right, rgba("+e.r+", "+e.g+", "+e.b+", 0), rgb("+e.r+", "+e.g+", "+e.b+"))")):(i.select(0,100,100),r.find("input").val(""),i.elemPicker.find("."+D)[0].style.background="",i.elemPicker.find("."+j).css("left",280))},s.prototype.side=function(){var n=this,l=n.config,t=n.elemColorBox.find("."+P),c=t.attr("lay-type"),a=n.elemPicker.find(".layui-colorpicker-side"),e=n.elemPicker.find("."+B),s=n.elemPicker.find("."+w),r=n.elemPicker.find("."+E),d=n.elemPicker.find("."+D),f=n.elemPicker.find("."+j),u=e[0].offsetTop/180*360,p=100-(r[0].offsetTop+3)/180*100,g=(r[0].offsetLeft+3)/260*100,h=Math.round(f[0].offsetLeft/280*100)/100,v=n.elemColorBox.find("."+C),i=n.elemPicker.find(".layui-colorpicker-pre").children("div"),b=function(e,i,o,r){n.select(e,i,o);e=M({h:e,s:i,b:o});v.addClass(y).removeClass(x),t[0].style.background="rgb("+e.r+", "+e.g+", "+e.b+")","torgb"===c&&n.elemPicker.find("."+F).find("input").val("rgb("+e.r+", "+e.g+", "+e.b+")"),"rgba"===c&&(f.css("left",280*r),n.elemPicker.find("."+F).find("input").val("rgba("+e.r+", "+e.g+", "+e.b+", "+r+")"),t[0].style.background="rgba("+e.r+", "+e.g+", "+e.b+", "+r+")",d[0].style.background="linear-gradient(to right, rgba("+e.r+", "+e.g+", "+e.b+", 0), rgb("+e.r+", "+e.g+", "+e.b+"))"),l.change&&l.change(n.elemPicker.find("."+F).find("input").val())},o=k(['
        '].join("")),m=function(e){k("#LAY-colorpicker-moving")[0]||k("body").append(o),o.on("mousemove",e),o.on("mouseup",function(){o.remove()}).on("mouseleave",function(){o.remove()})};e.on("mousedown",function(e){var r=this.offsetTop,n=e.clientY;m(function(e){var i=r+(e.clientY-n),o=a[0].offsetHeight,o=(i=o<(i=i<0?0:i)?o:i)/180*360;b(u=o,g,p,h),e.preventDefault()}),e.preventDefault()}),a.on("click",function(e){var i=e.clientY-k(this).offset().top,i=(i=(i=i<0?0:i)>this.offsetHeight?this.offsetHeight:i)/180*360;b(u=i,g,p,h),e.preventDefault()}),r.on("mousedown",function(e){var l=this.offsetTop,t=this.offsetLeft,c=e.clientY,a=e.clientX;layui.stope(e),m(function(e){var i=l+(e.clientY-c),o=t+(e.clientX-a),r=s[0].offsetHeight-3,n=s[0].offsetWidth-3,n=((o=n<(o=o<-3?-3:o)?n:o)+3)/260*100,o=100-((i=r<(i=i<-3?-3:i)?r:i)+3)/180*100;b(u,g=n,p=o,h),e.preventDefault()}),e.preventDefault()}),s.on("mousedown",function(e){var i=e.clientY-k(this).offset().top-3+I.scrollTop(),o=e.clientX-k(this).offset().left-3+I.scrollLeft(),o=((i=i<-3?-3:i)>this.offsetHeight-3&&(i=this.offsetHeight-3),((o=(o=o<-3?-3:o)>this.offsetWidth-3?this.offsetWidth-3:o)+3)/260*100),i=100-(i+3)/180*100;b(u,g=o,p=i,h),layui.stope(e),e.preventDefault(),r.trigger(e,"mousedown")}),f.on("mousedown",function(e){var r=this.offsetLeft,n=e.clientX;m(function(e){var i=r+(e.clientX-n),o=d[0].offsetWidth,o=(o<(i=i<0?0:i)&&(i=o),Math.round(i/280*100)/100);b(u,g,p,h=o),e.preventDefault()}),e.preventDefault()}),d.on("click",function(e){var i=e.clientX-k(this).offset().left,i=((i=i<0?0:i)>this.offsetWidth&&(i=this.offsetWidth),Math.round(i/280*100)/100);b(u,g,p,h=i),e.preventDefault()}),i.each(function(){k(this).on("click",function(){k(this).parent(".layui-colorpicker-pre").addClass("selected").siblings().removeClass("selected");var e=this.style.backgroundColor,i=H(Y(e)),o=e.slice(e.lastIndexOf(",")+1,e.length-1);u=i.h,g=i.s,p=i.b,3==(e.match(/[0-9]{1,3}/g)||[]).length&&(o=1),h=o,b(i.h,i.s,i.b,o)})})},s.prototype.select=function(e,i,o,r){var n=this,l=(n.config,f({h:e,s:100,b:100})),t=f({h:e,s:i,b:o}),e=e/360*180,o=180-o/100*180-3,i=i/100*260-3;n.elemPicker.find("."+B).css("top",e),n.elemPicker.find("."+w)[0].style.background="#"+l,n.elemPicker.find("."+E).css({top:o,left:i}),"change"!==r&&n.elemPicker.find("."+F).find("input").val("#"+t)},s.prototype.pickerEvents=function(){var c=this,a=c.config,s=c.elemColorBox.find("."+P),d=c.elemPicker.find("."+F+" input"),o={clear:function(e){s[0].style.background="",c.elemColorBox.find("."+C).removeClass(y).addClass(x),c.color="",a.done&&a.done(""),c.removePicker()},confirm:function(e,i){var o,r,n=d.val(),l=n,t={};if(-1>16,g:(65280&o)>>8,b:255&o},t=H(r),s[0].style.background=l="#"+f(t),c.elemColorBox.find("."+C).removeClass(x).addClass(y)),"change"===i)return c.select(t.h,t.s,t.b,i),void(a.change&&a.change(l));c.color=n,a.done&&a.done(n),c.removePicker()}};c.elemPicker.on("click","*[colorpicker-events]",function(){var e=k(this),i=e.attr("colorpicker-events");o[i]&&o[i].call(this,e)}),d.on("keyup",function(e){var i=k(this);o.confirm.call(this,i,13===e.keyCode?null:"change")})},s.prototype.events=function(){var i=this,e=i.config,o=i.elemColorBox.find("."+P);i.elemColorBox.on("click",function(){i.renderPicker(),k(c)[0]&&(i.val(),i.side())}),e.elem[0]&&!i.elemColorBox[0].eventHandler&&(a.on(r,function(e){k(e.target).hasClass(t)||k(e.target).parents("."+t)[0]||k(e.target).hasClass(c.replace(/\./g,""))||k(e.target).parents(c)[0]||i.elemPicker&&(i.color?(e=H(Y(i.color)),i.select(e.h,e.s,e.b)):i.elemColorBox.find("."+C).removeClass(y).addClass(x),o[0].style.background=i.color||"",i.removePicker())}),I.on("resize",function(){if(!i.elemPicker||!k(c)[0])return!1;i.position()}),i.elemColorBox[0].eventHandler=!0)},l.render=function(e){e=new s(e);return function(){return{config:this.config}}.call(e)},e("colorpicker",l)});layui.define("jquery",function(t){"use strict";var u=layui.$,d=(layui.hint(),layui.device()),c="element",r="layui-this",y="layui-show",i=function(){this.config={}},h=(i.prototype.set=function(t){return u.extend(!0,this.config,t),this},i.prototype.on=function(t,i){return layui.onevent.call(this,c,t,i)},i.prototype.tabAdd=function(t,i){var a,t=u(".layui-tab[lay-filter="+t+"]"),e=t.children(".layui-tab-title"),l=e.children(".layui-tab-bar"),t=t.children(".layui-tab-content"),n=""+(i.title||"unnaming")+"";return l[0]?l.before(n):e.append(n),t.append('
        '+(i.content||"")+"
        "),C.hideTabMore(!0),C.tabAuto(),this},i.prototype.tabDelete=function(t,i){t=u(".layui-tab[lay-filter="+t+"]").children(".layui-tab-title").find('>li[lay-id="'+i+'"]');return C.tabDelete(null,t),this},i.prototype.tabChange=function(t,i){t=u(".layui-tab[lay-filter="+t+"]").children(".layui-tab-title").find('>li[lay-id="'+i+'"]');return C.tabClick.call(t[0],null,null,t),this},i.prototype.tab=function(a){a=a||{},e.on("click",a.headerElem,function(t){var i=u(this).index();C.tabClick.call(this,t,i,null,a)})},i.prototype.progress=function(t,i){var a="layui-progress",t=u("."+a+"[lay-filter="+t+"]").find("."+a+"-bar"),a=t.find("."+a+"-text");return t.css("width",i).attr("lay-percent",i),a.text(i),this},".layui-nav"),f="layui-nav-item",l="layui-nav-bar",p="layui-nav-tree",b="layui-nav-child",v="layui-nav-more",m="layui-anim layui-anim-upbit",C={tabClick:function(t,i,a,e){e=e||{};var a=a||u(this),i=i||a.parent().children("li").index(a),l=e.headerElem?a.parent():a.parents(".layui-tab").eq(0),e=e.bodyElem?u(e.bodyElem):l.children(".layui-tab-content").children(".layui-tab-item"),n=a.find("a"),n="javascript:;"!==n.attr("href")&&"_blank"===n.attr("target"),s="string"==typeof a.attr("lay-unselect"),o=l.attr("lay-filter");n||s||(a.addClass(r).siblings().removeClass(r),e.eq(i).addClass(y).siblings().removeClass(y)),layui.event.call(this,c,"tab("+o+")",{elem:l,index:i})},tabDelete:function(t,i){var i=i||u(this).parent(),a=i.index(),e=i.parents(".layui-tab").eq(0),l=e.children(".layui-tab-content").children(".layui-tab-item"),n=e.attr("lay-filter");i.hasClass(r)&&(i.next()[0]&&i.next().is("li")?C.tabClick.call(i.next()[0],null,a+1):i.prev()[0]&&i.prev().is("li")&&C.tabClick.call(i.prev()[0],null,a-1)),i.remove(),l.eq(a).remove(),setTimeout(function(){C.tabAuto()},50),layui.event.call(this,c,"tabDelete("+n+")",{elem:e,index:a})},tabAuto:function(){var e="layui-tab-bar",l="layui-tab-close",n=this;u(".layui-tab").each(function(){var t=u(this),i=t.children(".layui-tab-title"),a=(t.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),a=u('');n===window&&8!=d.ie&&C.hideTabMore(!0),t.attr("lay-allowClose")&&i.find("li").each(function(){var t,i=u(this);i.find("."+l)[0]||((t=u('')).on("click",C.tabDelete),i.append(t))}),"string"!=typeof t.attr("lay-unauto")&&(i.prop("scrollWidth")>i.outerWidth()+1?i.find("."+e)[0]||(i.append(a),t.attr("overflow",""),a.on("click",function(t){i[this.title?"removeClass":"addClass"]("layui-tab-more"),this.title=this.title?"":"\u6536\u7f29"})):(i.find("."+e).remove(),t.removeAttr("overflow")))})},hideTabMore:function(t){var i=u(".layui-tab-title");!0!==t&&"tabmore"===u(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=u(this),i=t.parents(h),a=i.attr("lay-filter"),e=t.parent(),l=t.siblings("."+b),n="string"==typeof e.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||n||l[0]||(i.find("."+r).removeClass(r),e.addClass(r)),i.hasClass(p)&&(l.removeClass(m),l[0]&&(e["none"===l.css("display")?"addClass":"removeClass"](f+"ed"),"all"===i.attr("lay-shrink")&&e.siblings().removeClass(f+"ed"))),layui.event.call(this,c,"nav("+a+")",t)},collapse:function(){var t=u(this),i=t.find(".layui-colla-icon"),a=t.siblings(".layui-colla-content"),e=t.parents(".layui-collapse").eq(0),l=e.attr("lay-filter"),n="none"===a.css("display");"string"==typeof e.attr("lay-accordion")&&((e=e.children(".layui-colla-item").children("."+y)).siblings(".layui-colla-title").children(".layui-colla-icon").html(""),e.removeClass(y)),a[n?"addClass":"removeClass"](y),i.html(n?"":""),layui.event.call(this,c,"collapse("+l+")",{title:t,content:a,show:n})}},a=(i.prototype.render=i.prototype.init=function(t,i){var a=i?'[lay-filter="'+i+'"]':"",i={tab:function(){C.tabAuto.call({})},nav:function(){var s={},o={},c={},r="layui-nav-title";u(h+a).each(function(t){var i=u(this),a=u(''),e=i.find("."+f);i.find("."+l)[0]||(i.append(a),(i.hasClass(p)?e.find("dd,>."+r):e).on("mouseenter",function(){!function(t,i,a){var e,l=u(this),n=l.find("."+b);i.hasClass(p)?n[0]||(e=l.children("."+r),t.css({top:l.offset().top-i.offset().top,height:(e[0]?e:l).outerHeight(),opacity:1})):(n.addClass(m),n.hasClass("layui-nav-child-c")&&n.css({left:-(n.outerWidth()-l.width())/2}),n[0]?t.css({left:t.position().left+t.width()/2,width:0,opacity:0}):t.css({left:l.position().left+parseFloat(l.css("marginLeft")),top:l.position().top+l.height()-t.height()}),s[a]=setTimeout(function(){t.css({width:n[0]?0:l.width(),opacity:n[0]?0:1})},d.ie&&d.ie<10?0:200),clearTimeout(c[a]),"block"===n.css("display")&&clearTimeout(o[a]),o[a]=setTimeout(function(){n.addClass(y),l.find("."+v).addClass(v+"d")},300))}.call(this,a,i,t)}).on("mouseleave",function(){i.hasClass(p)?a.css({height:0,opacity:0}):(clearTimeout(o[t]),o[t]=setTimeout(function(){i.find("."+b).removeClass(y),i.find("."+v).removeClass(v+"d")},300))}),i.on("mouseleave",function(){clearTimeout(s[t]),c[t]=setTimeout(function(){i.hasClass(p)||a.css({width:0,left:a.position().left+a.width()/2,opacity:0})},200)})),e.find("a").each(function(){var t=u(this);t.parent();t.siblings("."+b)[0]&&!t.children("."+v)[0]&&t.append(''),t.off("click",C.clickThis).on("click",C.clickThis)})})},breadcrumb:function(){u(".layui-breadcrumb"+a).each(function(){var t=u(this),i="lay-separator",a=t.attr(i)||"/",e=t.find("a");e.next("span["+i+"]")[0]||(e.each(function(t){t!==e.length-1&&u(this).after(""+a+"")}),t.css("visibility","visible"))})},progress:function(){var e="layui-progress";u("."+e+a).each(function(){var t=u(this),i=t.find(".layui-progress-bar"),a=i.attr("lay-percent");i.css("width",/^.+\/.+$/.test(a)?100*new Function("return "+a)()+"%":a),t.attr("lay-showPercent")&&setTimeout(function(){i.html(''+a+"")},350)})},collapse:function(){u(".layui-collapse"+a).each(function(){u(this).find(".layui-colla-item").each(function(){var t=u(this),i=t.find(".layui-colla-title"),t="none"===t.find(".layui-colla-content").css("display");i.find(".layui-colla-icon").remove(),i.append(''+(t?"":"")+""),i.off("click",C.collapse).on("click",C.collapse)})})}};return i[t]?i[t]():layui.each(i,function(t,i){i()})},new i),e=u(document);u(function(){a.render()});e.on("click",".layui-tab-title li",C.tabClick),e.on("click",C.hideTabMore),u(window).on("resize",C.tabAuto),t(c,a)});layui.define("layer",function(e){"use strict";var v=layui.$,t=layui.layer,r=layui.hint(),y=layui.device(),i={config:{},set:function(e){var t=this;return t.config=v.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,n,e,t)}},n="upload",o="layui-upload-file",a="layui-upload-form",F="layui-upload-iframe",b="layui-upload-choose",x=function(e){var t=this;t.config=v.extend({},t.config,i.config,e),t.render()};x.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",force:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1},x.prototype.render=function(e){var t=this;(e=t.config).elem=v(e.elem),e.bindAction=v(e.bindAction),t.file(),t.events()},x.prototype.file=function(){var e=this,t=e.config,i=e.elemFile=v(['"].join("")),n=t.elem.next();(n.hasClass(o)||n.hasClass(a))&&n.remove(),y.ie&&y.ie<10&&t.elem.wrap('
        '),e.isFile()?(e.elemFile=t.elem,t.field=t.elem[0].name):t.elem.after(i),y.ie&&y.ie<10&&e.initIE()},x.prototype.initIE=function(){var i,e=this.config,t=v(''),n=v(['
        ',"
        "].join(""));v("#"+F)[0]||v("body").append(t),e.elem.next().hasClass(a)||(this.elemFile.wrap(n),e.elem.next("."+a).append((i=[],layui.each(e.data,function(e,t){t="function"==typeof t?t():t,i.push('')}),i.join(""))))},x.prototype.msg=function(e){return t.msg(e,{icon:2,shift:6})},x.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},x.prototype.preview=function(n){window.FileReader&&layui.each(this.chooseFiles,function(e,t){var i=new FileReader;i.readAsDataURL(t),i.onload=function(){n&&n(e,t,this.result)}})},x.prototype.upload=function(i,e){var n,o,t,a,l=this,r=l.config,u=l.elemFile[0],c=function(){var t=0,o=0,e=i||l.files||l.chooseFiles||u.files,a=function(){r.multiple&&t+o===l.fileLength&&"function"==typeof r.allDone&&r.allDone({total:l.fileLength,successful:t,failed:o})};layui.each(e,function(i,e){var n=new FormData,e=(n.append(r.field,e),layui.each(r.data,function(e,t){t="function"==typeof t?t():t,n.append(e,t)}),{url:r.url,type:"post",data:n,contentType:!1,processData:!1,dataType:"json",headers:r.headers||{},success:function(e){t++,f(i,e),a()},error:function(e){o++,l.msg("Request URL is abnormal: "+(e.statusText||"error")),p(i),a()}});"function"==typeof r.progress&&(e.xhr=function(){var e=v.ajaxSettings.xhr();return e.upload.addEventListener("progress",function(e){var t;e.lengthComputable&&(t=Math.floor(e.loaded/e.total*100),r.progress(t,(r.item||r.elem)[0],e,i))}),e}),v.ajax(e)})},s=function(){var n=v("#"+F);l.elemFile.parent().submit(),clearInterval(x.timer),x.timer=setInterval(function(){var e,t=n.contents().find("body");try{e=t.text()}catch(i){l.msg("Cross-domain requests are not supported"),clearInterval(x.timer),p()}e&&(clearInterval(x.timer),t.html(""),f(0,e))},30)},f=function(e,t){if(l.elemFile.next("."+b).remove(),u.value="","json"===r.force&&"object"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},l.msg("Please return JSON data format")}"function"==typeof r.done&&r.done(t,e||0,function(e){l.upload(e)})},p=function(e){r.auto&&(u.value=""),"function"==typeof r.error&&r.error(e||0,function(e){l.upload(e)})},d=r.exts,m=(o=[],layui.each(i||l.chooseFiles,function(e,t){o.push(t.name)}),o),h={preview:function(e){l.preview(e)},upload:function(e,t){var i={};i[e]=t,l.upload(i)},pushFile:function(){return l.files=l.files||{},layui.each(l.chooseFiles,function(e,t){l.files[e]=t}),l.files},resetFile:function(e,t,i){t=new File([t],i);l.files=l.files||{},l.files[e]=t}},g={file:"\u6587\u4ef6",images:"\u56fe\u7247",video:"\u89c6\u9891",audio:"\u97f3\u9891"}[r.accept]||"\u6587\u4ef6",m=0===m.length?u.value.match(/[^\/\\]+\..+/g)||[]||"":m;if(0!==m.length){switch(r.accept){case"file":layui.each(m,function(e,t){if(d&&!RegExp(".\\.("+d+")$","i").test(escape(t)))return n=!0});break;case"video":layui.each(m,function(e,t){if(!RegExp(".\\.("+(d||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(t)))return n=!0});break;case"audio":layui.each(m,function(e,t){if(!RegExp(".\\.("+(d||"mp3|wav|mid")+")$","i").test(escape(t)))return n=!0});break;default:layui.each(m,function(e,t){if(!RegExp(".\\.("+(d||"jpg|png|gif|bmp|jpeg")+")$","i").test(escape(t)))return n=!0})}if(n)return l.msg("\u9009\u62e9\u7684"+g+"\u4e2d\u5305\u542b\u4e0d\u652f\u6301\u7684\u683c\u5f0f"),u.value="";if("choose"!==e&&!r.auto||(r.choose&&r.choose(h),"choose"!==e)){if(l.fileLength=(t=0,g=i||l.files||l.chooseFiles||u.files,layui.each(g,function(){t++}),t),r.number&&l.fileLength>r.number)return l.msg("\u540c\u65f6\u6700\u591a\u53ea\u80fd\u4e0a\u4f20: "+r.number+" \u4e2a\u6587\u4ef6
        \u60a8\u5f53\u524d\u5df2\u7ecf\u9009\u62e9\u4e86: "+l.fileLength+" \u4e2a\u6587\u4ef6");if(01024*r.size&&(t=1<=(t=r.size/1024)?t.toFixed(2)+"MB":r.size+"KB",u.value="",a=t)}),a)return l.msg("\u6587\u4ef6\u5927\u5c0f\u4e0d\u80fd\u8d85\u8fc7 "+a);if(!r.before||!1!==r.before(h))y.ie?(9'+e+"")};o.elem.off("upload.start").on("upload.start",function(){var e=v(this),t=e.attr("lay-data");if(t)try{t=new Function("return "+t)(),n.config=v.extend({},o,t)}catch(i){r.error("Upload element property lay-data configuration item has a syntax error: "+t)}n.config.item=e,n.elemFile[0].click()}),y.ie&&y.ie<10||o.elem.off("upload.over").on("upload.over",function(){v(this).attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){v(this).removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(e,t){var i=v(this),t=t.originalEvent.dataTransfer.files||[];i.removeAttr("lay-over"),a(t),o.auto?n.upload():l(t)}),n.elemFile.off("upload.change").on("upload.change",function(){var e=this.files||[];a(e),o.auto?n.upload():l(e)}),o.bindAction.off("upload.action").on("upload.action",function(){n.upload()}),o.elem.data("haveEvents")||(n.elemFile.on("change",function(){v(this).trigger("upload.change")}),o.elem.on("click",function(){n.isFile()||v(this).trigger("upload.start")}),o.drag&&o.elem.on("dragover",function(e){e.preventDefault(),v(this).trigger("upload.over")}).on("dragleave",function(e){v(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),v(this).trigger("upload.drop",e)}),o.bindAction.on("click",function(){v(this).trigger("upload.action")}),o.elem.data("haveEvents",!0))},i.render=function(e){e=new x(e);return function(){var t=this;return{upload:function(e){t.upload.call(t,e)},reload:function(e){t.reload.call(t,e)},config:t.config}}.call(e)},e(n,i)});layui.define(["layer","util"],function(e){"use strict";var C=layui.$,h=layui.layer,d=layui.util,l=layui.hint(),w=(layui.device(),"form"),o=".layui-form",T="layui-this",$="layui-hide",E="layui-disabled",t=function(){this.config={verify:{required:[/[\S]+/,"\u5fc5\u586b\u9879\u4e0d\u80fd\u4e3a\u7a7a"],phone:[/^1\d{10}$/,"\u8bf7\u8f93\u5165\u6b63\u786e\u7684\u624b\u673a\u53f7"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"\u90ae\u7bb1\u683c\u5f0f\u4e0d\u6b63\u786e"],url:[/^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/,"\u94fe\u63a5\u683c\u5f0f\u4e0d\u6b63\u786e"],number:function(e){if(!e||isNaN(e))return"\u53ea\u80fd\u586b\u5199\u6570\u5b57"},date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"\u65e5\u671f\u683c\u5f0f\u4e0d\u6b63\u786e"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"\u8bf7\u8f93\u5165\u6b63\u786e\u7684\u8eab\u4efd\u8bc1\u53f7"]},autocomplete:null}},i=(t.prototype.set=function(e){return C.extend(!0,this.config,e),this},t.prototype.verify=function(e){return C.extend(!0,this.config.verify,e),this},t.prototype.getFormElem=function(e){return C(o+(e?'[lay-filter="'+e+'"]':""))},t.prototype.on=function(e,t){return layui.onevent.call(this,w,e,t)},t.prototype.val=function(e,i){return this.getFormElem(e).each(function(e,t){var a=C(this);layui.each(i,function(e,t){var i,e=a.find('[name="'+e+'"]');e[0]&&("checkbox"===(i=e[0].type)?e[0].checked=t:"radio"===i?e.each(function(){this.value==t&&(this.checked=!0)}):e.val(t))})}),r.render(null,e),this.getValue(e)},t.prototype.getValue=function(e,t){t=t||this.getFormElem(e);var a={},n={},e=t.find("input,select,textarea");return layui.each(e,function(e,t){var i;C(this);t.name=(t.name||"").replace(/^\s*|\s*&/,""),t.name&&(/^.*\[\]$/.test(t.name)&&(i=t.name.match(/^(.*)\[\]$/g)[0],a[i]=0|a[i],i=t.name.replace(/^(.*)\[\]$/,"$1["+a[i]+++"]")),/^checkbox|radio$/.test(t.type)&&!t.checked||(n[i||t.name]=t.value))}),n},t.prototype.render=function(e,t){var i=this.config,a=C(o+(t?'[lay-filter="'+t+'"]':"")),n={input:function(e){e=e||a.find("input,textarea");i.autocomplete&&e.attr("autocomplete",i.autocomplete)},select:function(e){var p,c="\u8bf7\u9009\u62e9",m="layui-form-select",g="layui-select-title",k="layui-select-none",x="",e=e||a.find("select"),b=function(e,t){C(e.target).parent().hasClass(g)&&!t||(C("."+m).removeClass(m+"ed "+m+"up"),p&&x&&p.val(x)),p=null},u=function(a,e,t){var s,r,i,n,o,l,c=C(this),u=a.find("."+g),d=u.find("input"),f=a.find("dl"),h=f.children("dd"),y=f.children("dt"),v=this.selectedIndex;e||(r=c.attr("lay-search"),i=function(){var e=a.offset().top+a.outerHeight()+5-q.scrollTop(),t=f.outerHeight();v=c[0].selectedIndex,a.addClass(m+"ed"),h.removeClass($),y.removeClass($),s=null,h.eq(v).addClass(T).siblings().removeClass(T),e+t>q.height()&&t<=e&&a.addClass(m+"up"),o()},n=function(e){a.removeClass(m+"ed "+m+"up"),d.blur(),s=null,e||l(d.val(),function(e){var t=c[0].selectedIndex;e&&(x=C(c[0].options[t]).html(),0===t&&x===d.attr("placeholder")&&(x=""),d.val(x||""))})},o=function(){var e,t,i=f.children("dd."+T);i[0]&&(e=i.position().top,t=f.height(),i=i.height(),t\u65e0\u5339\u914d\u9879

        '):f.find("."+k).remove()},"keyup"),""===t&&f.find("."+k).remove(),o()}).on("blur",function(e){var t=c[0].selectedIndex;p=d,x=C(c[0].options[t]).html(),0===t&&x===d.attr("placeholder")&&(x=""),setTimeout(function(){l(d.val(),function(e){x||d.val("")},"blur")},200)}),h.on("click",function(){var e=C(this),t=e.attr("lay-value"),i=c.attr("lay-filter");return e.hasClass(E)||(e.hasClass("layui-select-tips")?d.val(""):(d.val(e.text()),e.addClass(T)),e.siblings().removeClass(T),c.val(t).removeClass("layui-form-danger"),layui.event.call(this,w,"select("+i+")",{elem:c[0],value:t,othis:a}),n(!0)),!1}),a.find("dl>dt").on("click",function(e){return!1}),C(document).off("click",b).on("click",b))};e.each(function(e,t){var i=C(this),a=i.next("."+m),n=this.disabled,l=t.value,r=C(t.options[t.selectedIndex]),t=t.options[0];if("string"==typeof i.attr("lay-ignore"))return i.show();var s,o="string"==typeof i.attr("lay-search"),t=t&&!t.value&&t.innerHTML||c,r=C(['
        ','
        ','','
        ','
        ',(t=i.find("*"),s=[],layui.each(t,function(e,t){0!==e||t.value?"optgroup"===t.tagName.toLowerCase()?s.push("
        "+t.label+"
        "):s.push('
        '+C.trim(t.innerHTML)+"
        "):s.push('
        '+C.trim(t.innerHTML||c)+"
        ")}),0===s.length&&s.push('
        \u6ca1\u6709\u9009\u9879
        '),s.join("")+"
        "),"
        "].join(""));a[0]&&a.remove(),i.after(r),u.call(this,r,n,o)})},checkbox:function(e){var o={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},e=e||a.find("input[type=checkbox]");e.each(function(e,t){var i=C(this),a=i.attr("lay-skin"),n=(i.attr("lay-text")||"").split("|"),l=this.disabled,r=o[a="switch"===a?"_"+a:a]||o.checkbox;if("string"==typeof i.attr("lay-ignore"))return i.show();var s=i.next("."+r[0]),t=C(['
        ",(l={checkbox:[t.title.replace(/\s/g,"")?""+t.title+"":"",''].join(""),_switch:""+((t.checked?n[0]:n[1])||"")+""})[a]||l.checkbox,"
        "].join(""));s[0]&&s.remove(),i.after(t),function(i,a){var n=C(this);i.on("click",function(){var e=n.attr("lay-filter"),t=(n.attr("lay-text")||"").split("|");n[0].disabled||(n[0].checked?(n[0].checked=!1,i.removeClass(a[1]).find("em").text(t[1])):(n[0].checked=!0,i.addClass(a[1]).find("em").text(t[0])),layui.event.call(n[0],w,a[2]+"("+e+")",{elem:n[0],value:n[0].value,othis:i}))})}.call(this,t,r)})},radio:function(e){var r="layui-form-radio",s=["",""],e=e||a.find("input[type=radio]");e.each(function(e,t){var i=C(this),a=i.next("."+r),n=this.disabled;if("string"==typeof i.attr("lay-ignore"))return i.show();a[0]&&a.remove();n=C(['
        ',''+s[t.checked?0:1]+"","
        "+(a=t.title||"",a="string"==typeof i.next().attr("lay-radio")?i.next().html():a)+"
        ","
        "].join(""));i.after(n),function(a){var n=C(this),l="layui-anim-scaleSpring";a.on("click",function(){var e=n[0].name,t=n.parents(o),i=n.attr("lay-filter"),e=t.find("input[name="+e.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(e,function(){var e=C(this).next("."+r);this.checked=!1,e.removeClass(r+"ed"),e.find(".layui-icon").removeClass(l).html(s[1])}),n[0].checked=!0,a.addClass(r+"ed"),a.find(".layui-icon").addClass(l).html(s[0]),layui.event.call(n[0],w,"radio("+i+")",{elem:n[0],value:n[0].value,othis:a}))})}.call(this,n)})}};return"object"===layui.type(e)?e.each(function(e,t){var i=C(t);i.closest(o).length&&("SELECT"===t.tagName?n.select(i):"INPUT"===t.tagName&&("checkbox"===(t=t.type)||"radio"===t?n[t](i):n.input(i)))}):e?n[e]?n[e]():l.error('\u4e0d\u652f\u6301\u7684 "'+e+'" \u8868\u5355\u6e32\u67d3'):layui.each(n,function(e,t){t()}),this},t.prototype.validate=function(e){var u=null,d=r.config.verify,f="layui-form-danger";return!(e=C(e))[0]||(e.attr("lay-verify")!==undefined||!1!==this.validate(e.find("*[lay-verify]")))&&(layui.each(e,function(e,r){var s=C(this),t=(s.attr("lay-verify")||"").split("|"),o=s.attr("lay-verType"),c=s.val();if(s.removeClass(f),layui.each(t,function(e,t){var i="",a=d[t];if(a){var n="function"==typeof a?i=a(c,r):!a[0].test(c),l="select"===r.tagName.toLowerCase()||/^checkbox|radio$/.test(r.type),i=i||a[1];if("required"===t&&(i=s.attr("lay-reqText")||i),n)return"tips"===o?h.tips(i,"string"!=typeof s.attr("lay-ignore")&&l?s.next():s,{tips:1}):"alert"===o?h.alert(i,{title:"\u63d0\u793a",shadeClose:!0}):/\bstring|number\b/.test(typeof i)&&h.msg(i,{icon:5,shift:6}),setTimeout(function(){(l?s.next().find("input"):r).focus()},7),s.addClass(f),u=!0}}),u)return u}),!u)},t.prototype.submit=function(e,t){var i=C(this),e="string"==typeof e?e:i.attr("lay-filter"),a=this.getFormElem?this.getFormElem(e):i.parents(o).eq(0),n=a.find("*[lay-verify]");if(!r.validate(n))return!1;n=r.getValue(null,a),a={elem:this.getFormElem?window.event&&window.event.target:this,form:(this.getFormElem?a:i.parents("form"))[0],field:n};return"function"==typeof t&&t(a),layui.event.call(this,w,"submit("+e+")",a)}),r=new t,t=C(document),q=C(window);C(function(){r.render()}),t.on("reset",o,function(){var e=C(this).attr("lay-filter");setTimeout(function(){r.render(null,e)},50)}),t.on("submit",o,i).on("click","*[lay-submit]",i),e(w,r)});layui.define(["laytpl","laypage","form","util"],function(e){"use strict";var m=layui.$,v=layui.laytpl,c=layui.laypage,g=layui.layer,y=layui.form,b=layui.util,f=layui.hint(),h=layui.device(),x={config:{checkName:"LAY_CHECKED",indexName:"LAY_TABLE_INDEX",disabledName:"LAY_DISABLED"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var t=this;return t.config=m.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,C,e,t)}},p=function(){var a=this,e=a.config,i=e.id||e.index;return i&&(p.that[i]=a,p.config[i]=e),{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){x.reloadData(i,e,t)},setColsWidth:function(){a.setColsWidth.call(a)},resize:function(){a.resize.call(a)}}},l=function(e){var t=p.config[e];return t||f.error(e?"The table instance with ID '"+e+"' not found":"ID argument required"),t||null},k=function(e){var t=this.config||{},a=(e=e||{}).item3,i=e.content,t=(("escape"in a?a:t).escape&&(i=b.escape(i)),e.text&&a.exportTemplet||a.templet||a.toolbar);return t&&(i="function"==typeof t?t.call(a,e.tplData,e.obj):v(m(t).html()||String(i)).render(m.extend({LAY_COL:a},e.tplData))),e.text?m("
        "+i+"
        ").text():i},C="table",w="layui-hide",r="layui-hide-v",d="layui-none",s="layui-table-view",u=".layui-table-header",T=".layui-table-body",L=".layui-table-pageview",N=".layui-table-sort",D="layui-table-edit",A="layui-table-hover",E="layui-table-col-special",_="LAY_TABLE_MOVE_DICT",t=function(e){return['',"","{{# layui.each(d.data.cols, function(i1, item1){ }}","","{{# layui.each(item1, function(i2, item2){ }}",'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}','{{# if(item2.fixed === "right"){ right = true; } }}',(e=e||{}).fixed&&"right"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== "right"){ }}':"right"===e.fixed?'{{# if(item2.fixed === "right"){ }}':"","{{# var isSort = !(item2.colGroup) && item2.sort; }}",'",e.fixed?"{{# }; }}":"","{{# }); }}","","{{# }); }}","","
        ','
        ','{{# if(item2.type === "checkbox"){ }}','',"{{# } else { }}",'{{-item2.title||""}}',"{{# if(isSort){ }}",'',"{{# } }}","{{# } }}","
        ","
        "].join("")},a=['',"","
        "].join(""),j=[,"{{# if(d.data.toolbar){ }}",'
        ','
        ','
        ',"
        ","{{# } }}",'
        ',"{{# if(d.data.loading){ }}",'
        ','',"
        ","{{# } }}","{{# var left, right; }}",'
        ',t(),"
        ",'
        ',a,"
        ","{{# if(left){ }}",'
        ','
        ',t({fixed:!0}),"
        ",'
        ',a,"
        ","
        ","{{# }; }}","{{# if(right){ }}",'
        ','
        ',t({fixed:"right"}),'
        ',"
        ",'
        ',a,"
        ","
        ","{{# }; }}","
        ","{{# if(d.data.totalRow){ }}",'
        ','','',"
        ","
        ","{{# } }}",'
        ','
        ',"
        ",""].join(""),R=m(window),S=m(document),i=function(e){this.index=++x.index,this.config=m.extend({},this.config,x.config,e),this.render()},F=(i.prototype.config={limit:10,loading:!0,escape:!0,cellMinWidth:60,editTrigger:"click",defaultToolbar:["filter","exports","print"],autoSort:!0,text:{none:"\u65e0\u6570\u636e"}},i.prototype.render=function(e){var t=this,a=t.config;if(a.elem=m(a.elem),a.where=a.where||{},a.id=a.id||a.elem.attr("id")||t.index,a.request=m.extend({pageName:"page",limitName:"limit"},a.request),a.response=m.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",totalRowName:"totalRow",countName:"count"},a.response),"object"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,t.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return t;if("reloadData"===e)return t.pullData(t.page,{type:"reloadData"});a.height&&/^full-\d+$/.test(a.height)&&(t.fullHeightGap=a.height.split("-")[1],a.height=R.height()-t.fullHeightGap),t.setInit();var i,l,e=a.elem,n=e.next("."+s),o=t.elem=m("
        ");o.addClass((i=[s,s+"-"+t.index,"layui-form","layui-border-box"],a.className&&i.push(a.className),i.join(" "))).attr({"lay-filter":"LAY-TABLE-FORM-DF-"+t.index,"lay-id":a.id,style:(i=[],a.width&&i.push("width:"+a.width+"px;"),a.height&&i.push("height:"+a.height+"px;"),i.join(""))}).html(v(j).render({data:a,index:t.index})),a.index=t.index,t.key=a.id||a.index,n[0]&&n.remove(),e.after(o),t.layTool=o.find(".layui-table-tool"),t.layBox=o.find(".layui-table-box"),t.layHeader=o.find(u),t.layMain=o.find(".layui-table-main"),t.layBody=o.find(T),t.layFixed=o.find(".layui-table-fixed"),t.layFixLeft=o.find(".layui-table-fixed-l"),t.layFixRight=o.find(".layui-table-fixed-r"),t.layTotal=o.find(".layui-table-total"),t.layPage=o.find(".layui-table-page"),t.renderToolbar(),t.renderPagebar(),t.fullSize(),1
        ','
        ','
        '].join(""),a=this.layTool.find(".layui-table-tool-temp"),i=("default"===e.toolbar?a.html(t):"string"==typeof e.toolbar&&(t=m(e.toolbar).html()||"")&&a.html(v(t).render(e)),{filter:{title:"\u7b5b\u9009\u5217",layEvent:"LAYTABLE_COLS",icon:"layui-icon-cols"},exports:{title:"\u5bfc\u51fa",layEvent:"LAYTABLE_EXPORT",icon:"layui-icon-export"},print:{title:"\u6253\u5370",layEvent:"LAYTABLE_PRINT",icon:"layui-icon-print"}}),l=[];"object"==typeof e.defaultToolbar&&layui.each(e.defaultToolbar,function(e,t){t="string"==typeof t?i[t]:t;t&&l.push('
        ')}),this.layTool.find(".layui-table-tool-self").html(l.join(""))},i.prototype.renderPagebar=function(){var e,t=this.config,a=this.layPagebar=m('
        ');t.pagebar&&((e=m(t.pagebar).html()||"")&&a.append(v(e).render(t)),this.layPage.append(a))},i.prototype.setParentCol=function(e,t){var a=this.config,i=this.layHeader.find('th[data-key="'+a.index+"-"+t+'"]'),l=parseInt(i.attr("colspan"))||0;i[0]&&(t=t.split("-"),t=a.cols[t[0]][t[1]],e?l--:l++,i.attr("colspan",l),i[l<1?"addClass":"removeClass"](w),t.colspan=l,t.hide=l<1,(a=i.data("parentkey"))&&this.setParentCol(e,a))},i.prototype.setColsPatch=function(){var a=this,e=a.config;layui.each(e.cols,function(e,t){layui.each(t,function(e,t){t.hide&&a.setParentCol(t.hide,t.parentKey)})})},i.prototype.setColsWidth=function(){var t,a,i=this,o=i.config,l=0,c=0,r=0,d=0,s=i.setInit("width"),e=(i.eachCols(function(e,t){t.hide||l++}),s=s-("line"===o.skin||"nob"===o.skin?2:l+1)-i.getScrollWidth(i.layMain[0])-1,function(n){layui.each(o.cols,function(e,l){layui.each(l,function(e,t){var a=0,i=t.minWidth||o.cellMinWidth;t?t.colGroup||t.hide||(n?r&&r'+(e||"Error")+"
        ");a[0]&&(t.layNone.remove(),a.remove()),t.layFixed.addClass(w),t.layMain.find("tbody").html(""),t.layMain.append(t.layNone=e),t.layTotal.addClass(r),t.layPage.find(L).addClass(r),x.cache[t.key]=[],t.syncCheckAll()},i.prototype.page=1,i.prototype.pullData=function(t,a){var e,i=this,l=i.config,n=l.request,o=l.response,c=function(){"object"==typeof l.initSort&&i.sort(l.initSort.field,l.initSort.type)};a=a||{},"function"==typeof l.before&&l.before(l),i.startTime=(new Date).getTime(),l.url?((e={})[n.pageName]=t,e[n.limitName]=l.limit,n=m.extend(e,l.where),l.contentType&&0==l.contentType.indexOf("application/json")&&(n=JSON.stringify(n)),i.loading(),m.ajax({type:l.method||"get",url:l.url,contentType:l.contentType,data:n,dataType:l.dataType||"json",jsonpCallback:l.jsonpCallback,headers:l.headers||{},success:function(e){(e="function"==typeof l.parseData?l.parseData(e)||e:e)[o.statusName]!=o.statusCode?(i.renderForm(),i.errorView(e[o.msgName]||'\u8fd4\u56de\u7684\u6570\u636e\u4e0d\u7b26\u5408\u89c4\u8303\uff0c\u6b63\u786e\u7684\u6210\u529f\u72b6\u6001\u7801\u5e94\u4e3a\uff1a"'+o.statusName+'": '+o.statusCode)):(i.renderData({res:e,curr:t,count:e[o.countName],type:a.type}),c(),l.time=(new Date).getTime()-i.startTime+" ms"),i.setColsWidth(),"function"==typeof l.done&&l.done(e,t,e[o.countName])},error:function(e,t){i.errorView("\u8bf7\u6c42\u5f02\u5e38\uff0c\u9519\u8bef\u63d0\u793a\uff1a"+t),i.renderForm(),i.setColsWidth(),"function"==typeof l.error&&l.error(e,t)}})):"array"===layui.type(l.data)&&(e=t*l.limit-l.limit,(n={})[o.dataName]=l.data.concat().splice(e,l.limit),n[o.countName]=l.data.length,"object"==typeof l.totalRow&&(n[o.totalRowName]=m.extend({},l.totalRow)),i.renderData({res:n,curr:t,count:n[o.countName],type:a.type}),c(),i.setColsWidth(),"function"==typeof l.done&&l.done(n,t,n[o.countName]))},i.prototype.eachCols=function(e){return x.eachCols(null,e,this.config.cols),this},i.prototype.col=function(e){try{return e=e.split("-"),this.config.cols[e[1]][e[2]]}catch(t){return f.error(t),{}}},i.prototype.renderData=function(e){var u=this,y=u.config,t=e.res,l=e.curr,a=e.count,n=e.sort,i=t[y.response.dataName]||[],t=t[y.response.totalRowName],h=[],f=[],p=[],o=function(){var s;if(y.HAS_SET_COLS_PATCH||u.setColsPatch(),y.HAS_SET_COLS_PATCH=!0,!n&&u.sortKey)return u.sort(u.sortKey.field,u.sortKey.sort,!0);layui.each(i,function(o,c){var a=[],i=[],r=[],d=o+y.limit*(l-1)+1;"array"===layui.type(c)&&0===c.length||(n||(c[x.config.indexName]=o),u.eachCols(function(e,l){var e=l.field||e,t=y.index+"-"+l.key,n=c[e];n!==undefined&&null!==n||(n=""),l.colGroup||(t=['','
        "+function(){var e,t=m.extend(!0,{LAY_INDEX:d,LAY_COL:l},c),a=x.config.checkName,i=x.config.disabledName;switch(l.type){case"checkbox":return'";case"radio":return t[a]&&(s=o),'';case"numbers":return d}return l.toolbar?v(m(l.toolbar).html()||"").render(t):k.call(u,{item3:l,content:n,tplData:t})}(),"
        "].join(""),a.push(t),l.fixed&&"right"!==l.fixed&&i.push(t),"right"===l.fixed&&r.push(t))}),h.push(''+a.join("")+""),f.push(''+i.join("")+""),p.push(''+r.join("")+""))}),"fixed"===y.scrollPos&&"reloadData"===e.type||u.layBody.scrollTop(0),"reset"===y.scrollPos&&u.layBody.scrollLeft(0),u.layMain.find("."+d).remove(),u.layMain.find("tbody").html(h.join("")),u.layFixLeft.find("tbody").html(f.join("")),u.layFixRight.find("tbody").html(p.join("")),u.renderForm(),"number"==typeof s&&u.setThisRowChecked(s),u.syncCheckAll(),u.fullSize(),u.haveInit?u.scrollPatch():setTimeout(function(){u.scrollPatch()},50),u.haveInit=!0,g.close(u.tipsIndex)};return x.cache[u.key]=i,u.layTotal[0==i.length?"addClass":"removeClass"](r),u.layPage[y.page||y.pagebar?"removeClass":"addClass"](w),u.layPage.find(L)[!y.page||0==a||0===i.length&&1==l?"addClass":"removeClass"](r),0===i.length?(u.renderForm(),u.errorView(y.text.none)):(u.layFixLeft.removeClass(w),n?o():(o(),u.renderTotal(i,t),u.layTotal&&u.layTotal.removeClass(w),void(y.page&&(y.page=m.extend({elem:"layui-table-page"+y.index,count:a,limit:y.limit,limits:y.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(u.page=e.curr,y.limit=e.limit,u.pullData(e.curr))}},y.page),y.page.count=a,c.render(y.page)))))},i.prototype.renderTotal=function(e,o){var c,r=this,d=r.config,s={};d.totalRow&&(layui.each(e,function(e,i){"array"===layui.type(i)&&0===i.length||r.eachCols(function(e,t){var e=t.field||e,a=i[e];t.totalRow&&(s[e]=(s[e]||0)+(parseFloat(a)||0))})}),r.dataTotal={},c=[],r.eachCols(function(e,t){var a,e=t.field||e,i=o&&o[t.field],l=(a=t.totalRowText||"",n="totalRowDecimals"in t?t.totalRowDecimals:2,n=parseFloat(s[e]).toFixed(n),(l={LAY_COL:t})[e]=n,n=t.totalRow&&k.call(r,{item3:t,content:n,tplData:l})||a,i||n),n=['','
        "+("string"==typeof(a=t.totalRow||d.totalRow)?v(a).render(m.extend({TOTAL_NUMS:i||s[e],LAY_COL:t},t)):l),"
        "].join("");t.field&&(r.dataTotal[e]=l),c.push(n)}),r.layTotal.find("tbody").html(""+c.join("")+""))},i.prototype.getColElem=function(e,t){var a=this.config;return e.eq(0).find(".laytable-cell-"+a.index+"-"+t+":eq(0)")},i.prototype.renderForm=function(e){this.config;var t=this.elem.attr("lay-filter");y.render(e,t)},i.prototype.setThisRowChecked=function(e){this.config;var t="layui-table-click";this.layBody.find('tr[data-index="'+e+'"]').addClass(t).siblings("tr").removeClass(t)},i.prototype.sort=function(l,e,t,a){var i,n=this,o={},c=n.config,r=c.elem.attr("lay-filter"),d=x.cache[n.key];"string"==typeof l&&(s=l,n.layHeader.find("th").each(function(e,t){var a=m(this),i=a.data("field");if(i===l)return l=a,s=i,!1}));try{var s=s||l.data("field"),u=l.data("key");if(n.sortKey&&!t&&s===n.sortKey.field&&e===n.sortKey.sort)return;var y=n.layHeader.find("th .laytable-cell-"+u).find(N);n.layHeader.find("th").find(N).removeAttr("lay-sort"),y.attr("lay-sort",e||null),n.layFixed.find("th")}catch(h){f.error("Table modules: sort field '"+s+"' not matched")}n.sortKey={field:s,sort:e},c.autoSort&&("asc"===e?i=layui.sort(d,s):"desc"===e?i=layui.sort(d,s,!0):(i=layui.sort(d,x.config.indexName),delete n.sortKey,delete c.initSort)),o[c.response.dataName]=i||d,n.renderData({res:o,curr:n.page,count:n.count,sort:!0}),a&&(c.initSort={field:s,type:e},layui.event.call(l,C,"sort("+r+")",c.initSort))},i.prototype.loading=function(e){var t=this;t.config.loading&&(e?(t.layInit&&t.layInit.remove(),delete t.layInit,t.layBox.find(".layui-table-init").remove()):(t.layInit=m(['
        ','',"
        "].join("")),t.layBox.append(t.layInit)))},i.prototype.setCheckData=function(e,t){var a=this.config,i=x.cache[this.key];i[e]&&"array"!==layui.type(i[e])&&(i[e][a.checkName]=t)},i.prototype.syncCheckAll=function(){var e=this,i=e.config,t=e.layHeader.find('input[name="layTableCheckbox"]'),a=function(a){return e.eachCols(function(e,t){"checkbox"===t.type&&(t[i.checkName]=a)}),a};t[0]&&(x.checkStatus(e.key).isAll?(t[0].checked||(t.prop("checked",!0),e.renderForm("checkbox")),a(!0)):(t[0].checked&&(t.prop("checked",!1),e.renderForm("checkbox")),a(!1)))},i.prototype.getCssRule=function(a,i){var e=this.elem.find("style")[0],e=e.sheet||e.styleSheet||{},e=e.cssRules||e.rules;layui.each(e,function(e,t){if(t.selectorText===".laytable-cell-"+a)return i(t),!0})},i.prototype.fullSize=function(){var e=this,t=e.config,a=t.height;e.fullHeightGap&&(a=R.height()-e.fullHeightGap,e.elem.css("height",a=a<135?135:a)),a&&(a=parseFloat(a)-(e.layHeader.outerHeight()||38),t.toolbar&&(a-=e.layTool.outerHeight()||50),t.totalRow&&(a-=e.layTotal.outerHeight()||40),(t.page||t.pagebar)&&(a-=e.layPage.outerHeight()||43),e.layMain.outerHeight(a))},i.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:((e=document.createElement("div")).style.width="100px",e.style.height="100px",e.style.overflowY="scroll",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},i.prototype.scrollPatch=function(){var e=this,t=e.layMain.children("table"),a=e.layMain.width()-e.layMain.prop("clientWidth"),i=e.layMain.height()-e.layMain.prop("clientHeight"),l=(e.getScrollWidth(e.layMain[0]),t.outerWidth()-e.layMain.width()),n=function(e){var t;a&&i?(e=e.eq(0)).find(".layui-table-patch")[0]||((t=m('
        ')).find("div").css({width:a}),e.find("tr").append(t)):e.find(".layui-table-patch").remove()};n(e.layHeader),n(e.layTotal);n=e.layMain.height()-i;e.layFixed.find(T).css("height",t.height()>=n?n:"auto"),e.layFixRight[0');a.html(t),r.height&&a.css("max-height",r.height-(s.layTool.outerHeight()||50)),i.find(".layui-table-tool-panel")[0]||i.append(a),s.renderForm(),a.on("click",function(e){layui.stope(e)}),e.done&&e.done(a,t)};switch(layui.stope(e),S.trigger("table.tool.panel.remove"),g.close(s.tipsIndex),t){case"LAYTABLE_COLS":l({list:(a=[],s.eachCols(function(e,t){t.field&&"normal"==t.type&&a.push('
      • ')}),a.join("")),done:function(){y.on("checkbox(LAY_TABLE_TOOL_COLS)",function(e){var e=m(e.elem),i=this.checked,l=e.data("key"),n=e.data("parentkey");layui.each(r.cols,function(a,e){layui.each(e,function(e,t){a+"-"+e===l&&(e=t.hide,t.hide=!i,s.elem.find('*[data-key="'+r.index+"-"+l+'"]')[i?"removeClass":"addClass"](w),e!=t.hide&&s.setParentCol(!i,n),s.resize())})})})}});break;case"LAYTABLE_EXPORT":h.ie?g.tips("\u5bfc\u51fa\u529f\u80fd\u4e0d\u652f\u6301 IE\uff0c\u8bf7\u7528 Chrome \u7b49\u9ad8\u7ea7\u6d4f\u89c8\u5668\u5bfc\u51fa",this,{tips:3}):l({list:['
      • \u5bfc\u51fa csv \u683c\u5f0f\u6587\u4ef6
      • ','
      • \u5bfc\u51fa xls \u683c\u5f0f\u6587\u4ef6
      • '].join(""),done:function(e,t){t.on("click",function(){var e=m(this).data("type");x.exportFile.call(s,r.id,null,e)})}});break;case"LAYTABLE_PRINT":var n=window.open("about:blank","_blank"),o=[""].join(""),c=m(s.layHeader.html());c.append(s.layMain.find("table").html()),c.append(s.layTotal.find("table").html()),c.find("th.layui-table-patch").remove(),c.find("thead>tr>th."+E).filter(function(e,t){return!m(t).children(".laytable-cell-group").length}).remove(),c.find("tbody>tr>td."+E).remove(),n.document.write(o+c.prop("outerHTML")),n.document.close(),n.print(),n.close()}layui.event.call(this,C,"toolbar("+d+")",m.extend({event:t,config:r},{}))}),s.layPagebar.on("click","*[lay-event]",function(e){var t=m(this).attr("lay-event");layui.event.call(this,C,"pagebar("+d+")",m.extend({event:t,config:r},{}))}),e.on("mousemove",function(e){var t=m(this),a=t.offset().left,e=e.clientX-a;t.data("unresize")||p.eventMoveElem||(l.allowResize=t.width()-e<=10,i.css("cursor",l.allowResize?"col-resize":""))}).on("mouseleave",function(){m(this);p.eventMoveElem||i.css("cursor","")}).on("mousedown",function(e){var t,a=m(this);l.allowResize&&(t=a.data("key"),e.preventDefault(),l.offset=[e.clientX,e.clientY],s.getCssRule(t,function(e){var t=e.style.width||a.outerWidth();l.rule=e,l.ruleWidth=parseFloat(t),l.minWidth=a.data("minwidth")||r.cellMinWidth}),a.data(_,l),p.eventMoveElem=a)}),p.docEvent||S.on("mousemove",function(e){var t;p.eventMoveElem&&(t=p.eventMoveElem.data(_)||{},p.eventMoveElem.data("resizing",1),e.preventDefault(),t.rule&&((e=t.ruleWidth+e.clientX-t.offset[0])':''))[0].value=n.data("content")||a[t]||i.text(),n.find("."+D)[0]||n.append(l),l.focus(),layui.stope(e)))}).on("mouseenter","td",function(){a.call(this)}).on("mouseleave","td",function(){a.call(this,"hide")}),"layui-table-grid-down"),a=function(e){var t=m(this),a=t.children(u);t.data("off")||(e?t.find(".layui-table-grid-down").remove():!(a.prop("scrollWidth")>a.outerWidth()||0'))},c=(s.layBody.on("click","."+o,function(e){var t=m(this).parent().children(u);s.tipsIndex=g.tips(['
        ',t.html(),"
        ",''].join(""),t[0],{tips:[3,""],time:-1,anim:-1,maxWidth:h.ios||h.android?300:s.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){g.close(t)})}}),layui.stope(e)}),function(e){var t=m(this),a=t.parents("tr").eq(0).data("index");layui.event.call(this,C,(e||"tool")+"("+d+")",n.call(this,{event:t.attr("lay-event")})),s.setThisRowChecked(a)});s.layBody.on("click","*[lay-event]",function(e){c.call(this),layui.stope(e)}).on("dblclick","*[lay-event]",function(e){c.call(this,"toolDouble"),layui.stope(e)}),s.layMain.on("scroll",function(){var e=m(this),t=e.scrollLeft(),e=e.scrollTop();s.layHeader.scrollLeft(t),s.layTotal.scrollLeft(t),s.layFixed.find(T).scrollTop(e),g.close(s.tipsIndex)}),R.on("resize",function(){s.resize()})},S.on("click",function(){S.trigger("table.remove.tool.panel")}),S.on("table.remove.tool.panel",function(){m(".layui-table-tool-panel").remove()}),x.init=function(a,i){i=i||{};var e=m(a?'table[lay-filter="'+a+'"]':".layui-table[lay-data]"),c="Table element property lay-data configuration item has a syntax error: ";return e.each(function(){var e=m(this),t=e.attr("lay-data");try{t=new Function("return "+t)()}catch(l){f.error(c+t,"error")}var n=[],o=m.extend({elem:this,cols:[],data:[],skin:e.attr("lay-skin"),size:e.attr("lay-size"),even:"string"==typeof e.attr("lay-even")},x.config,i,t);a&&e.hide(),e.find("thead>tr").each(function(i){o.cols[i]=[],m(this).children().each(function(e){var t=m(this),a=t.attr("lay-data");try{a=new Function("return "+a)()}catch(l){return f.error(c+a)}t=m.extend({title:t.text(),colspan:t.attr("colspan")||1,rowspan:t.attr("rowspan")||1},a);t.colspan<2&&n.push(t),o.cols[i].push(t)})}),e.find("tbody>tr").each(function(e){var a=m(this),l={};a.children("td").each(function(e,t){var a=m(this),i=a.data("field");if(i)return l[i]=a.html()}),layui.each(n,function(e,t){e=a.children("td").eq(e);l[t.field]=e.html()}),o.data[e]=l}),x.render(o)}),this},p.that={},p.config={},function(a,i,e,l){var n,o;l.colGroup&&(n=0,a++,l.CHILD_COLS=[],o=e+(parseInt(l.rowspan)||1),layui.each(i[o],function(e,t){t.parentKey?t.parentKey===l.key&&(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),F(a,i,o,t)):t.PARENT_COL_INDEX||1<=n&&n==(l.colspan||1)||(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),n+=t.hide?0:parseInt(1td'),a!==undefined&&null!==a||(a=""),0==l&&c.push(t.title||""),o.push('"'+k.call(d,{item3:t,content:a,tplData:n,text:"text",obj:d.commonMember.call(i.eq(0),{td:function(e){return i.filter('[data-field="'+e+'"]')}})})+'"')))}),i.push(o.join(","))}),d&&layui.each(d.dataTotal,function(e,t){r[e]||l.push(t)}),c.join(",")+"\r\n"+i.join("\r\n")+"\r\n"+l.join(","))),u.download=(a.title||o.title||"table_"+(o.index||""))+"."+n,document.body.appendChild(u),u.click(),document.body.removeChild(u)},x.resize=function(e){e?l(e)&&p.that[e].resize():layui.each(p.that,function(){this.resize()})},x.reload=function(e,t,a,i){if(l(e))return e=p.that[e],e.reload(t,a,i),p.call(e)},x.reloadData=function(){var a=m.extend([],arguments),i=(a[3]="reloadData",new RegExp("^("+["data","url","method","contentType","dataType","jsonpCallback","headers","where","page","limit","request","response","parseData","scrollPos"].join("|")+")$"));return layui.each(a[1],function(e,t){i.test(e)||delete a[1][e]}),x.reload.apply(null,a)},x.render=function(e){e=new i(e);return p.call(e)},x.clearCacheKey=function(e){return delete(e=m.extend({},e))[x.config.checkName],delete e[x.config.indexName],delete e[x.config.disabledName],e},m(function(){x.init()}),e(C,x)});layui.define("form",function(e){"use strict";var u=layui.$,i=layui.form,p=layui.layer,n="tree",a={config:{},index:layui[n]?layui[n].index+1e4:0,set:function(e){var i=this;return i.config=u.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,n,e,i)}},t=function(){var i=this,e=i.config,n=e.id||i.index;return t.that[n]=i,{config:t.config[n]=e,reload:function(e){i.reload.call(i,e)},getChecked:function(){return i.getChecked.call(i)},setChecked:function(e){return i.setChecked.call(i,e)}}},y="layui-hide",d="layui-disabled",f="layui-tree-set",C="layui-tree-iconClick",k="layui-icon-addition",v="layui-icon-subtraction",m="layui-tree-entry",x="layui-tree-main",b="layui-tree-txt",g="layui-tree-pack",w="layui-tree-spread",N="layui-tree-setLineShort",T="layui-tree-showLine",L="layui-tree-lineExtend",l=function(e){var i=this;i.index=++a.index,i.config=u.extend({},i.config,a.config,e),i.render()};l.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:"\u672a\u547d\u540d",none:"\u65e0\u6570\u636e"}},l.prototype.reload=function(e){var n=this;layui.each(e,function(e,i){"array"===layui.type(i)&&delete n.config[e]}),n.config=u.extend(!0,{},n.config,e),n.render()},l.prototype.render=function(){var e=this,i=e.config,n=(e.checkids=[],u('
        ')),a=(e.tree(n),i.elem=u(i.elem));if(a[0]){if(e.key=i.id||e.index,e.elem=n,e.elemNone=u('
        '+i.text.none+"
        "),a.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);i.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=u(this);e.parent(".layui-tree-pack")[0]||e.addClass("layui-tree-setHide"),!e.next()[0]&&e.parents(".layui-tree-pack").eq(1).hasClass("layui-tree-lineExtend")&&e.addClass(N),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(N)}),e.events()}},l.prototype.renderForm=function(e){i.render(e,"LAY-tree-"+this.index)},l.prototype.tree=function(l,e){var r=this,c=r.config,e=e||c.data;layui.each(e,function(e,i){var n=i.children&&0"),t=u(['
        ','
        ','
        ',c.showLine?n?'':'':'',c.showCheckbox?'':"",c.isJump&&i.href?''+(i.title||i.label||c.text.defaultNodeName)+"":''+(i.title||i.label||c.text.defaultNodeName)+"","
        ",function(){if(!c.edit)return"";var n={add:'',update:'',del:''},a=['
        '];return!0===c.edit&&(c.edit=["update","del"]),"object"==typeof c.edit?(layui.each(c.edit,function(e,i){a.push(n[i]||"")}),a.join("")+"
        "):void 0}(),"
        "].join(""));n&&(t.append(a),r.tree(a,i.children)),l.append(t),t.prev("."+f)[0]&&t.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),n||t.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),r.spread(t,i),c.showCheckbox&&(i.checked&&r.checkids.push(i.id),r.checkClick(t,i)),c.edit&&r.operate(t,i)})},l.prototype.spread=function(a,e){var t=this.config,i=a.children("."+m),n=i.children("."+x),l=i.find("."+C),i=i.find("."+b),r=t.onlyIconControl?l:n,c="";r.on("click",function(e){var i=a.children("."+g),n=(r.children(".layui-icon")[0]?r:r.find(".layui-tree-icon")).children(".layui-icon");i[0]?a.hasClass(w)?(a.removeClass(w),i.slideUp(200),n.removeClass(v).addClass(k)):(a.addClass(w),i.slideDown(200),n.addClass(v).removeClass(k),t.accordion&&((i=a.siblings("."+f)).removeClass(w),i.children("."+g).slideUp(200),i.find(".layui-tree-icon").children(".layui-icon").removeClass(v).addClass(k))):c="normal"}),i.on("click",function(){u(this).hasClass(d)||(c=a.hasClass(w)?t.onlyIconControl?"open":"close":t.onlyIconControl?"close":"open",t.click&&t.click({elem:a,state:c,data:e}))})},l.prototype.setCheckbox=function(e,i,n){this.config;var t,l=n.prop("checked");n.prop("disabled")||("object"!=typeof i.children&&!e.find("."+g)[0]||e.find("."+g).find('input[same="layuiTreeCheck"]').each(function(){this.disabled||(this.checked=l)}),(t=function(e){var i,n,a;e.parents("."+f)[0]&&(n=(e=e.parent("."+g)).parent(),a=e.prev().find('input[same="layuiTreeCheck"]'),l?a.prop("checked",l):(e.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||a.prop("checked",!1)),t(n))})(e),this.renderForm("checkbox"))},l.prototype.checkClick=function(n,a){var t=this,l=t.config;n.children("."+m).children("."+x).on("click",'input[same="layuiTreeCheck"]+',function(e){layui.stope(e);var e=u(this).prev(),i=e.prop("checked");e.prop("disabled")||(t.setCheckbox(n,a,e),l.oncheck&&l.oncheck({elem:n,checked:i,data:a}))})},l.prototype.operate=function(c,d){var s=this,o=s.config,e=c.children("."+m),h=e.children("."+x);e.children(".layui-tree-btnGroup").on("click",".layui-icon",function(e){layui.stope(e);var i,e=u(this).data("type"),a=c.children("."+g),t={data:d,type:e,elem:c};if("add"==e){a[0]||(o.showLine?(h.find("."+C).addClass("layui-tree-icon"),h.find("."+C).children(".layui-icon").addClass(k).removeClass("layui-icon-file")):h.find(".layui-tree-iconArrow").removeClass(y),c.append('
        '));var n,l=o.operate&&o.operate(t),r={};if(r.title=o.text.defaultNodeName,r.id=l,s.tree(c.children("."+g),[r]),o.showLine&&(a[0]?(a.hasClass(L)||a.addClass(L),c.find("."+g).each(function(){u(this).children("."+f).last().addClass(N)}),(a.children("."+f).last().prev().hasClass(N)?a.children("."+f).last().prev():a.children("."+f).last()).removeClass(N),!c.parent("."+g)[0]&&c.next()[0]&&a.children("."+f).last().removeClass(N)):(l=c.siblings("."+f),n=1,r=c.parent("."+g),layui.each(l,function(e,i){u(i).children("."+g)[0]||(n=0)}),1==n?(l.children("."+g).addClass(T),l.children("."+g).children("."+f).removeClass(N),c.children("."+g).addClass(T),r.removeClass(L),r.children("."+f).last().children("."+g).children("."+f).last().addClass(N)):c.children("."+g).children("."+f).addClass(N))),!o.showCheckbox)return;h.find('input[same="layuiTreeCheck"]')[0].checked&&(c.children("."+g).children("."+f).last().find('input[same="layuiTreeCheck"]')[0].checked=!0),s.renderForm("checkbox")}else"update"==e?(l=h.children("."+b).html(),h.children("."+b).html(""),h.append(''),h.children(".layui-tree-editInput").val(l).focus(),i=function(e){var i=(i=e.val().trim())||o.text.defaultNodeName;e.remove(),h.children("."+b).html(i),t.data.title=i,o.operate&&o.operate(t)},h.children(".layui-tree-editInput").blur(function(){i(u(this))}),h.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),i(u(this)))})):p.confirm('\u786e\u8ba4\u5220\u9664\u8be5\u8282\u70b9 "'+(d.title||"")+'" \u5417\uff1f',function(e){if(o.operate&&o.operate(t),t.status="remove",p.close(e),!c.prev("."+f)[0]&&!c.next("."+f)[0]&&!c.parent("."+g)[0])return c.remove(),void s.elem.append(s.elemNone);var l,n,i;c.siblings("."+f).children("."+m)[0]?(o.showCheckbox&&(l=function(e){var i,n,a,t;e.parents("."+f)[0]&&(i=e.siblings("."+f).children("."+m),n=(e=e.parent("."+g).prev()).find('input[same="layuiTreeCheck"]')[0],a=1,(t=0)==n.checked&&(i.each(function(e,i){i=u(i).find('input[same="layuiTreeCheck"]')[0];0!=i.checked||i.disabled||(a=0),i.disabled||(t=1)}),1==a&&1==t&&(n.checked=!0,s.renderForm("checkbox"),l(e.parent("."+f)))))})(c),o.showLine&&(e=c.siblings("."+f),n=1,i=c.parent("."+g),layui.each(e,function(e,i){u(i).children("."+g)[0]||(n=0)}),1==n?(a[0]||(i.removeClass(L),e.children("."+g).addClass(T),e.children("."+g).children("."+f).removeClass(N)),(c.next()[0]?i.children("."+f).last():c.prev()).children("."+g).children("."+f).last().addClass(N),c.next()[0]||c.parents("."+f)[1]||c.parents("."+f).eq(0).next()[0]||c.prev("."+f).addClass(N)):!c.next()[0]&&c.hasClass(N)&&c.prev().addClass(N))):(e=c.parent("."+g).prev(),o.showLine?(e.find("."+C).removeClass("layui-tree-icon"),e.find("."+C).children(".layui-icon").removeClass(v).addClass("layui-icon-file"),(i=e.parents("."+g).eq(0)).addClass(L),i.children("."+f).each(function(){u(this).children("."+g).children("."+f).last().addClass(N)})):e.find(".layui-tree-iconArrow").addClass(y),c.parents("."+f).eq(0).removeClass(w),c.parent("."+g).remove()),c.remove()})})},l.prototype.events=function(){var i=this,t=i.config;i.elem.find(".layui-tree-checkedFirst");i.setChecked(i.checkids),i.elem.find(".layui-tree-search").on("keyup",function(){var e=u(this),n=e.val(),e=e.nextAll(),a=[];e.find("."+b).each(function(){var i,e=u(this).parents("."+m);-1!=u(this).html().indexOf(n)&&(a.push(u(this).parent()),(i=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+g)[0]&&i(e.parent("."+g).parent("."+f))})(e.parent("."+f)))}),e.find("."+m).each(function(){var e=u(this).parent("."+f);e.hasClass("layui-tree-searchShow")||e.addClass(y)}),0==e.find(".layui-tree-searchShow").length&&i.elem.append(i.elemNone),t.onsearch&&t.onsearch({elem:a})}),i.elem.find(".layui-tree-search").on("keydown",function(){u(this).nextAll().find("."+m).each(function(){u(this).parent("."+f).removeClass("layui-tree-searchShow "+y)}),u(".layui-tree-emptyText")[0]&&u(".layui-tree-emptyText").remove()})},l.prototype.getChecked=function(){var e=this.config,i=[],n=[],t=(this.elem.find(".layui-form-checked").each(function(){i.push(u(this).prev()[0].value)}),function(e,a){layui.each(e,function(e,n){layui.each(i,function(e,i){if(n.id==i)return delete(i=u.extend({},n)).children,a.push(i),n.children&&(i.children=[],t(n.children,i.children)),!0})})});return t(u.extend({},e.data),n),n},l.prototype.setChecked=function(l){this.config;this.elem.find("."+f).each(function(e,i){var n=u(this).data("id"),a=u(i).children("."+m).find('input[same="layuiTreeCheck"]'),t=a.next();if("number"==typeof l){if(n==l)return a[0].checked||t.click(),!1}else"object"==typeof l&&layui.each(l,function(e,i){if(i==n&&!a[0].checked)return t.click(),!0})})},t.that={},t.config={},a.reload=function(e,i){e=t.that[e];return e.reload(i),t.call(e)},a.getChecked=function(e){return t.that[e].getChecked()},a.setChecked=function(e,i){return t.that[e].setChecked(i)},a.render=function(e){e=new l(e);return t.call(e)},e(n,a)});layui.define(["laytpl","form"],function(e){"use strict";var s=layui.$,n=layui.laytpl,t=layui.form,a="transfer",i={config:{},index:layui[a]?layui[a].index+1e4:0,set:function(e){var t=this;return t.config=s.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,a,e,t)}},l=function(){var t=this,e=t.config,a=e.id||t.index;return l.that[a]=t,{config:l.config[a]=e,reload:function(e){t.reload.call(t,e)},getData:function(){return t.getData.call(t)}}},d="layui-hide",h="layui-btn-disabled",r="layui-none",c="layui-transfer-box",u="layui-transfer-header",o="layui-transfer-search",f="layui-transfer-data",y=function(e){return['
        ','
        ','","
        ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
          ',"
          "].join("")},p=['
          ',y({index:0,checkAllName:"layTransferLeftCheckAll"}),'
          ','",'","
          ",y({index:1,checkAllName:"layTransferRightCheckAll"}),"
          "].join(""),v=function(e){var t=this;t.index=++i.index,t.config=s.extend({},t.config,i.config,e),t.render()};v.prototype.config={title:["\u5217\u8868\u4e00","\u5217\u8868\u4e8c"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"\u65e0\u6570\u636e",searchNone:"\u65e0\u5339\u914d\u6570\u636e"}},v.prototype.reload=function(e){var t=this;t.config=s.extend({},t.config,e),t.render()},v.prototype.render=function(){var e=this,t=e.config,a=e.elem=s(n(p).render({data:t,index:e.index})),i=t.elem=s(t.elem);i[0]&&(t.data=t.data||[],t.value=t.value||[],e.key=t.id||e.index,i.html(e.elem),e.layBox=e.elem.find("."+c),e.layHeader=e.elem.find("."+u),e.laySearch=e.elem.find("."+o),e.layData=a.find("."+f),e.layBtn=a.find(".layui-transfer-active .layui-btn"),e.layBox.css({width:t.width,height:t.height}),e.layData.css({height:(i=t.height-e.layHeader.outerHeight(),t.showSearch&&(i-=e.laySearch.outerHeight()),i-2)}),e.renderData(),e.events())},v.prototype.renderData=function(){var e=this,i=(e.config,[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,a=["
        • ",'',"
        • "].join("");i[t].views.push(a),delete e.selected}),e.layData.eq(0).html(i[0].views.join("")),e.layData.eq(1).html(i[1].views.join("")),e.renderCheckBtn()},v.prototype.renderForm=function(e){t.render(e,"LAY-transfer-"+this.index)},v.prototype.renderCheckBtn=function(r){var c=this,o=c.config;r=r||{},c.layBox.each(function(e){var t=s(this),a=t.find("."+f),t=t.find("."+u).find('input[type="checkbox"]'),i=a.find('input[type="checkbox"]'),n=0,l=!1;i.each(function(){var e=s(this).data("hide");(this.checked||this.disabled||e)&&n++,this.checked&&!e&&(l=!0)}),t.prop("checked",l&&n===i.length),c.layBtn.eq(e)[l?"removeClass":"addClass"](h),r.stopNone||(i=a.children("li:not(."+d+")").length,c.noneView(a,i?"":o.text.none))}),c.renderForm("checkbox")},v.prototype.noneView=function(e,t){var a=s('

          '+(t||"")+"

          ");e.find("."+r)[0]&&e.find("."+r).remove(),t.replace(/\s/g,"")&&e.append(a)},v.prototype.setValue=function(){var e=this.config,t=[];return this.layBox.eq(1).find("."+f+' input[type="checkbox"]').each(function(){s(this).data("hide")||t.push(this.value)}),e.value=t,this},v.prototype.parseData=function(t){var i=this.config,n=[];return layui.each(i.data,function(e,a){a=("function"==typeof i.parseData?i.parseData(a):a)||a,n.push(a=s.extend({},a)),layui.each(i.value,function(e,t){t==a.value&&(a.selected=!0)}),t&&t(a)}),i.data=n,this},v.prototype.getData=function(e){var t=this.config,i=[];return this.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},v.prototype.transfer=function(e,t){var a,i=this,n=i.config,l=i.layBox.eq(e),r=[],t=(t?((a=(t=t).find('input[type="checkbox"]'))[0].checked=!1,l.siblings("."+c).find("."+f).append(t.clone()),t.remove(),r.push(a[0].value),i.setValue()):l.each(function(e){s(this).find("."+f).children("li").each(function(){var e=s(this),t=e.find('input[type="checkbox"]'),a=t.data("hide");t[0].checked&&!a&&(t[0].checked=!1,l.siblings("."+c).find("."+f).append(e.clone()),e.remove(),r.push(t[0].value)),i.setValue()})}),i.renderCheckBtn(),l.siblings("."+c).find("."+o+" input"));""!==t.val()&&t.trigger("keyup"),n.onchange&&n.onchange(i.getData(r),e)},v.prototype.events=function(){var n=this,l=n.config;n.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var e=s(this).prev(),t=e[0].checked,a=e.parents("."+c).eq(0).find("."+f);e[0].disabled||("all"===e.attr("lay-type")&&a.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=t)}),setTimeout(function(){n.renderCheckBtn({stopNone:!0})},0))}),n.elem.on("dblclick","."+f+">li",function(e){var t=s(this),a=t.children('input[type="checkbox"]'),i=t.parent().parent();a[0].disabled||n.transfer(i.data("index"),t)}),n.layBtn.on("click",function(){var e=s(this),t=e.data("index");e.hasClass(h)||n.transfer(t)}),n.laySearch.find("input").on("keyup",function(){var i=this.value,e=s(this).parents("."+o).eq(0).siblings("."+f),t=e.children("li"),t=(t.each(function(){var e=s(this),t=e.find('input[type="checkbox"]'),a=t[0].title,a=("cs"!==l.showSearch&&(a=a.toLowerCase(),i=i.toLowerCase()),-1!==a.indexOf(i));e[a?"removeClass":"addClass"](d),t.data("hide",!a)}),n.renderCheckBtn(),t.length===e.children("li."+d).length);n.noneView(e,t?l.text.searchNone:"")})},l.that={},l.config={},i.reload=function(e,t){e=l.that[e];return e.reload(t),l.call(e)},i.getData=function(e){return l.that[e].getData()},i.render=function(e){e=new v(e);return l.call(e)},e(a,i)});layui.define("jquery",function(e){"use strict";var a=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,d,e,i)}}),d="carousel",r="layui-this",s="layui-carousel-left",u="layui-carousel-right",c="layui-carousel-prev",m="layui-carousel-next",t="layui-carousel-arrow",l="layui-carousel-ind",i=function(e){var i=this;i.config=a.extend({},i.config,n.config,e),i.render()};i.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},i.prototype.render=function(){var e=this,i=e.config;i.elem=a(i.elem),i.elem[0]&&(e.elemItem=i.elem.find(">*[carousel-item]>*"),i.index<0&&(i.index=0),i.index>=e.elemItem.length&&(i.index=e.elemItem.length-1),i.interval<800&&(i.interval=800),i.full?i.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):i.elem.css({width:i.width,height:i.height}),i.elem.attr("lay-anim",i.anim),e.elemItem.eq(i.index).addClass(r),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},i.prototype.reload=function(e){var i=this;clearInterval(i.timer),i.config=a.extend({},i.config,e),i.render()},i.prototype.prevIndex=function(){var e=this.config.index-1;return e=e<0?this.elemItem.length-1:e},i.prototype.nextIndex=function(){var e=this.config.index+1;return e=e>=this.elemItem.length?0:e},i.prototype.addIndex=function(e){var i=this.config;i.index=i.index+(e=e||1),i.index>=this.elemItem.length&&(i.index=0)},i.prototype.subIndex=function(e){var i=this.config;i.index=i.index-(e=e||1),i.index<0&&(i.index=this.elemItem.length-1)},i.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},i.prototype.arrow=function(){var i=this,e=i.config,n=a(['",'"].join(""));e.elem.attr("lay-arrow",e.arrow),e.elem.find("."+t)[0]&&e.elem.find("."+t).remove(),e.elem.append(n),n.on("click",function(){var e=a(this).attr("lay-type");i.slide(e)})},i.prototype.indicator=function(){var i,n=this,t=n.config,e=n.elemInd=a(['
            ',(i=[],layui.each(n.elemItem,function(e){i.push("")}),i.join("")),"
          "].join(""));t.elem.attr("lay-indicator",t.indicator),t.elem.find("."+l)[0]&&t.elem.find("."+l).remove(),t.elem.append(e),"updown"===t.anim&&e.css("margin-top",-e.height()/2),e.find("li").on("hover"===t.trigger?"mouseover":t.trigger,function(){var e=a(this).index();e>t.index?n.slide("add",e-t.index):ea.length&&(a.value=a.length),parseInt(a.value)===a.value||a.half||(a.value=Math.ceil(a.value)-a.value<.5?Math.ceil(a.value):Math.floor(a.value)),'
            "),n=1;n<=a.length;n++){var t='
          • ";a.half&&parseInt(a.value)!==a.value&&n==Math.ceil(a.value)?i=i+'
          • ":i+=t}i+="
          "+(a.text?''+a.value+"\u661f":"")+"";var o=a.elem,s=o.next(".layui-rate");s[0]&&s.remove(),e.elemTemp=u(i),a.span=e.elemTemp.next("span"),a.setText&&a.setText(a.value),o.html(e.elemTemp),o.addClass("layui-inline"),a.readonly||e.action()},a.prototype.setvalue=function(e){this.config.value=e,this.render()},a.prototype.action=function(){var i=this.config,n=this.elemTemp,t=n.find("i").width();n.children("li").each(function(e){var a=e+1,l=u(this);l.on("click",function(e){i.value=a,i.half&&e.pageX-u(this).offset().left<=t/2&&(i.value=i.value-.5),i.text&&n.next("span").text(i.value+"\u661f"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),l.on("mousemove",function(e){n.find("i").each(function(){u(this).addClass(c).removeClass(s)}),n.find("i:lt("+a+")").each(function(){u(this).addClass(r).removeClass(f)}),i.half&&e.pageX-u(this).offset().left<=t/2&&l.children("i").addClass(o).removeClass(r)}),l.on("mouseleave",function(){n.find("i").each(function(){u(this).addClass(c).removeClass(s)}),n.find("i:lt("+Math.floor(i.value)+")").each(function(){u(this).addClass(r).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&n.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(o).removeClass("layui-icon-rate-solid layui-icon-rate")})})},a.prototype.events=function(){this.config},l.render=function(e){e=new a(e);return function(){var a=this;return{setvalue:function(e){a.setvalue.call(a,e)},config:a.config}}.call(e)},e(i,l)});layui.define("jquery",function(l){"use strict";var g=layui.$,e=function(l){};e.prototype.load=function(l){var t,i,n,e,r,o,a,c,m,s,u,f,y,d=this,p=0,h=g((l=l||{}).elem);if(h[0])return e=g(l.scrollElem||document),r=l.mb||50,o=!("isAuto"in l)||l.isAuto,a=l.end||"\u6ca1\u6709\u66f4\u591a\u4e86",c=l.scrollElem&&l.scrollElem!==document,m="\u52a0\u8f7d\u66f4\u591a",s=g('"),h.find(".layui-flow-more")[0]||h.append(s),u=function(l,e){l=g(l),s.before(l),(e=0==e||null)?s.html(a):s.find("a").html(m),i=e,t=null,y&&y()},f=function(){t=!0,s.find("a").html(''),"function"==typeof l.done&&l.done(++p,u)},f(),s.find("a").on("click",function(){g(this);i||t||f()}),l.isLazyimg&&(y=d.lazyimg({elem:l.elem+" img",scrollElem:l.scrollElem})),o&&e.on("scroll",function(){var e=g(this),o=e.scrollTop();n&&clearTimeout(n),!i&&h.width()&&(n=setTimeout(function(){var l=(c?e:g(window)).height();(c?e.prop("scrollHeight"):document.documentElement.scrollHeight)-o-l<=r&&(t||f())},100))}),d},e.prototype.lazyimg=function(l){var e,c=this,m=0,s=g((l=l||{}).scrollElem||document),u=l.elem||"img",f=l.scrollElem&&l.scrollElem!==document,y=function(e,l){var o,t=s.scrollTop(),l=t+l,i=f?e.offset().top-s.offset().top+t:e.offset().top;t<=i&&i<=l&&e.attr("lay-src")&&(o=e.attr("lay-src"),layui.img(o,function(){var l=c.lazyimg.elem.eq(m);e.attr("src",o).removeAttr("lay-src"),l[0]&&n(l),m++},function(){c.lazyimg.elem.eq(m);e.removeAttr("lay-src")}))},n=function(l,e){var o=(f?e||s:g(window)).height(),t=s.scrollTop(),i=t+o;if(c.lazyimg.elem=g(u),l)y(l,o);else for(var n=0;n','
          '+e+"
          ",'
          ','',"
          ",""].join(""));return d.ie&&d.ie<8?s.removeClass("layui-hide").addClass("layui-show"):(c[0]&&c.remove(),f.call(a,o,s[0],n),s.addClass("layui-hide").after(o),a.index)},e.prototype.getContent=function(t){t=n(t);if(t[0])return l(t[0].document.body.innerHTML)},e.prototype.getText=function(t){t=n(t);if(t[0])return u(t[0].document.body).text()},e.prototype.setContent=function(t,e,i){var l=n(t);l[0]&&(i?u(l[0].document.body).append(e):u(l[0].document.body).html(e),layedit.sync(t))},e.prototype.sync=function(t){t=n(t);t[0]&&u("#"+t[1].attr("textarea")).val(l(t[0].document.body.innerHTML))},e.prototype.getSelection=function(t){var t=n(t);if(t[0])return t=p(t[0].document),document.selection?t.text:t.toString()},function(a,n,o){var s=this,r=a.find("iframe");r.css({height:o.height}).on("load",function(){var t=r.contents(),e=r.prop("contentWindow"),i=t.find("head"),l=u([""].join("")),t=t.find("body");i.append(l),t.attr("contenteditable","true").css({"min-height":o.height}).html(n.value||""),m.apply(s,[e,r,n,o]),g.call(s,e,a,o)})}),n=function(t){t=u("#LAY_layedit_"+t);return[t.prop("contentWindow"),t]},l=function(t){return t=8==d.ie?t.replace(/<.+>/g,function(t){return t.toLowerCase()}):t},m=function(e,t,i,l){var a=e.document,n=u(a.body);n.on("keydown",function(t){if(13===t.keyCode){var e=p(a);if("pre"===h(e).parentNode.tagName.toLowerCase())return t.shiftKey?void 0:(c.msg("\u8bf7\u6682\u65f6\u7528shift+enter"),!1);a.execCommand("formatBlock",!1,"

          ")}}),u(i).parents("form").on("submit",function(){var t=n.html();8==d.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),i.value=t}),n.on("paste",function(t){a.execCommand("formatBlock",!1,"

          "),setTimeout(function(){o.call(e,n),i.value=n.html()},100)})},o=function(t){this.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),u(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},p=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},h=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,e,i){var l,a,n=this.document,o=document.createElement(t);for(l in e)o.setAttribute(l,e[l]);o.removeAttribute("text"),n.selection?(a=i.text||e.text,"a"===t&&!a||(a&&(o.innerHTML=a),i.pasteHTML(u(o).prop("outerHTML")),i.select())):(a=i.toString()||e.text,"a"===t&&!a||(a&&(o.innerHTML=a),i.deleteContents(),i.insertNode(o)))},b=function(e,t){var i=this.document,l="layedit-tool-active",i=h(p(i)),a=function(t){return e.find(".layedit-tool-"+t)};t&&t[t.hasClass(l)?"removeClass":"addClass"](l),e.find(">i").removeClass(l),a("unlink").addClass(y),u(i).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||a("b").addClass(l),"i"!==t&&"em"!==t||a("i").addClass(l),"u"===t&&a("u").addClass(l),"strike"===t&&a("d").addClass(l),"p"===t&&a("center"===e?"center":"right"===e?"right":"left").addClass(l),"a"===t&&(a("link").addClass(l),a("unlink").removeClass(y))})},g=function(a,t,e){var n=a.document,o=u(n.body),s={link:function(i){var t=h(i),l=u(t).parent();x.call(o,{href:l.attr("href"),target:l.attr("target")},function(t){var e=l[0];"A"===e.tagName?e.href=t.url:v.call(a,"a",{target:t.target,href:t.url,text:t.url},i)})},unlink:function(t){n.execCommand("unlink")},code:function(e){k.call(o,function(t){v.call(a,"pre",{text:t.code,"lay-lang":t.lang},e)})},help:function(){c.open({type:2,title:"\u5e2e\u52a9",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["","no"]})}},r=t.find(".layui-layedit-tool"),i=function(){var t,e=u(this),i=e.attr("layedit-event"),l=e.attr("lay-command");e.hasClass(y)||(o.focus(),(t=p(n)).commonAncestorContainer,l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

          "),setTimeout(function(){o.focus()},10)):s[i]&&s[i].call(this,t),b.call(a,r,e))},l=/image/;r.find(">i").on("mousedown",function(){var t=u(this).attr("layedit-event");l.test(t)||i.call(this)}).on("click",function(){var t=u(this).attr("layedit-event");l.test(t)&&i.call(this)}),o.on("click",function(){b.call(a,r)})},x=function(t,i){var l=this,t=c.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"\u8d85\u94fe\u63a5",skin:"layui-layer-msg",content:['

            ','
          • ','','
            ','',"
            ","
          • ",'
          • ','','
            ','",'","
            ","
          • ",'
          • ','','',"
          • ","
          "].join(""),success:function(t,e){a.render("radio"),t.find(".layui-btn-primary").on("click",function(){c.close(e),l.focus()}),a.on("submit(layedit-link-yes)",function(t){c.close(x.index),i&&i(t.field)})}});x.index=t},k=function(i){var l=this,t=c.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"\u63d2\u5165\u4ee3\u7801",skin:"layui-layer-msg",content:['
            ','
          • ','','
            ','","
            ","
          • ",'
          • ','','
            ','',"
            ","
          • ",'
          • ','','',"
          • ","
          "].join(""),success:function(t,e){a.render("select"),t.find(".layui-btn-primary").on("click",function(){c.close(e),l.focus()}),a.on("submit(layedit-code-yes)",function(t){c.close(k.index),i&&i(t.field)})}});k.index=t},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},e=new e;t(i,e)});layui.define(["lay","util"],function(e){"use strict";var d=layui.$,o=layui.util,u="layui-code-title",l={elem:".layui-code",title:"</>",about:"",ln:!0};e("code",function(e){var c=e=d.extend({},l,e);e.elem=d(e.elem),e.elem[0]&&layui.each(e.elem.get().reverse(),function(e,l){var t,a=d(l),i=(i=a.html(),d.trim(i).replace(/^\n|\n$/,"")),l=d.extend({},c,lay.options(l),(t={},layui.each(["title","height","encode","skin","about"],function(e,l){var i=a.attr("lay-"+l);"string"==typeof i&&(t[l]=i)}),t)),s=l.ln?"ol":"ul",s=d("<"+s+' class="layui-code-'+s+'">'),n=d('
          ');a.addClass("layui-code-view layui-box"),l.skin&&("notepad"===l.skin&&(l.skin="dark"),a.addClass("layui-code-"+l.skin)),i=(i=l.encode?o.escape(i):i).replace(/[\r\t\n]+/g,"
        • "),a.html(s.html("
        • "+i+"
        • ")),a.children("."+u)[0]||(n.html(l.title+(l.about?'
          '+l.about+"
          ":"")),a.prepend(n)),0<(i=Math.floor(s.find("li").length/100))&&s.css("margin-left",i+"px"),l.height&&s.css("max-height",l.height)})})}).addcss("modules/code.css?v=3","skincodecss"); diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/login/css/index.css b/src/parsers/Telegram/telegram_media_downloader/module/static/login/css/index.css new file mode 100644 index 0000000..e2a523f --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/login/css/index.css @@ -0,0 +1,97 @@ +* { + margin: 0; + padding: 0; +} + +.main { + position: relative; + width: 100%; + min-height: 100vh; +} +.main .content { + position: absolute; + top: 150px; + left: 50%; + transform: translateX(-50%); +} +.main .content .logo { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} +.main .content .logo img { + width: 150px; + height: 150px; +} +.main .content .logo .title { + margin-top: 40px; + font-size: 24px; +} +.main .content .logo .tips { + margin-top: 8px; + font-size: 16px; + color: #707579; +} +.main .content .password-input { + position: relative; + width: 408px; + margin-top: 48px; +} +.main .content .password-input:hover .tip { + color: #3390ec !important; +} +.main .content .password-input .input-p { + display: block; + box-sizing: border-box; + width: 100%; + height: 54px; + padding: 11px 13px; + border: 1px solid #dadce0; + border-radius: 12px; + font-size: 16px; + transition: transform 0.15s ease-out, color 0.15s ease-out; + outline: none; +} +.main .content .password-input .input-p:focus { + outline: 2px solid #3390ec; +} +.main .content .password-input .tip { + position: absolute; + left: 12px; + top: 15px; + padding: 0 4px; + background-color: #fff; + font-size: 16px; + font-weight: 400; + transition: transform 0.15s ease-out, color 0.15s ease-out; + transform-origin: left center; + color: #707579; + transform: scale(0.75) translate(-8px, -36px); +} +.main .content .confirm-btn { + margin-top: 44px; + outline: none !important; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 56px; + border: 0; + border-radius: 12px; + background-color: rgba(74, 149, 214, 0.08); + background-size: cover; + padding: 10px; + color: #3390ec; + line-height: 1.2; + cursor: pointer; + text-transform: uppercase; + flex-shrink: 0; + position: relative; + overflow: hidden; + transition: background-color 0.15s, color 0.15s; + text-decoration: none !important; + --premium-gradient: linear-gradient(88.39deg, #6C93FF -2.56%, #976FFF 51.27%, #DF69D1 107.39%); +} + +/*# sourceMappingURL=index.css.map */ diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/login/images/login.svg b/src/parsers/Telegram/telegram_media_downloader/module/static/login/images/login.svg new file mode 100644 index 0000000..ae107ff --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/login/images/login.svg @@ -0,0 +1 @@ + diff --git a/src/parsers/Telegram/telegram_media_downloader/module/static/request/index.js b/src/parsers/Telegram/telegram_media_downloader/module/static/request/index.js new file mode 100644 index 0000000..19dabdf --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/static/request/index.js @@ -0,0 +1,20 @@ +var request = (url, type = 'get' | 'post', data) => { + const $ = layui.$ + + return new Promise((resolve, reject) => { + $.ajax({ + url, + type, + data, + dataType: 'json', + timeout: 60 * 1000, + contentType: 'application/x-www-form-urlencoded', + success: (res) => { + resolve(res) + }, + error: (err) => { + reject(err) + } + }) + }) +} diff --git a/src/parsers/Telegram/telegram_media_downloader/module/templates/index.html b/src/parsers/Telegram/telegram_media_downloader/module/templates/index.html new file mode 100644 index 0000000..02d4cba --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/templates/index.html @@ -0,0 +1,313 @@ + + + + + + + Telegram Media Downloader + + + + + + +
          +
          +
            +
          • Downloading
          • +
          • Downloaded
          • + +
          +
          {{ download_state }}
          +
          +
          +
          +
          +
          +
          +
          +
          + +
          +
          + + + + + + + + diff --git a/src/parsers/Telegram/telegram_media_downloader/module/templates/login.html b/src/parsers/Telegram/telegram_media_downloader/module/templates/login.html new file mode 100644 index 0000000..b21d7c7 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/templates/login.html @@ -0,0 +1,68 @@ + + + + + + + login + + + + +
          +
          + +
          + +
          Your password
          +
          + +
          +
          + + + + + + + + diff --git a/src/parsers/Telegram/telegram_media_downloader/module/web.py b/src/parsers/Telegram/telegram_media_downloader/module/web.py new file mode 100644 index 0000000..4f00e1d --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/module/web.py @@ -0,0 +1,222 @@ +"""web ui for media download""" + +import logging +import os +import threading + +from flask import Flask, jsonify, render_template, request + +import utils +from flask_login import LoginManager, UserMixin, login_required, login_user +from module.app import Application +from module.download_stat import ( + DownloadState, + get_download_result, + get_download_state, + get_total_download_speed, + set_download_state, +) +from utils.crypto import AesBase64 +from utils.format import format_byte + +log = logging.getLogger("werkzeug") +log.setLevel(logging.ERROR) + +_flask_app = Flask(__name__) + +_flask_app.secret_key = "tdl" +_login_manager = LoginManager() +_login_manager.login_view = "login" +_login_manager.init_app(_flask_app) +web_login_users: dict = {} +deAesCrypt = AesBase64("1234123412ABCDEF", "ABCDEF1234123412") + + +class User(UserMixin): + """Web Login User""" + + def __init__(self): + self.sid = "root" + + @property + def id(self): + """ID""" + return self.sid + + +@_login_manager.user_loader +def load_user(_): + """ + Load a user object from the user ID. + + Returns: + User: The user object. + """ + return User() + + +def get_flask_app() -> Flask: + """get flask app instance""" + return _flask_app + + +def run_web_server(app: Application): + """ + Runs a web server using the Flask framework. + """ + + get_flask_app().run( + app.web_host, app.web_port, debug=app.debug_web, use_reloader=False + ) + + +# pylint: disable = W0603 +def init_web(app: Application): + """ + Set the value of the users variable. + + Args: + users: The list of users to set. + + Returns: + None. + """ + global web_login_users + if app.web_login_secret: + web_login_users = {"root": app.web_login_secret} + else: + _flask_app.config["LOGIN_DISABLED"] = True + if app.debug_web: + threading.Thread(target=run_web_server, args=(app,)).start() + else: + threading.Thread( + target=get_flask_app().run, daemon=True, args=(app.web_host, app.web_port) + ).start() + + +@_flask_app.route("/login", methods=["GET", "POST"]) +def login(): + """ + Function to handle the login route. + + Parameters: + - No parameters + + Returns: + - If the request method is "POST" and the username and + password match the ones in the web_login_users dictionary, + it returns a JSON response with a code of "1". + - Otherwise, it returns a JSON response with a code of "0". + - If the request method is not "POST", it returns the rendered "login.html" template. + """ + if request.method == "POST": + username = "root" + web_login_form = {} + for key, value in request.form.items(): + if value: + value = deAesCrypt.decrypt(value) + web_login_form[key] = value + + if not web_login_form.get("password"): + return jsonify({"code": "0"}) + + password = web_login_form["password"] + if username in web_login_users and web_login_users[username] == password: + user = User() + login_user(user) + return jsonify({"code": "1"}) + + return jsonify({"code": "0"}) + + return render_template("login.html") + + +@_flask_app.route("/") +@login_required +def index(): + """Index html""" + return render_template( + "index.html", + download_state=( + "pause" if get_download_state() is DownloadState.Downloading else "continue" + ), + ) + + +@_flask_app.route("/get_download_status") +@login_required +def get_download_speed(): + """Get download speed""" + return ( + '{ "download_speed" : "' + + format_byte(get_total_download_speed()) + + '/s" , "upload_speed" : "0.00 B/s" } ' + ) + + +@_flask_app.route("/set_download_state", methods=["POST"]) +@login_required +def web_set_download_state(): + """Set download state""" + state = request.args.get("state") + + if state == "continue" and get_download_state() is DownloadState.StopDownload: + set_download_state(DownloadState.Downloading) + return "pause" + + if state == "pause" and get_download_state() is DownloadState.Downloading: + set_download_state(DownloadState.StopDownload) + return "continue" + + return state + + +@_flask_app.route("/get_app_version") +def get_app_version(): + """Get telegram_media_downloader version""" + return utils.__version__ + + +@_flask_app.route("/get_download_list") +@login_required +def get_download_list(): + """get download list""" + if request.args.get("already_down") is None: + return "[]" + + already_down = request.args.get("already_down") == "true" + + download_result = get_download_result() + result = "[" + for chat_id, messages in download_result.items(): + for idx, value in messages.items(): + is_already_down = value["down_byte"] == value["total_size"] + + if already_down and not is_already_down: + continue + + if result != "[": + result += "," + download_speed = format_byte(value["download_speed"]) + "/s" + result += ( + '{ "chat":"' + + f"{chat_id}" + + '", "id":"' + + f"{idx}" + + '", "filename":"' + + os.path.basename(value["file_name"]) + + '", "total_size":"' + + f'{format_byte(value["total_size"])}' + + '" ,"download_progress":"' + ) + result += ( + f'{round(value["down_byte"] / value["total_size"] * 100, 1)}' + + '" ,"download_speed":"' + + download_speed + + '" ,"save_path":"' + + value["file_name"].replace("\\", "/") + + '"}' + ) + + result += "]" + return result diff --git a/src/parsers/Telegram/telegram_media_downloader/mypy.ini b/src/parsers/Telegram/telegram_media_downloader/mypy.ini new file mode 100644 index 0000000..f96d433 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/mypy.ini @@ -0,0 +1,8 @@ +[mypy] +warn_return_any = True + +[mypy-yaml.*] +ignore_missing_imports = True + +[mypy-tests.*] +ignore_errors = True diff --git a/src/parsers/Telegram/telegram_media_downloader/pylintrc b/src/parsers/Telegram/telegram_media_downloader/pylintrc new file mode 100644 index 0000000..14a68cb --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/pylintrc @@ -0,0 +1,509 @@ +# pylint-version: 2.2 + +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist= + pycurl, + cdecimal, + + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS .git + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=no + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable= + locally-disabled, + file-ignored, + fixme, + useless-object-inheritance, + + redefined-variable-type, + redefined-argument-from-local, + wrong-import-position, + consider-using-ternary, + redefined-outer-name, + + invalid-name, + bad-continuation, + import-error, + broad-except, + + unspecified-encoding, + + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=no + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, XXX, TODO + + +[LOGGING] + +# Format style used to check logging format string. `old` means using % +# formatting, while `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package.. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes= + st.config._config._section._unset, + + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=90 + +# Maximum number of lines in a module. +max-module-lines= + 1500 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=(?x) + (_|dummy)$ + + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=(?x) + _|(?:dummy|(?:kw)?args|request|response|context|ctx)$ + + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, bar, baz, toto, tutu, tata + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +const-rgx=(?x)( + ([A-Z_][A-Z0-9_]*) + |(__.*__) + |(.+_)?logger + |(.+_)?predicate + |t_[a-z0-9]+(_[a-z0-9]+)* + |(.*_)?templates + )$ + + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Good variable names which should always be accepted, separated by a comma. +good-names= + _, j, db, e, fd, fp, + + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=(?x)( + __.*__ + |test_.* + |.+Test + |render_.+ + |repeat_.+ + |(?:Pre)?Render + )$ + + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules=regsub, TERMIOS, Bastion, rexec + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods= + __init__, + __new__, + setUp, + + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, _fields, _replace, _source, _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method. +max-args=10 + +# Maximum number of attributes for a class (see R0902). +max-attributes=8 + +# Maximum number of boolean expressions in an if statement. +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=13 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception". +overgeneral-exceptions=Exception diff --git a/src/parsers/Telegram/telegram_media_downloader/requirements.txt b/src/parsers/Telegram/telegram_media_downloader/requirements.txt new file mode 100644 index 0000000..e24b31e --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/requirements.txt @@ -0,0 +1,14 @@ +#https://github.com/tangyoha/pyrogram/archive/refs/tags/v2.0.69.zip +#pyrogram==2.0.106 +https://github.com/tangyoha/pyrogram/archive/refs/heads/master_v2.0.69_1.zip +PyYAML==5.3.1 +rich==12.5.1 +TgCrypto==1.2.5 +loguru==0.6.0 +# aligo==5.4.0 +Werkzeug==2.2.2 +flask==2.2.2 +ply==3.11 +ruamel.yaml==0.17.21 +flask-login==0.6.2 +pycryptodome==3.18.0 diff --git a/src/parsers/Telegram/telegram_media_downloader/screenshot/alipay.JPG b/src/parsers/Telegram/telegram_media_downloader/screenshot/alipay.JPG new file mode 100644 index 0000000000000000000000000000000000000000..e8aa0d9c82f21c1050473f9b8a890f020c1b153b GIT binary patch literal 226914 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 YAOB{N{?}L8zgeXJx`O^Q=YP-tH@jkFxc~qF literal 0 HcmV?d00001 diff --git a/src/parsers/Telegram/telegram_media_downloader/screenshot/bot.gif b/src/parsers/Telegram/telegram_media_downloader/screenshot/bot.gif new file mode 100644 index 0000000000000000000000000000000000000000..770e2d9fba4387a984aab40239aed984a97690d8 GIT binary patch literal 73374 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 i*6983%= {message_id} && id < {int(message_id) + 1}" + config["chat"][0]['last_read_message_id'] = int(message_id) + with open( + os.path.join(os.path.abspath(""), "src/parsers/Telegram/telegram_media_downloader/config.yaml"), + mode="w+", encoding="utf-8" + ) as f: + YAML().dump(config, f) + if _check_config(): + main() diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/__init__.py b/src/parsers/Telegram/telegram_media_downloader/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/module/__init__.py b/src/parsers/Telegram/telegram_media_downloader/tests/module/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/module/test_app.py b/src/parsers/Telegram/telegram_media_downloader/tests/module/test_app.py new file mode 100644 index 0000000..b0da21f --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/module/test_app.py @@ -0,0 +1,63 @@ +"""test app""" + +import os +import sys +import unittest +from unittest import mock + +import module.app +from module.app import Application, ChatDownloadConfig + +sys.path.append("..") # Adds higher directory to python modules path. + + +class AppTestCase(unittest.TestCase): + @classmethod + def tearDownClass(cls): + config_test = os.path.join(os.path.abspath(""), "config_test.yaml") + data_test = os.path.join(os.path.abspath(""), "data_test.yaml") + if os.path.exists(config_test): + os.remove(config_test) + if os.path.exists(data_test): + os.remove(data_test) + + def test_app(self): + app = Application("", "") + self.assertEqual(app.save_path, os.path.join(os.path.abspath(""), "downloads")) + self.assertEqual(app.proxy, {}) + self.assertEqual(app.restart_program, False) + + app.chat_download_config[123] = ChatDownloadConfig() + app.chat_download_config[123].last_read_message_id = 13 + app.chat_download_config[123].failed_ids.append(6) + app.chat_download_config[123].ids_to_retry.append(7) + # download success + app.chat_download_config[123].downloaded_ids.append(8) + app.chat_download_config[123].finish_task += 1 + # download success + app.chat_download_config[123].downloaded_ids.append(10) + app.chat_download_config[123].finish_task += 1 + # not exist message + app.chat_download_config[123].downloaded_ids.append(13) + app.config["chat"] = [{"chat_id": 123, "last_read_message_id": 5}] + + app.update_config(False) + + self.assertEqual( + app.chat_download_config[123].last_read_message_id + 1, + app.config["chat"][0]["last_read_message_id"], + ) + self.assertEqual( + [5, 6, 7, 9, 11, 12], + app.app_data["chat"][0]["ids_to_retry"], + ) + + @mock.patch("__main__.__builtins__.open", new_callable=mock.mock_open) + @mock.patch("module.app.yaml", autospec=True) + def test_update_config(self, mock_yaml, mock_open): + app = Application("", "") + app.config_file = "config_test.yaml" + app.app_data_file = "data_test.yaml" + app.config["chat"] = [{"chat_id": 123, "last_read_message_id": 0}] + app.update_config() + mock_open.assert_called_with("data_test.yaml", "w", encoding="utf-8") diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/test_common.py b/src/parsers/Telegram/telegram_media_downloader/tests/test_common.py new file mode 100644 index 0000000..e0fea42 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/test_common.py @@ -0,0 +1,202 @@ +import datetime +import platform + +from pyrogram.file_id import PHOTO_TYPES, FileType + + +class Chat: + def __init__(self, chat_id, chat_title): + self.id = chat_id + self.title = chat_title + + +class Date: + def __init__(self, date): + self.date = date + + def strftime(self, str) -> str: + return "" + + +class MockMessage: + def __init__(self, **kwargs): + self.id = kwargs.get("id") + self.media = kwargs.get("media") + self.audio = kwargs.get("audio", None) + self.document = kwargs.get("document", None) + self.photo = kwargs.get("photo", None) + self.video = kwargs.get("video", None) + self.voice = kwargs.get("voice", None) + self.video_note = kwargs.get("video_note", None) + self.media_group_id = kwargs.get("media_group_id", None) + self.caption = kwargs.get("caption", None) + self.text = None + self.empty = kwargs.get("empty", False) + self.from_user = kwargs.get("from_user", None) + self.reply_to_message_id = kwargs.get("reply_to_message_id", None) + + if kwargs.get("dis_chat") == None: + self.chat = Chat( + kwargs.get("chat_id", None), kwargs.get("chat_title", None) + ) + else: + self.chat = None + self.date: datetime = None + if kwargs.get("date") != None: + self.date = kwargs["date"] + + +class MockUser: + def __init__(self, **kwargs): + self.id = kwargs.get("id", 0) + self.username = kwargs.get("username", "") + + +class MockAudio: + def __init__(self, **kwargs): + self.file_name = kwargs["file_name"] + self.mime_type = kwargs["mime_type"] + self.file_id = "AUDIO" + if kwargs.get("file_size"): + self.file_size = kwargs["file_size"] + else: + self.file_size = 1024 + + +class MockDocument: + def __init__(self, **kwargs): + self.file_name = kwargs["file_name"] + self.mime_type = kwargs["mime_type"] + self.file_id = "DOCUMENT" + if kwargs.get("file_size"): + self.file_size = kwargs["file_size"] + else: + self.file_size = 1024 + + +class MockPhoto: + def __init__(self, **kwargs): + self.date = kwargs["date"] + self.file_unique_id = kwargs["file_unique_id"] + self.file_id = "PHOTO" + if kwargs.get("file_size"): + self.file_size = kwargs["file_size"] + else: + self.file_size = 1024 + + +class MockVoice: + def __init__(self, **kwargs): + self.mime_type = kwargs["mime_type"] + self.date = kwargs["date"] + self.file_id = "VOICE" + if kwargs.get("file_size"): + self.file_size = kwargs["file_size"] + else: + self.file_size = 1024 + + +class MockVideo: + def __init__(self, **kwargs): + self.file_name = kwargs.get("file_name") + self.mime_type = kwargs["mime_type"] + self.file_id = "VIDEO" + if kwargs.get("file_size"): + self.file_size = kwargs["file_size"] + else: + self.file_size = 1024 + + if kwargs.get("width"): + self.width = kwargs["width"] + else: + self.width = 1920 + + if kwargs.get("height"): + self.height = kwargs["height"] + else: + self.height = 1080 + + if kwargs.get("duration"): + self.duration = kwargs["duration"] + else: + self.duration = 1024 + + +class MockVideoNote: + def __init__(self, **kwargs): + self.mime_type = kwargs["mime_type"] + self.file_id = "VIDEO_NOTE" + self.date = kwargs["date"] + + +def platform_generic_path(_path: str) -> str: + platform_specific_path: str = _path + if platform.system() == "Windows": + platform_specific_path = platform_specific_path.replace("/", "\\") + return platform_specific_path + + +def get_file_type(file_id: str): + if file_id == "THUMBNAIL": + return FileType.THUMBNAIL + elif file_id == "CHAT_PHOTO": + return FileType.CHAT_PHOTO + elif file_id == "PHOTO": + return FileType.PHOTO + elif file_id == "VOICE": + return FileType.VOICE + elif file_id == "VIDEO": + return FileType.VIDEO + elif file_id == "DOCUMENT": + return FileType.DOCUMENT + elif file_id == "ENCRYPTED": + return FileType.ENCRYPTED + elif file_id == "TEMP": + return FileType.TEMP + elif file_id == "STICKER": + return FileType.STICKER + elif file_id == "AUDIO": + return FileType.AUDIO + elif file_id == "ANIMATION": + return FileType.ANIMATION + elif file_id == "ENCRYPTED_THUMBNAIL": + return FileType.ENCRYPTED_THUMBNAIL + elif file_id == "WALLPAPER": + return FileType.WALLPAPER + elif file_id == "VIDEO_NOTE": + return FileType.VIDEO_NOTE + elif file_id == "SECURE_RAW": + return FileType.SECURE_RAW + elif file_id == "SECURE": + return FileType.SECURE + elif file_id == "BACKGROUND": + return FileType.BACKGROUND + elif file_id == "DOCUMENT_AS_FILE": + return FileType.DOCUMENT_AS_FILE + + raise ValueError("error file id!") + + +def get_extension(file_id: str, mime_type: str, dot: bool = True): + file_type = get_file_type(file_id=file_id) + guessed_extension = "" + + if file_type in PHOTO_TYPES: + extension = "jpg" + elif file_type == FileType.VOICE: + extension = guessed_extension or "ogg" + elif file_type in (FileType.VIDEO, FileType.ANIMATION, FileType.VIDEO_NOTE): + extension = guessed_extension or "mp4" + elif file_type == FileType.DOCUMENT: + extension = guessed_extension or "zip" + elif file_type == FileType.STICKER: + extension = guessed_extension or "webp" + elif file_type == FileType.AUDIO: + extension = guessed_extension or "mp3" + else: + extension = "unknown" + + if dot: + extension = "." + extension + + return extension diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/test_media_downloader.py b/src/parsers/Telegram/telegram_media_downloader/tests/test_media_downloader.py new file mode 100644 index 0000000..36f133d --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/test_media_downloader.py @@ -0,0 +1,1083 @@ +"""Unittest module for media downloader.""" +import asyncio +import os +import platform +import queue +import sys +import unittest +from datetime import datetime +from typing import List, Union + +import mock +import pyrogram + +from media_downloader import ( + _can_download, + _check_config, + _get_media_meta, + _is_exist, + app, + download_all_chat, + download_media, + download_task, + main, + worker, +) +from module.app import Application, DownloadStatus, TaskNode +from module.cloud_drive import CloudDriveConfig +from module.pyrogram_extension import ( + get_extension, + record_download_status, + reset_download_cache, +) + +from .test_common import ( + Chat, + Date, + MockAudio, + MockDocument, + MockMessage, + MockPhoto, + MockVideo, + MockVideoNote, + MockVoice, + get_extension, + platform_generic_path, +) + +MOCK_DIR: str = "/root/project" +if platform.system() == "Windows": + MOCK_DIR = "\\root\\project" +MOCK_CONF = { + "api_id": 123, + "api_hash": "hasw5Tgawsuj67", + "chat": [{"chat_id": 8654123, "last_read_message_id": 0, "ids_to_retry": [1, 2]}], + "media_types": ["audio", "voice", "document", "photo", "video", "video_note"], + "file_formats": {"audio": ["all"], "voice": ["all"], "video": ["all"]}, + "save_path": MOCK_DIR, + "file_name_prefix": ["message_id", "caption", "file_name"], +} + +event_str = "asyncio.AbstractEventLoop.run_forever" +if sys.version_info > (3, 8): + event_str = "asyncio.ProactorEventLoop.run_forever" + + +def os_remove(_: str): + pass + + +def is_exist(file: str): + if os.path.basename(file).find("313 - sucess_exist_down.mp4") != -1: + return True + elif os.path.basename(file).find("422 - exception.mov") != -1: + raise Exception + return False + + +def os_get_file_size(file: str) -> int: + if os.path.basename(file).find("311 - failed_down.mp4") != -1: + return 0 + elif os.path.basename(file).find("312 - sucess_down.mp4") != -1: + return 1024 + elif os.path.basename(file).find("313 - sucess_exist_down.mp4") != -1: + return 1024 + return 0 + + +def new_set_download_id( + chat_id: Union[int, str], message_id: int, download_status: DownloadStatus +): + if download_status is DownloadStatus.SuccessDownload: + app.total_download_task += 1 + if chat_id not in app.chat_download_config: + return + app.chat_download_config[chat_id].last_read_message_id = max( + app.chat_download_config[chat_id].last_read_message_id, message_id + ) + if download_status is not DownloadStatus.FailedDownload: + app.chat_download_config[chat_id].downloaded_ids.append(message_id) + else: + app.chat_download_config[chat_id].failed_ids.append(message_id) + app.is_running = False + + +def rest_app(conf: dict): + config_test = os.path.join(os.path.abspath(""), "config_test.yaml") + data_test = os.path.join(os.path.abspath(""), "data_test.yaml") + if os.path.exists(config_test): + os.remove(config_test) + if os.path.exists(data_test): + os.remove(data_test) + app.total_download_task = 0 + app.is_running = True + app.chat_download_config: dict = {} + # app.already_download_ids_set = set() + app.disable_syslog: list = [] + app.save_path = os.path.abspath("") + app.api_id: str = "" + app.api_hash: str = "" + app.media_types: List[str] = [] + app.file_formats: dict = {} + app.proxy: dict = {} + app.restart_program = False + app.config: dict = {} + app.app_data: dict = {} + app.file_path_prefix: List[str] = ["chat_title", "media_datetime"] + app.file_name_prefix: List[str] = ["message_id", "file_name"] + app.file_name_prefix_split: str = " - " + app.log_file_path = os.path.join(os.path.abspath(""), "log") + app.cloud_drive_config = CloudDriveConfig() + app.hide_file_name = False + app.caption_name_dict: dict = {} + app.max_concurrent_transmissions: int = 1 + app.web_host: str = "localhost" + app.web_port: int = 5000 + app.config_file = "config_test.yaml" + app.app_data_file = "data_test.yaml" + app.config = conf + app.assign_config(conf) + app.assign_app_data(conf) + + +def mock_manage_duplicate_file(file_path: str) -> str: + return file_path + + +def raise_keyboard_interrupt(): + raise KeyboardInterrupt + + +async def new_upload_telegram_chat( + client: pyrogram.Client, + upload_user: pyrogram.Client, + app: Application, + node: TaskNode, + message: pyrogram.types.Message, + file_name: str, + download_status: DownloadStatus, +): + pass + + +def raise_exception(): + raise Exception + + +def load_config(): + raise ValueError("error load config") + + +class MyQueue: + def __init__(self, queue_list_obj): + self._queue = queue.Queue() + for item in queue_list_obj: + self._queue.put(item) + + async def get(self): + if self._queue.empty(): + raise Exception + return self._queue.get() + + +class MockEventLoop: + def __init__(self): + pass + + def run_until_complete(self, *args, **kwargs): + return {"api_id": 1, "api_hash": "asdf", "ids_to_retry": [1, 2, 3]} + + +class MockAsync: + def __init__(self): + pass + + def get_event_loop(self): + return MockEventLoop() + + +async def async_get_media_meta(chat_id, message, message_media, _type): + result = await _get_media_meta(chat_id, message, message_media, _type) + return result + + +async def async_download_media( + client, message, media_types, file_formats, chat_id=-123 +): + return await download_media(client, message, media_types, file_formats, chat_id) + + +def mock_move_to_download_path(temp_download_path: str, download_path: str): + pass + + +def mock_check_download_finish(media_size: int, download_path: str, ui_file_name: str): + pass + + +async def new_fetch_message(client: pyrogram.Client, message: pyrogram.types.Message): + return message + + +async def get_chat_history(client, *args, **kwargs): + items = [ + MockMessage( + id=1213, + media=True, + voice=MockVoice( + mime_type="audio/ogg", + date=datetime(2019, 7, 25, 14, 53, 50), + ), + ), + MockMessage( + id=1214, + media=False, + text="test message 1", + ), + MockMessage( + id=1215, + media=False, + text="test message 2", + ), + MockMessage( + id=1216, + media=False, + text="test message 3", + ), + ] + for item in items: + yield item + + +class MockClient: + def __init__(self, *args, **kwargs): + pass + + def __aiter__(self): + return self + + async def start(self): + pass + + async def stop(self): + pass + + async def get_messages(self, *args, **kwargs): + if kwargs["message_ids"] == 7: + return MockMessage( + id=7, + media=True, + chat_id=123456, + chat_title="123456", + date=datetime.now(), + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + elif kwargs["message_ids"] == 8: + return MockMessage( + id=8, + media=True, + chat_id=234567, + chat_title="234567", + date=datetime.now(), + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + elif kwargs["message_ids"] == [1, 2]: + return [ + MockMessage( + id=1, + media=True, + chat_id=234568, + chat_title="234568", + date=datetime.now(), + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ), + MockMessage( + id=2, + media=True, + chat_id=234568, + chat_title="234568", + date=datetime.now(), + video=MockVideo( + file_name="sample_video2.mov", + mime_type="video/mov", + ), + ), + ] + elif kwargs["message_ids"] == 313: + return MockMessage( + id=313, + media=True, + video=MockVideo( + file_name="sucess_exist_down.mp4", + mime_type="video/mp4", + file_size=1024, + ), + ) + elif kwargs["message_ids"] == 312: + return MockMessage( + id=312, + media=True, + video=MockVideo( + file_name="sucess_down.mp4", + mime_type="video/mp4", + file_size=1024, + ), + ) + elif kwargs["message_ids"] == 311: + return MockMessage( + id=311, + media=True, + video=MockVideo( + file_name="failed_down.mp4", + mime_type="video/mp4", + file_size=1024, + ), + ) + return [] + + async def download_media(self, *args, **kwargs): + mock_message = args[0] + if mock_message.id in [7, 8]: + raise pyrogram.errors.exceptions.bad_request_400.BadRequest + elif mock_message.id == 9: + raise pyrogram.errors.exceptions.unauthorized_401.Unauthorized + elif mock_message.id == 11: + raise TypeError + elif mock_message.id == 420: + raise pyrogram.errors.exceptions.flood_420.FloodWait(value=420) + elif mock_message.id == 421: + raise Exception + return kwargs["file_name"] + + async def edit_message_text(self, *args, **kwargs): + return True + + +def check_for_updates(): + pass + + +@mock.patch("media_downloader.get_extension", new=get_extension) +@mock.patch("module.pyrogram_extension.get_extension", new=get_extension) +@mock.patch("media_downloader.fetch_message", new=new_fetch_message) +@mock.patch("media_downloader.get_chat_history_v2", new=get_chat_history) +@mock.patch("media_downloader.RETRY_TIME_OUT", new=0) +@mock.patch("media_downloader.check_for_updates", new=check_for_updates) +class MediaDownloaderTestCase(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.loop = asyncio.get_event_loop() + rest_app(MOCK_CONF) + + # @mock.patch("media_downloader.app.save_path", new=MOCK_DIR) + def test_get_media_meta(self): + rest_app(MOCK_CONF) + app.save_path = MOCK_DIR + # Test Voice notes + message = MockMessage( + id=1, + media=True, + chat_title="test1", + date=datetime(2019, 7, 25, 14, 53, 50), + voice=MockVoice( + mime_type="audio/ogg", + date=datetime(2019, 7, 25, 14, 53, 50), + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.voice, "voice") + ) + + self.assertEqual( + ( + platform_generic_path( + "/root/project/test1/2019_07/1 - voice_2019-07-25T14_53_50.ogg" + ), + platform_generic_path( + os.path.join( + app.temp_save_path, "test1/1 - voice_2019-07-25T14_53_50.ogg" + ) + ), + "ogg", + ), + result, + ) + + # Test photos + message = MockMessage( + id=2, + media=True, + date=datetime(2019, 8, 5, 14, 35, 12), + chat_title="test2", + photo=MockPhoto( + date=datetime(2019, 8, 5, 14, 35, 12), file_unique_id="ADAVKJYIFV" + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.photo, "photo") + ) + self.assertEqual( + ( + platform_generic_path("/root/project/test2/2019_08/2 - ADAVKJYIFV.jpg"), + platform_generic_path( + os.path.join(app.temp_save_path, "test2/2 - ADAVKJYIFV.jpg") + ), + None, + ), + result, + ) + + message = MockMessage( + id=2, + media=True, + date=datetime(2019, 8, 5, 14, 35, 12), + chat_title="test2", + media_group_id="AAA213213", + caption="#home #book", + photo=MockPhoto( + date=datetime(2019, 8, 5, 14, 35, 12), file_unique_id="ADAVKJYIFV" + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.photo, "photo") + ) + self.assertEqual( + ( + platform_generic_path( + "/root/project/test2/2019_08/2 - #home #book - ADAVKJYIFV.jpg" + ), + platform_generic_path( + os.path.join( + app.temp_save_path, "test2/2 - #home #book - ADAVKJYIFV.jpg" + ) + ), + None, + ), + result, + ) + + # Test Documents + message = MockMessage( + id=3, + media=True, + chat_title="test2", + document=MockDocument( + file_name="sample_document.pdf", + mime_type="application/pdf", + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.document, "document") + ) + self.assertEqual( + ( + platform_generic_path("/root/project/test2/0/3 - sample_document.pdf"), + platform_generic_path( + os.path.join(app.temp_save_path, "test2/3 - sample_document.pdf") + ), + "pdf", + ), + result, + ) + + before_file_name_prefix_split = app.file_name_prefix_split + app.file_name_prefix_split = "-" + + message = MockMessage( + id=3, + media=True, + chat_title="test2", + media_group_id="BBB213213", + caption="#work", + document=MockDocument( + file_name="sample_document.pdf", + mime_type="application/pdf", + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.document, "document") + ) + self.assertEqual( + ( + platform_generic_path( + "/root/project/test2/0/3-#work-sample_document.pdf" + ), + platform_generic_path( + os.path.join( + app.temp_save_path, "test2/3-#work-sample_document.pdf" + ) + ), + "pdf", + ), + result, + ) + + app.file_name_prefix_split = before_file_name_prefix_split + # Test audio + message = MockMessage( + id=4, + media=True, + date=datetime(2021, 8, 5, 14, 35, 12), + chat_title="test2", + audio=MockAudio( + file_name="sample_audio.mp3", + mime_type="audio/mp3", + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.audio, "audio") + ) + self.assertEqual( + ( + platform_generic_path( + "/root/project/test2/2021_08/4 - sample_audio.mp3" + ), + platform_generic_path( + os.path.join(app.temp_save_path, "test2/4 - sample_audio.mp3") + ), + "mp3", + ), + result, + ) + + # Test Video 1 + message = MockMessage( + id=5, + media=True, + date=datetime(2022, 8, 5, 14, 35, 12), + chat_title="test2", + video=MockVideo( + mime_type="video/mp4", + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.video, "video") + ) + self.assertEqual( + ( + platform_generic_path("/root/project/test2/2022_08/5.mp4"), + platform_generic_path(os.path.join(app.temp_save_path, "test2/5.mp4")), + "mp4", + ), + result, + ) + + # Test Video 2 + message = MockMessage( + id=5, + media=True, + date=datetime(2022, 8, 5, 14, 35, 12), + chat_title="test2", + video=MockVideo( + file_name="test.mp4", + mime_type="video/mp4", + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.video, "video") + ) + self.assertEqual( + ( + platform_generic_path("/root/project/test2/2022_08/5 - test.mp4"), + platform_generic_path( + os.path.join(app.temp_save_path, "test2/5 - test.mp4") + ), + "mp4", + ), + result, + ) + + # Test Video 3: not exist chat_title + message = MockMessage( + id=5, + media=True, + dis_chat=True, + date=datetime(2022, 8, 5, 14, 35, 12), + video=MockVideo( + file_name="test.mp4", + mime_type="video/mp4", + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.video, "video") + ) + + self.assertEqual( + ( + platform_generic_path("/root/project/-123/2022_08/5 - test.mp4"), + platform_generic_path( + os.path.join(app.temp_save_path, "-123/5 - test.mp4") + ), + "mp4", + ), + result, + ) + + # Test VideoNote + message = MockMessage( + id=6, + media=True, + date=datetime(2019, 7, 25, 14, 53, 50), + chat_title="test2", + video_note=MockVideoNote( + mime_type="video/mp4", + date=datetime(2019, 7, 25, 14, 53, 50), + ), + ) + result = self.loop.run_until_complete( + async_get_media_meta(-123, message, message.video_note, "video_note") + ) + self.assertEqual( + ( + platform_generic_path( + "/root/project/test2/2019_07/6 - video_note_2019-07-25T14_53_50.mp4" + ), + platform_generic_path( + os.path.join( + app.temp_save_path, + "test2/6 - video_note_2019-07-25T14_53_50.mp4", + ) + ), + "mp4", + ), + result, + ) + + @mock.patch("media_downloader.app.save_path", new=MOCK_DIR) + @mock.patch("media_downloader.asyncio.sleep", return_value=None) + @mock.patch("media_downloader.logger") + @mock.patch("media_downloader._is_exist", new=is_exist) + @mock.patch( + "media_downloader._move_to_download_path", new=mock_move_to_download_path + ) + @mock.patch( + "media_downloader._check_download_finish", new=mock_check_download_finish + ) + def test_download_media(self, mock_logger, patch_sleep): + reset_download_cache() + rest_app(MOCK_CONF) + client = MockClient() + app.hide_file_name = True + message = MockMessage( + id=5, + media=True, + video=MockVideo( + file_name="sample_video.mp4", + mime_type="video/mp4", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["mp4"]}, -123 + ) + ) + self.assertEqual( + ( + DownloadStatus.SuccessDownload, + platform_generic_path("/root/project/-123/0/5 - sample_video.mp4"), + ), + result, + ) + + message = MockMessage( + id=6, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual( + ( + DownloadStatus.SuccessDownload, + platform_generic_path("/root/project/-123/0/6 - sample_video.mov"), + ), + result, + ) + + # Test re-fetch message success + message = MockMessage( + id=7, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + mock_logger.warning.assert_called_with( + "Message[7]: file reference expired, refetching..." + ) + + # Test re-fetch message failure + message = MockMessage( + id=8, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + mock_logger.error.assert_called_with( + "Message[8]: file reference expired for 3 retries, download skipped." + ) + + # Test other exception + message = MockMessage( + id=9, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + + # Check no media + message = MockMessage( + id=10, + media=None, + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.SkipDownload, None), result) + + # Test timeout + message = MockMessage( + id=11, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + mock_logger.error.assert_called_with( + "Message[11]: Timing out after 3 reties, download skipped." + ) + + # Test file name with out suffix + message = MockMessage( + id=12, + media=True, + video=MockVideo( + file_name="sample_video", + mime_type="video/mp4", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual( + ( + DownloadStatus.SuccessDownload, + platform_generic_path("/root/project/-123/0/12 - sample_video.mp4"), + ), + result, + ) + + # Test FloodWait 420 + message = MockMessage( + id=420, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + mock_logger.warning.assert_called_with("Message[{}]: FlowWait {}", 420, 420) + + # Test other Exception + message = MockMessage( + id=421, + media=True, + video=MockVideo( + file_name="sample_video.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + + # Test other Exception + message = MockMessage( + id=422, + media=True, + video=MockVideo( + file_name="422 - exception.mov", + mime_type="video/mov", + ), + ) + result = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["all"]} + ) + ) + self.assertEqual((DownloadStatus.FailedDownload, None), result) + + @mock.patch("media_downloader.pyrogram.Client", new=MockClient) + @mock.patch("media_downloader.asyncio.Queue.put") + def test_download_task(self, moc_put): + rest_app(MOCK_CONF) + client = MockClient() + app.chat_download_config[8654123].download_filter = "id != 1213" + self.loop.run_until_complete(download_all_chat(client)) + moc_put.assert_called() + + def test_can_download(self): + file_formats = { + "audio": ["mp3"], + "video": ["mp4"], + "document": ["all"], + } + result = _can_download("audio", file_formats, "mp3") + self.assertEqual(result, True) + + result1 = _can_download("audio", file_formats, "ogg") + self.assertEqual(result1, False) + + result2 = _can_download("document", file_formats, "pdf") + self.assertEqual(result2, True) + + result3 = _can_download("document", file_formats, "epub") + self.assertEqual(result3, True) + + def test_is_exist(self): + this_dir = os.path.dirname(os.path.abspath(__file__)) + result = _is_exist(os.path.join(this_dir, "__init__.py")) + self.assertEqual(result, True) + + result1 = _is_exist(os.path.join(this_dir, "init.py")) + self.assertEqual(result1, False) + + result2 = _is_exist(this_dir) + self.assertEqual(result2, False) + + @mock.patch("media_downloader.RETRY_TIME_OUT", new=0) + @mock.patch("media_downloader.os.path.getsize", new=os_get_file_size) + @mock.patch("media_downloader.os.remove", new=os_remove) + @mock.patch("media_downloader._is_exist", new=is_exist) + @mock.patch( + "media_downloader._move_to_download_path", new=mock_move_to_download_path + ) + def test_issues_311(self): + # see https://github.com/Dineshkarthik/telegram_media_downloader/issues/311 + rest_app(MOCK_CONF) + + client = MockClient() + # 1. test `TimeOutError` + message = MockMessage( + id=311, + media=True, + video=MockVideo( + file_name="failed_down.mp4", + mime_type="video/mp4", + file_size=1024, + ), + ) + + media_size = getattr(message.video, "file_size") + self.assertEqual(media_size, 1024) + + res = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["mp4"]} + ) + ) + self.assertEqual(res, (DownloadStatus.FailedDownload, None)) + + # 2. test sucess download + rest_app(MOCK_CONF) + message = MockMessage( + id=312, + media=True, + video=MockVideo( + file_name="sucess_down.mp4", + mime_type="video/mp4", + file_size=1024, + ), + ) + + res = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["mp4"]} + ) + ) + + self.assertEqual( + res, + ( + DownloadStatus.SuccessDownload, + platform_generic_path("/root/project/-123/0/312 - sucess_down.mp4"), + ), + ) + + rest_app(MOCK_CONF) + # 3. test already download + message = MockMessage( + id=313, + media=True, + video=MockVideo( + file_name="sucess_exist_down.mp4", + mime_type="video/mp4", + file_size=1024, + ), + ) + + res = self.loop.run_until_complete( + async_download_media( + client, message, ["video", "photo"], {"video": ["mp4"]} + ) + ) + + self.assertEqual(res, (DownloadStatus.SkipDownload, None)) + + @mock.patch("media_downloader.pyrogram.Client", new=MockClient) + @mock.patch("media_downloader.RETRY_TIME_OUT", new=1) + @mock.patch("media_downloader.logger") + def test_main_with_bot(self, mock_logger): + rest_app(MOCK_CONF) + + main() + + mock_logger.success.assert_called_with( + "Updated last read message_id to config file,total download 0, total upload file 0" + ) + + @mock.patch("media_downloader.app.pre_run", new=raise_keyboard_interrupt) + @mock.patch("media_downloader.pyrogram.Client", new=MockClient) + @mock.patch("media_downloader.RETRY_TIME_OUT", new=1) + @mock.patch("media_downloader.logger") + def test_keyboard_interrupt(self, mock_logger): + rest_app(MOCK_CONF) + + main() + + mock_logger.info.assert_any_call("KeyboardInterrupt") + mock_logger.success.assert_called_with( + "Updated last read message_id to config file,total download 0, total upload file 0" + ) + + @mock.patch("media_downloader.app.pre_run", new=raise_exception) + @mock.patch("media_downloader.pyrogram.Client", new=MockClient) + @mock.patch("media_downloader.RETRY_TIME_OUT", new=1) + @mock.patch("media_downloader.logger") + def test_other_exception(self, mock_logger): + rest_app(MOCK_CONF) + + main() + + mock_logger.success.assert_called_with( + "Updated last read message_id to config file,total download 0, total upload file 0" + ) + + @mock.patch("media_downloader._load_config", new=load_config) + @mock.patch("media_downloader.logger") + def test_check_config(self, mock_logger): + _check_config() + mock_logger.exception.assert_called_with("load config error: error load config") + + def test_check_config_suc(self): + app.update_config() + self.assertEqual(_check_config(), True) + + # @mock.patch( + # "media_downloader.queue", + # new=MyQueue( + # [ + # ( + # MockMessage( + # id=312, + # media=True, + # chat_id=8654123, + # chat_title="8654123", + # video=MockVideo( + # file_name="sucess_down.mp4", + # mime_type="video/mp4", + # file_size=1024, + # ), + # ), + # TaskNode(chat_id=8654123, upload_telegram_chat_id=123456), + # ), + # ( + # MockMessage( + # id=333, + # media=True, + # chat_id=8654123, + # chat_title="8654123", + # text="123", + # ), + # TaskNode(chat_id=8654123, upload_telegram_chat_id=123456), + # ), + # ] + # ), + # ) + # @mock.patch("media_downloader.app.set_download_id", new=new_set_download_id) + # @mock.patch("media_downloader.upload_telegram_chat", new=new_upload_telegram_chat) + # @mock.patch("media_downloader.os.remove") + # @mock.patch( + # "media_downloader._move_to_download_path", new=mock_move_to_download_path + # ) + # @mock.patch("media_downloader.os.path.getsize", new=os_get_file_size) + # def test_upload_telegram_chat(self, mock_remove): + # rest_app(MOCK_CONF) + # client = MockClient() + # app.chat_download_config[8654123].last_read_message_id = 0 + # self.loop.run_until_complete(worker(client)) + # mock_remove.assert_called_with( + # platform_generic_path("/root/project/8654123/0/312 - sucess_down.mp4") + # ) + + @classmethod + def tearDownClass(cls): + cls.loop.close() diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/__init__.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_cypto.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_cypto.py new file mode 100644 index 0000000..4b87099 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_cypto.py @@ -0,0 +1,55 @@ +"""Test Crypto""" + +import sys +import unittest + +from utils.crypto import AesBase64 + +sys.path.append("..") # Adds higher directory to python modules path. + + +class TestAesBase64(unittest.TestCase): + def test_aes_base64_encryption(self): + key = "This is a key123" + iv = "This is an iv456" + aes = AesBase64(key, iv) + content = "Some text for encryption." + encrypted_content = aes.encrypt(content) + decrypted_content = aes.decrypt(encrypted_content) + self.assertEqual(content, decrypted_content) + + def test_aes_base64_encryption_with_special_characters(self): + key = "Special!@#$%^&*(" + iv = "Characters123456" + aes = AesBase64(key, iv) + content = "Text with special characters!@#$%^&*()_+-=[]{}|;" + encrypted_content = aes.encrypt(content) + decrypted_content = aes.decrypt(encrypted_content) + self.assertEqual(content, decrypted_content) + + def test_aes_base64_encryption_with_empty_string(self): + key = "Empty string tes" + iv = "1234567890123456" + aes = AesBase64(key, iv) + content = "" + encrypted_content = aes.encrypt(content) + decrypted_content = aes.decrypt(encrypted_content) + self.assertEqual(content, decrypted_content) + + def test_aes_base64_pkcs7padding(self): + key = "Test padding key" + iv = "1234567890123456" + aes = AesBase64(key, iv) + content = "Test padding." + padded_content = aes.pkcs7padding(content) + self.assertEqual(len(padded_content) % 16, 0) + self.assertEqual(padded_content[-1], chr(16 - len(content) % 16)) + + def test_aes_base64_pkcs7unpadding(self): + key = "Test unpadding key" + iv = "1234567890123456" + aes = AesBase64(key, iv) + content = "Test unpadding." + padded_content = aes.pkcs7padding(content) + unpadded_content = aes.pkcs7unpadding(padded_content) + self.assertEqual(unpadded_content, content) diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_file_management.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_file_management.py new file mode 100644 index 0000000..bf4fc4d --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_file_management.py @@ -0,0 +1,40 @@ +"""Unittest module for media downloader.""" +import os +import sys +import tempfile +import unittest +from pathlib import Path + +import mock + +sys.path.append("..") # Adds higher directory to python modules path. +from utils.file_management import get_next_name, manage_duplicate_file + + +class FileManagementTestCase(unittest.TestCase): + def setUp(self): + self.this_dir = os.path.dirname(os.path.abspath(__file__)) + self.test_file = os.path.join(self.this_dir, "file-test.txt") + self.test_file_copy_1 = os.path.join(self.this_dir, "file-test-copy1.txt") + self.test_file_copy_2 = os.path.join(self.this_dir, "file-test-copy2.txt") + f = open(self.test_file, "w+") + f.write("dummy file") + f.close() + Path(self.test_file_copy_1).touch() + Path(self.test_file_copy_2).touch() + + def test_get_next_name(self): + result = get_next_name(self.test_file) + excepted_result = os.path.join(self.this_dir, "file-test-copy3.txt") + self.assertEqual(result, excepted_result) + + def test_manage_duplicate_file(self): + result = manage_duplicate_file(self.test_file_copy_2) + self.assertEqual(result, self.test_file_copy_1) + + result1 = manage_duplicate_file(self.test_file_copy_1) + self.assertEqual(result1, self.test_file_copy_1) + + def tearDown(self): + os.remove(self.test_file) + os.remove(self.test_file_copy_1) diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_filter.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_filter.py new file mode 100644 index 0000000..454aa54 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_filter.py @@ -0,0 +1,450 @@ +"""Unittest module for media downloader.""" +import sys +import unittest +from datetime import datetime + +import mock + +from module.filter import Filter, MetaData +from module.pyrogram_extension import set_meta_data +from tests.test_common import ( + Chat, + Date, + MockAudio, + MockDocument, + MockMessage, + MockPhoto, + MockUser, + MockVideo, + MockVideoNote, + MockVoice, + get_extension, +) +from utils.format import replace_date_time + +sys.path.append("..") # Adds higher directory to python modules path. + + +def filter_exec(download_filter: Filter, filter_str: str) -> bool: + filter_str = replace_date_time(filter_str) + return download_filter.exec(filter_str) + + +def check_filter_exec(download_filter: Filter, filter_str: str) -> bool: + filter_str = replace_date_time(filter_str) + return download_filter.check_filter(filter_str) + + +@mock.patch("module.pyrogram_extension.get_extension", new=get_extension) +class FilterTestCase(unittest.TestCase): + def test_string_filter(self): + download_filter = Filter() + self.assertRaises(ValueError, filter_exec, download_filter, "213") + + meta = MetaData() + + message = MockMessage( + id=5, + media=True, + date=datetime(2022, 8, 5, 14, 35, 12), + chat_title="test2", + caption=None, + video=MockVideo( + mime_type="video/mp4", + file_size=1024 * 1024 * 10, + file_name="test.mp4", + width=1920, + height=1080, + duration=35, + ), + from_user=MockUser( + username="coco", + id=123, + ), + ) + + set_meta_data(meta, message) + + self.assertEqual(meta.message_id, 5) + self.assertEqual(meta.message_date, datetime(2022, 8, 5, 14, 35, 12)) + self.assertEqual(meta.message_caption, "") + self.assertEqual(meta.media_file_size, 1024 * 1024 * 10) + self.assertEqual(meta.media_width, 1920) + self.assertEqual(meta.media_height, 1080) + self.assertEqual(meta.media_file_name, "test.mp4") + self.assertEqual(meta.media_duration, 35) + self.assertEqual(meta.media_type, "video") + self.assertEqual(meta.file_extension, "mp4") + + download_filter.set_meta_data(meta) + + self.assertEqual(filter_exec(download_filter, "media_file_size == 1"), False) + self.assertEqual(filter_exec(download_filter, "media_file_size > 1024"), True) + + # str + self.assertEqual( + filter_exec(download_filter, "media_file_name == 'test.mp4'"), True + ) + self.assertEqual( + filter_exec(download_filter, "media_file_name == 'test2.mp4'"), False + ) + # re str + self.assertEqual( + filter_exec(download_filter, "media_file_name == r'test.*mp4'"), True + ) + + self.assertEqual( + filter_exec(download_filter, "media_file_name == r'test\.*mp4'"), True + ) + + self.assertEqual( + filter_exec(download_filter, "media_file_name == r'test2.*mp4'"), False + ) + + self.assertEqual( + filter_exec(download_filter, "media_file_name != r'test2.*mp4'"), True + ) + self.assertEqual( + filter_exec(download_filter, "media_file_name != r'test2.*mp4'"), True + ) + + # int + self.assertEqual(filter_exec(download_filter, "media_duration > 60"), False) + self.assertEqual(filter_exec(download_filter, "media_duration <= 60"), True) + self.assertEqual( + filter_exec( + download_filter, "media_width >= 1920 and media_height >= 1080" + ), + True, + ) + self.assertEqual( + filter_exec(download_filter, "media_width >= 2560 && media_height >= 1440"), + False, + ) + self.assertEqual( + filter_exec( + download_filter, + "media_width >= 2560 && media_height >= 1440 or media_file_name == 'test.mp4'", + ), + True, + ) + + # datetime + # 2020.03 + self.assertEqual( + filter_exec( + download_filter, "message_date >= 2022.03 and message_date <= 2022.08" + ), + False, + ) + self.assertEqual( + filter_exec( + download_filter, "message_date >= 2022.03 and message_date <= 2022.09" + ), + True, + ) + + # 2020.03.04 + self.assertEqual( + filter_exec( + download_filter, + "message_date >= 2022.03.04 and message_date <= 2022.03.08", + ), + False, + ) + self.assertEqual( + filter_exec( + download_filter, + "message_date >= 2022.03.04 and message_date <= 2022.08.06", + ), + True, + ) + + # 2020.03.04 14:50 + self.assertEqual( + filter_exec( + download_filter, + "message_date >= 2022.03.04 14:50 and message_date <= 2022.03.08", + ), + False, + ) + self.assertEqual( + filter_exec( + download_filter, + "message_date >= 2022.03.04 and message_date <= 2022.08.05 14:36", + ), + True, + ) + + # 2020.03.04 14:50:15 + self.assertEqual( + filter_exec( + download_filter, + "message_date >= 2022.03.04 14:50:15 and message_date <= 2022.03.08", + ), + False, + ) + self.assertEqual( + filter_exec( + download_filter, + "message_date >= 2022.03.04 14:50:15 and message_date <= 2022.08.05 14:35:12", + ), + True, + ) + + # test not exist value + self.assertRaises( + ValueError, + filter_exec, + download_filter, + "message_date >= 2022.03.04 && message_date <= 2022.08.06 && not_exist == True", + ) + + download_filter.set_debug(True) + + # test file_size + self.assertEqual(filter_exec(download_filter, "file_size >= 10MB"), True) + + self.assertEqual(filter_exec(download_filter, "file_size >= 11MB"), False) + + self.assertEqual(filter_exec(download_filter, "file_size >= 11GB"), False) + + self.assertEqual(filter_exec(download_filter, "file_size <= 11GB"), True) + + self.assertEqual( + filter_exec(download_filter, "1024 * 1024 * 1024 * 11 == 11GB"), True + ) + + # test caption + self.assertEqual(filter_exec(download_filter, "caption == r'.*#test.*'"), False) + + # test media_type + self.assertEqual(filter_exec(download_filter, "media_type == 'video'"), True) + + self.assertEqual(filter_exec(download_filter, "media_type == 'audio'"), False) + + self.assertEqual( + filter_exec(download_filter, "media_type == r'(video|audio)'"), True + ) + + self.assertEqual( + filter_exec(download_filter, "media_type != r'(video|audio)'"), False + ) + + # test file_extension + self.assertEqual(filter_exec(download_filter, "file_extension == 'mp4'"), True) + + self.assertEqual(filter_exec(download_filter, "file_extension == 'mp3'"), False) + + self.assertEqual( + filter_exec(download_filter, "file_extension == r'(mp4|mp3)'"), True + ) + + self.assertEqual( + filter_exec(download_filter, "file_extension != r'(mp4|mp3)'"), False + ) + + # test sender + self.assertEqual(filter_exec(download_filter, "sender_name == 'coco'"), True) + + self.assertEqual(filter_exec(download_filter, "sender_id == 1"), False) + + def test_null_obj(self): + download_filter = Filter() + + meta = MetaData() + + message = MockMessage( + id=5, + media=True, + date=datetime(2022, 8, 5, 14, 35, 12), + chat_title="test2", + caption=None, + video=MockPhoto( + file_size=1024 * 1024 * 10, + date=datetime(2019, 8, 5, 14, 35, 12), + file_unique_id="ADAVKJYIFV", + ), + ) + + set_meta_data(meta, message) + + download_filter.set_meta_data(meta) + + # test media_duration + self.assertEqual(filter_exec(download_filter, "media_duration < 1"), False) + self.assertEqual(filter_exec(download_filter, "media_duration <= 1"), False) + self.assertEqual(filter_exec(download_filter, "media_duration != 1"), False) + self.assertEqual(filter_exec(download_filter, "media_duration == 1"), False) + + def test_str_obj(self): + download_filter = Filter() + self.assertRaises(ValueError, filter_exec, download_filter, "213") + + meta = MetaData() + + message = MockMessage( + id=5, + media=True, + date=datetime(2022, 8, 5, 14, 35, 12), + chat_title="test2", + caption="#中文最吊 #哈啰", + video=MockVideo( + mime_type="video/mp4", + file_size=1024 * 1024 * 10, + file_name="test.mp4", + width=1920, + height=1080, + duration=35, + ), + reply_to_message_id=4, + ) + + set_meta_data(meta, message) + + self.assertEqual(meta.message_id, 5) + self.assertEqual(meta.message_date, datetime(2022, 8, 5, 14, 35, 12)) + self.assertEqual(meta.message_caption, "#中文最吊 #哈啰") + self.assertEqual(meta.media_file_size, 1024 * 1024 * 10) + self.assertEqual(meta.media_width, 1920) + self.assertEqual(meta.media_height, 1080) + self.assertEqual(meta.media_file_name, "test.mp4") + self.assertEqual(meta.media_duration, 35) + + download_filter.set_meta_data(meta) + download_filter.set_debug(True) + + # test caption + self.assertEqual(filter_exec(download_filter, "caption == r'.*#test.*'"), False) + + self.assertEqual(filter_exec(download_filter, "caption == r'.*#中文.*'"), True) + + self.assertEqual(filter_exec(download_filter, "caption == r'.*#中文啊.*'"), False) + + self.assertEqual(filter_exec(download_filter, "reply_to_message_id == 4"), True) + self.assertEqual( + filter_exec(download_filter, "reply_to_message_id != 4"), False + ) + self.assertEqual(filter_exec(download_filter, "reply_to_message_id >= 4"), True) + + def test_check_filter(self): + download_filter = Filter() + meta = MetaData() + + message = MockMessage( + id=5, + media=True, + date=datetime(2022, 8, 5, 14, 35, 12), + chat_title="test2", + caption=None, + video=MockVideo( + mime_type="video/mp4", + file_size=1024 * 1024 * 10, + file_name="test.mp4", + width=1920, + height=1080, + duration=35, + ), + ) + + set_meta_data(meta, message) + + download_filter.set_debug(True) + download_filter.set_meta_data(meta) + + # 1. == + # 1.1 restring + self.assertEqual( + check_filter_exec(download_filter, "caption == rr'.*#中文啊.*'"), + (False, "Syntax error at '.*#中文啊.*'"), + ) + self.assertEqual( + check_filter_exec(download_filter, "caption == r'.*#中文啊.*'"), (True, None) + ) + self.assertEqual( + check_filter_exec(download_filter, "caption tis r'.*#中文啊.*'"), + (False, "Syntax error at 'tis'"), + ) + # 1.2 string + self.assertEqual( + check_filter_exec(download_filter, "caption = '.*#中文啊.*'"), (True, None) + ) + + # 2. check type + # 2.1 str + self.assertEqual( + check_filter_exec(download_filter, "caption = 1"), + (False, "caption is str but 1 is not"), + ) + self.assertEqual( + check_filter_exec(download_filter, "caption = 3KB"), + (False, "caption is str but 3072 is not"), + ) + # 2.2 datetime + self.assertEqual( + check_filter_exec(download_filter, "message_date == '.*#中文啊.*'"), + (False, "2022-08-05 14:35:12 is datetime but .*#中文啊.* is not"), + ) + + # 2.3 int + self.assertEqual( + check_filter_exec(download_filter, "id == '.*'"), + (False, "5 is int but .* is not"), + ) + self.assertEqual( + check_filter_exec(download_filter, "id == .*"), + (False, "Syntax error at '*'"), + ) + self.assertEqual( + check_filter_exec(download_filter, "id == ."), + (False, "Syntax error at EOF"), + ) + self.assertEqual( + check_filter_exec(download_filter, "id == ."), + (False, "Syntax error at EOF"), + ) + # 2.3.1 custom token + self.assertEqual( + check_filter_exec(download_filter, "file_size == 3KB"), (True, None) + ) + self.assertEqual( + check_filter_exec(download_filter, "file_size == 3kb"), + (False, "Syntax error at 'kb'"), + ) + + # 3. error name + self.assertEqual( + check_filter_exec(download_filter, "caption2 == .*#中文啊.*'"), + (False, "Undefined name caption2"), + ) + + # 4. datetime + self.assertEqual( + check_filter_exec(download_filter, "message_date == 2023/0b-05"), + (False, "Syntax error at 'b'"), + ) + self.assertEqual( + check_filter_exec(download_filter, "message_date == 2023/01/45")[0], False + ) + + def test_normal(self): + download_filter = Filter() + print(download_filter.filter.names) + meta = MetaData("2022/03/08 10:00:00", 0, "#高桥千x", 0, 0, 0, "", 0) + download_filter.set_meta_data(meta) + self.assertEqual(check_filter_exec(download_filter, "id > 1"), (True, None)) + download_filter.set_debug(True) + filter_exec(download_filter, "caption == r'.*高桥.*'") + + download_filter2 = Filter() + meta2 = MetaData("2022/03/08 10:00:00", 0, "", 0, 0, 0, "", 0) + download_filter2.set_meta_data(meta2) + download_filter2.set_debug(True) + filter_exec(download_filter2, "caption == r'.*高桥.*'") + print(download_filter.filter.names) + + download_filter.set_meta_data(meta) + self.assertEqual(check_filter_exec(download_filter, "id > 1"), (True, None)) + download_filter.set_debug(True) + filter_exec(download_filter, "caption == r'.*高桥.*'") + filter_exec(download_filter, "caption == r'.*高桥.*'") diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_format.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_format.py new file mode 100644 index 0000000..e7e960a --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_format.py @@ -0,0 +1,233 @@ +"""Unittest module for media downloader.""" +import os +import sys +import unittest +from unittest.mock import patch + +from utils.format import ( + create_progress_bar, + extract_info_from_link, + format_byte, + get_byte_from_str, + replace_date_time, + truncate_filename, + validate_title, +) + +sys.path.append("..") # Adds higher directory to python modules path. + + +class FormatTestCase(unittest.TestCase): + def test_format_byte(self): + byte_list = [ + "KB", + "MB", + "GB", + "TB", + "PB", + "EB", + "ZB", + "YB", + "BB", + "NB", + "DB", + "CB", + ] + + self.assertEqual(format_byte(0.1), "0.8b") + self.assertEqual(format_byte(1), "1B") + + for i, value in enumerate(byte_list): + self.assertEqual(format_byte(pow(1024, i + 1)), "1.0" + value) + + try: + format_byte(-1) + except Exception as e: + self.assertEqual(isinstance(e, ValueError), True) + + def test_replace_date_time(self): + self.assertEqual( + replace_date_time(""), + "", + ) + + # split by '.' + self.assertEqual( + replace_date_time("xxxxx 2020.03.08 xxxxxxxxx"), + "xxxxx 2020-03-08 00:00:00 xxxxxxxxx", + ) + + # split by '-' + self.assertEqual( + replace_date_time("xxxxx 2020-03-08 xxxxxxxxxxxx"), + "xxxxx 2020-03-08 00:00:00 xxxxxxxxxxxx", + ) + + # split by '/' + self.assertEqual( + replace_date_time("xasd as 2020/03/08 21321fszv"), + "xasd as 2020-03-08 00:00:00 21321fszv", + ) + + # more different date + self.assertEqual( + replace_date_time("xxxxx 2020.03.08 2020.03.09 14:51 xxxxxxxxx"), + "xxxxx 2020-03-08 00:00:00 2020-03-09 14:51:00 xxxxxxxxx", + ) + + # more space + self.assertEqual( + replace_date_time("xxxxx 2020.03.08 2020.03.09 14:51 xxxxxxxxx"), + "xxxxx 2020-03-08 00:00:00 2020-03-09 14:51:00 xxxxxxxxx", + ) + + # more date format + self.assertEqual( + replace_date_time("xasd as 2020/03 21321fszv"), + "xasd as 2020-03-01 00:00:00 21321fszv", + ) + self.assertEqual( + replace_date_time("xasd as 2020-03 21321fszv"), + "xasd as 2020-03-01 00:00:00 21321fszv", + ) + self.assertEqual( + replace_date_time("xasd as 2020.03 21321fszv"), + "xasd as 2020-03-01 00:00:00 21321fszv", + ) + + def test_get_byte_from_str(self): + # B + self.assertEqual(get_byte_from_str("2B"), 2) + # KB + self.assertEqual(get_byte_from_str("2KB"), 2 * 1024) + self.assertEqual(get_byte_from_str("1024KB"), 1024 * 1024) + self.assertEqual(get_byte_from_str("2024KB"), 2024 * 1024) + self.assertEqual(get_byte_from_str("4000KB"), 4000 * 1024) + + # MB + self.assertEqual(get_byte_from_str("2MB"), 2 * 1024 * 1024) + self.assertEqual(get_byte_from_str("1024MB"), 1024 * 1024 * 1024) + + # GB + self.assertEqual(get_byte_from_str("2GB"), 2 * 1024 * 1024 * 1024) + + # TB + self.assertEqual(get_byte_from_str("2TB"), 2 * 1024 * 1024 * 1024 * 1024) + self.assertEqual(get_byte_from_str("1024TB"), 1024 * 1024 * 1024 * 1024 * 1024) + + # more str + self.assertEqual(get_byte_from_str("2BW"), 2) + self.assertEqual(get_byte_from_str("2WBW"), None) + + self.assertEqual(get_byte_from_str("2CB"), None) + + def test_extract_info_from_link(self): + test_cases = [ + ("https://t.me/", (None, None)), + ("https://t.me/username/1234", ("username", 1234)), + ("https://t.me/username", ("username", None)), + ("https://t.me/c/213213/91011", (-100213213, 91011)), + ("https://t.me/test123/1/1234", ("test123", 1234)), + ("me", ("me", None)), + ("self", ("self", None)), + ] + + for link, expected_output in test_cases: + result = extract_info_from_link(link) + self.assertEqual(result, expected_output) + + def test_create_progress_bar(self): + progress = 50 + progress_bar = create_progress_bar(progress) + self.assertEqual(progress_bar, "█████░░░░░") + + def test_create_progress_bar_with_custom_bars(self): + progress = 75 + total_bars = 20 + progress_bar = create_progress_bar(progress, total_bars) + self.assertEqual(progress_bar, "███████████████░░░░░") + + +class TestTruncateFilename(unittest.TestCase): + def test_truncate_filename(self): + test_cases = [ + ("testfile.txt", 240, "testfile.txt"), + ("testfile.txt", 5, "t.txt"), + ("a" * 240 + ".txt", 240, "a" * 236 + ".txt"), + ("a" * 241 + ".txt", 240, "a" * 236 + ".txt"), + ] + + for path, limit, expected in test_cases: + self.assertEqual(truncate_filename(path, limit), expected) + + @unittest.skipIf(sys.platform.startswith("win"), "requires Unix-based system") + def test_linux_filename_too_long(self): + long_filename = "a" * 265 + ".txt" + with self.assertRaises(OSError): + with open(long_filename, "w") as f: + f.write("test") + + long_filename = "a" * 265 + ".txt" + long_filename = truncate_filename(long_filename) + ".temp" + try: + with open(long_filename, "w") as f: + f.write("test") + os.remove(long_filename) + except Exception: + self.assertEqual(False, True) + + @unittest.skipIf(not sys.platform.startswith("win"), "requires Windows system") + def test_windows_filename_too_long(self): + long_filename = "a" * 265 + ".txt" + with self.assertRaises(OSError): + with open(long_filename, "w") as f: + f.write("test") + + long_filename = "a" * 265 + ".txt" + long_filename = truncate_filename(long_filename) + ".temp" + try: + with open(long_filename, "w") as f: + f.write("test") + os.remove(long_filename) + except Exception: + self.assertEqual(False, True) + + @patch("builtins.open", unittest.mock.mock_open()) + def test_file_creation(self): + file_name = "a" * 240 + ".txt" + truncated_file_name = truncate_filename(file_name) + + with open(truncated_file_name, "w") as f: + f.write("test") + + open.assert_called_once_with(truncated_file_name, "w") + + +class TestValidateTitle(unittest.TestCase): + def test_validate_title(self): + test_cases = [ + ("Hello, World!", "Hello, World!"), + ("Invalid/Title", "Invalid_Title"), + ("File\\Name", "File_Name"), + ("Colons:Are:Not:Allowed", "Colons_Are_Not_Allowed"), + ("Asterisks*In*Title", "Asterisks_In_Title"), + ("Question?Mark", "Question_Mark"), + ('Double"Quotes', "Double_Quotes"), + ("LessThan", "Greater_Than"), + ("Pipe|Symbol", "Pipe_Symbol"), + ("Multi\nLine", "Multi_Line"), + ] + + for title, expected in test_cases: + with self.subTest(title=title, expected=expected): + self.assertEqual(validate_title(title), expected) + + @patch("utils.format.re.sub") + def test_mock_re_sub(self, mock_re_sub): + title = "Invalid/Title" + mock_re_sub.return_value = "Mocked_Title" + + result = validate_title(title) + self.assertEqual(result, "Mocked_Title") + mock_re_sub.assert_called_once_with(r"[/\\:*?\"<>|\n]", "_", title) diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_log.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_log.py new file mode 100644 index 0000000..71cf7a1 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_log.py @@ -0,0 +1,30 @@ +"""Unittest module for log handlers.""" +import os +import sys +import unittest + +import mock + +sys.path.append("..") # Adds higher directory to python modules path. +from utils.log import LogFilter + + +class MockLog: + """ + Mock logs. + """ + + def __init__(self, **kwargs): + self.funcName = kwargs["funcName"] + + +class MetaTestCase(unittest.TestCase): + def test_log_filter(self): + result = LogFilter().filter(MockLog(funcName="invoke")) + self.assertEqual(result, False) + + result1 = LogFilter().filter(MockLog(funcName="get_file")) + self.assertEqual(result1, True) + + result2 = LogFilter().filter(MockLog(funcName="Synced")) + self.assertEqual(result2, True) diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_meta.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_meta.py new file mode 100644 index 0000000..a54c275 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_meta.py @@ -0,0 +1,23 @@ +"""Unittest module for media downloader.""" +import os +import sys +import unittest + +import mock + +sys.path.append("..") # Adds higher directory to python modules path. +from utils.meta import print_meta + + +class MetaTestCase(unittest.TestCase): + @mock.patch("utils.meta.APP_VERSION", "test-version 1.0.0") + @mock.patch("utils.meta.DEVICE_MODEL", "CPython X.X.X") + @mock.patch("utils.meta.SYSTEM_VERSION", "System xx.x.xx") + @mock.patch("media_downloader.logger") + def test_print_meta(self, mock_logger): + print_meta(mock_logger) + calls = [ + mock.call.info("Device: CPython X.X.X - test-version 1.0.0"), + mock.call.info("System: System xx.x.xx (EN)"), + ] + mock_logger.assert_has_calls(calls, any_order=True) diff --git a/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_updates.py b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_updates.py new file mode 100644 index 0000000..a4a8df4 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/tests/utils/test_updates.py @@ -0,0 +1,66 @@ +"""Unittest module for update checker.""" +import sys +import unittest + +import mock + +sys.path.append("..") # Adds higher directory to python modules path. +from utils.updates import check_for_updates + + +class FakeHTTPSConnection: + def __init__(self, status): + self.status = status + + def request(self, *args, **kwargs): + pass + + def getresponse(self): + return FakeHTTPSResponse(self.status) + + +class FakeHTTPSResponse: + def __init__(self, status): + self.status = status + + def read(self): + if self.status == 200: + return b'{"name":"v0.0.0 2022-03-02","tag_name":"v0.0.0", "html_url":"https://github.com/tangyoha/telegram_media_downloader/releases/tag/v0.0.0"}' + else: + return b"{error}" + + +class UpdatesTestCase(unittest.TestCase): + @mock.patch( + "utils.updates.http.client.HTTPSConnection", + new=mock.MagicMock(return_value=FakeHTTPSConnection(200)), + ) + @mock.patch("utils.updates.__version__", new="0.0.1") + @mock.patch("utils.updates.Console") + @mock.patch("utils.updates.Markdown") + def test_update(self, mock_markdown, mock_console): + check_for_updates() + name: str = "v0.0.0 2022-03-02" + html_url: str = ( + "https://github.com/tangyoha/telegram_media_downloader/releases/tag/v0.0.0" + ) + expected_message: str = ( + f"## New version of Telegram-Media-Downloader is available - {name}\n" + "You are using an outdated version v0.0.1 please pull in the changes using `git pull` or download the latest release.\n\n" + f"Find more details about the latest release here - {html_url}" + ) + mock_markdown.assert_called_with(expected_message) + mock_console.return_value.print.assert_called_once() + + @mock.patch( + "utils.updates.http.client.HTTPSConnection", + new=mock.MagicMock(return_value=FakeHTTPSConnection(500)), + ) + @mock.patch("utils.updates.Console") + def test_exception(self, mock_console): + check_for_updates() + exception_message: str = ( + "Following error occurred when checking for updates\n" + ", Expecting property name enclosed in double quotes: line 1 column 2 (char 1)" + ) + mock_console.return_value.log.assert_called_with(exception_message) diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/__init__.py b/src/parsers/Telegram/telegram_media_downloader/utils/__init__.py new file mode 100644 index 0000000..35cecd5 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/__init__.py @@ -0,0 +1,5 @@ +"""Init namespace""" + +__version__ = "2.2.1" +__license__ = "MIT License" +__copyright__ = "Copyright (C) 2023 tangyoha " diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/crypto.py b/src/parsers/Telegram/telegram_media_downloader/utils/crypto.py new file mode 100644 index 0000000..e8c40fe --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/crypto.py @@ -0,0 +1,77 @@ +"""Crypto utils""" + +import base64 + +from Crypto.Cipher import AES + + +class AesBase64(object): + """for AES encryption""" + + def __init__(self, key: str, iv: str): + self.key = key.encode("utf-8") + self.iv = iv.encode("utf-8") + self.mode = AES.MODE_CBC + + def encrypt(self, content): + """ + Encrypts the given content using the AES encryption algorithm. + + Parameters: + content (str): The content to be encrypted. + + Returns: + str: The encrypted content encoded in base64. + """ + cipher = AES.new(self.key, AES.MODE_CBC, self.iv) + content_padding = self.pkcs7padding(content) + encrypt_bytes = cipher.encrypt(content_padding.encode("utf-8")) + return base64.b64encode(encrypt_bytes) + + def decrypt(self, content): + """ + Decrypts the given content using AES encryption + with Cipher Block Chaining (CBC) mode. + + Parameters: + content (str): The content to be decrypted. + + Returns: + str: The decrypted text. + """ + cipher = AES.new(self.key, AES.MODE_CBC, self.iv) + content = base64.b64decode(content) + text = cipher.decrypt(content).decode("utf-8") + return self.pkcs7unpadding(text) + + def pkcs7unpadding(self, text): + """ + Removes the PKCS#7 padding from the given text. + + Parameters: + text (str): The text to remove padding from. + + Returns: + str: The text without PKCS#7 padding. + """ + length = len(text) + unpadding = ord(text[length - 1]) + return text[0 : length - unpadding] + + def pkcs7padding(self, text): + """ + Adds PKCS7 padding to the given text. + + Args: + text (str): The text to be padded. + + Returns: + str: The padded text. + """ + bs = 16 + length = len(text) + bytes_length = len(text.encode("utf-8")) + padding_size = length if (bytes_length == length) else bytes_length + padding = bs - padding_size % bs + padding_text = chr(padding) * padding + return text + padding_text diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/file_management.py b/src/parsers/Telegram/telegram_media_downloader/utils/file_management.py new file mode 100644 index 0000000..1a43896 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/file_management.py @@ -0,0 +1,78 @@ +"""Utility functions to handle downloaded files.""" +import glob +import os +import pathlib +from hashlib import md5 + + +def get_next_name(file_path: str) -> str: + """ + Get next available name to download file. + + Parameters + ---------- + file_path: str + Absolute path of the file for which next available name to + be generated. + + Returns + ------- + str + Absolute path of the next available name for the file. + """ + posix_path = pathlib.Path(file_path) + counter: int = 1 + new_file_name: str = os.path.join("{0}", "{1}-copy{2}{3}") + while os.path.isfile( + new_file_name.format( + posix_path.parent, + posix_path.stem, + counter, + "".join(posix_path.suffixes), + ) + ): + counter += 1 + return new_file_name.format( + posix_path.parent, + posix_path.stem, + counter, + "".join(posix_path.suffixes), + ) + + +def manage_duplicate_file(file_path: str): + """ + Check if a file is duplicate. + + Compare the md5 of files with copy name pattern + and remove if the md5 hash is same. + + Parameters + ---------- + file_path: str + Absolute path of the file for which duplicates needs to + be managed. + + Returns + ------- + str + Absolute path of the duplicate managed file. + """ + # pylint: disable = R1732 + posix_path = pathlib.Path(file_path) + file_base_name: str = "".join(posix_path.stem.split("-copy")[0]) + name_pattern: str = f"{posix_path.parent}/{file_base_name}*" + # Reason for using `str.translate()` + # https://stackoverflow.com/q/22055500/6730439 + old_files: list = glob.glob( + name_pattern.translate({ord("["): "[[]", ord("]"): "[]]"}) + ) + if file_path in old_files: + old_files.remove(file_path) + current_file_md5: str = md5(open(file_path, "rb").read()).hexdigest() + for old_file_path in old_files: + old_file_md5: str = md5(open(old_file_path, "rb").read()).hexdigest() + if current_file_md5 == old_file_md5: + os.remove(file_path) + return old_file_path + return file_path diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/format.py b/src/parsers/Telegram/telegram_media_downloader/utils/format.py new file mode 100644 index 0000000..32c341c --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/format.py @@ -0,0 +1,253 @@ +"""util format""" + +import math +import os +import re +import unicodedata +from datetime import datetime +from typing import Optional + + +def format_byte(size: float, dot=2): + """format byte""" + + # pylint: disable = R0912 + if 0 <= size < 1: + human_size = str(round(size / 0.125, dot)) + "b" + elif 1 <= size < 1024: + human_size = str(round(size, dot)) + "B" + elif math.pow(1024, 1) <= size < math.pow(1024, 2): + human_size = str(round(size / math.pow(1024, 1), dot)) + "KB" + elif math.pow(1024, 2) <= size < math.pow(1024, 3): + human_size = str(round(size / math.pow(1024, 2), dot)) + "MB" + elif math.pow(1024, 3) <= size < math.pow(1024, 4): + human_size = str(round(size / math.pow(1024, 3), dot)) + "GB" + elif math.pow(1024, 4) <= size < math.pow(1024, 5): + human_size = str(round(size / math.pow(1024, 4), dot)) + "TB" + elif math.pow(1024, 5) <= size < math.pow(1024, 6): + human_size = str(round(size / math.pow(1024, 5), dot)) + "PB" + elif math.pow(1024, 6) <= size < math.pow(1024, 7): + human_size = str(round(size / math.pow(1024, 6), dot)) + "EB" + elif math.pow(1024, 7) <= size < math.pow(1024, 8): + human_size = str(round(size / math.pow(1024, 7), dot)) + "ZB" + elif math.pow(1024, 8) <= size < math.pow(1024, 9): + human_size = str(round(size / math.pow(1024, 8), dot)) + "YB" + elif math.pow(1024, 9) <= size < math.pow(1024, 10): + human_size = str(round(size / math.pow(1024, 9), dot)) + "BB" + elif math.pow(1024, 10) <= size < math.pow(1024, 11): + human_size = str(round(size / math.pow(1024, 10), dot)) + "NB" + elif math.pow(1024, 11) <= size < math.pow(1024, 12): + human_size = str(round(size / math.pow(1024, 11), dot)) + "DB" + elif math.pow(1024, 12) <= size: + human_size = str(round(size / math.pow(1024, 12), dot)) + "CB" + else: + raise ValueError( + f'format_byte() takes number than or equal to 0, " \ + " but less than 0 given. {size}' + ) + return human_size + + +class SearchDateTimeResult: + """search result for datetime""" + + def __init__( + self, + value: str = "", + right_str: str = "", + left_str: str = "", + match: bool = False, + ): + self.value = value + self.right_str = right_str + self.left_str = left_str + self.match = match + + +def get_date_time(text: str, fmt: str) -> SearchDateTimeResult: + """Get first of date time,and split two part + + Parameters + ---------- + text: str + ready to search text + + Returns + ------- + SearchDateTimeResult + + """ + res = SearchDateTimeResult() + search_text = re.sub(r"\s+", " ", text) + regex_list = [ + # 2013.8.15 22:46:21 + r"\d{4}[-/\.]{1}\d{1,2}[-/\.]{1}\d{1,2}[ ]{1,}\d{1,2}:\d{1,2}:\d{1,2}", + # "2013.8.15 22:46" + r"\d{4}[-/\.]{1}\d{1,2}[-/\.]{1}\d{1,2}[ ]{1,}\d{1,2}:\d{1,2}", + # "2014.5.11" + r"\d{4}[-/\.]{1}\d{1,2}[-/\.]{1}\d{1,2}", + # "2014.5" + r"\d{4}[-/\.]{1}\d{1,2}", + ] + + format_list = [ + "%Y-%m-%d %H:%M:%S", + "%Y-%m-%d %H:%M", + "%Y-%m-%d", + "%Y-%m", + ] + + for i, value in enumerate(regex_list): + search_res = re.search(value, search_text) + if search_res: + time_str = search_res.group(0) + try: + res.value = datetime.strptime( + time_str.replace("/", "-").replace(".", "-").strip(), format_list[i] + ).strftime(fmt) + except Exception: + break + if search_res.start() != 0: + res.left_str = search_text[0 : search_res.start()] + if search_res.end() + 1 <= len(search_text): + res.right_str = search_text[search_res.end() :] + res.match = True + return res + + return res + + +def replace_date_time(text: str, fmt: str = "%Y-%m-%d %H:%M:%S") -> str: + """Replace text all datetime to the right fmt + + Parameters + ---------- + text: str + ready to search text + + fmt: str + the right datetime format + + Returns + ------- + str + The right format datetime str + + """ + + if not text: + return text + res_str = "" + res = get_date_time(text, fmt) + if not res.match: + return text + if res.left_str: + res_str += replace_date_time(res.left_str) + res_str += res.value + if res.right_str: + res_str += replace_date_time(res.right_str) + + return res_str + + +_BYTE_UNIT = ["B", "KB", "MB", "GB", "TB"] + + +def get_byte_from_str(byte_str: str) -> Optional[int]: + """Get byte from str + + Parameters + ---------- + byte_str: str + Include byte str + + Returns + ------- + int + Byte + """ + search_res = re.match(r"(\d{1,})(B|KB|MB|GB|TB)", byte_str) + if search_res: + unit_str = search_res.group(2) + unit: int = 1 + for it in _BYTE_UNIT: + if it == unit_str: + break + unit *= 1024 + + return int(search_res.group(1)) * unit + + return None + + +def truncate_filename(path: str, limit: int = 230) -> str: + """Truncate filename to the max len. + + Parameters + ---------- + path: str + File name path + + limit: int + limit file name len(utf-8 byte) + + Returns + ------- + str + if file name len more than limit then return truncate filename or return filename + + """ + p, f = os.path.split(os.path.normpath(path)) + f, e = os.path.splitext(f) + f_max = limit - len(e.encode("utf-8")) + f = unicodedata.normalize("NFC", f) + f_trunc = f.encode()[:f_max].decode("utf-8", errors="ignore") + return os.path.join(p, f_trunc + e) + + +def extract_info_from_link(link: str): + """Extract info from link""" + if link in ("me", "self"): + return link, None + + channel_match = re.match(r"(?:https?://)?t\.me/c/(\w+)(?:.*/(\d+)|/(\d+))?", link) + if channel_match: + chat_id = f"-100{channel_match.group(1)}" + message_id = int(channel_match.group(2)) if channel_match.group(2) else None + return int(chat_id), message_id + + username_match = re.match(r"(?:https?://)?t\.me/(\w+)(?:.*/(\d+)|/(\d+))?", link) + if username_match: + username = username_match.group(1) + message_id = int(username_match.group(2)) if username_match.group(2) else None + return username, message_id + + return None, None + + +def validate_title(title: str) -> str: + """Fix if title validation fails + + Parameters + ---------- + title: str + Chat title + + """ + + r_str = r"[/\\:*?\"<>|\n]" # '/ \ : * ? " < > |' + new_title = re.sub(r_str, "_", title) + return new_title + + +def create_progress_bar(progress, total_bars=10): + """ + example + progress = 50 + progress_bar = create_progress_bar(progress) + print(f'Progress: [{progress_bar}] ({progress}%)') + """ + completed_bars = int(progress * total_bars / 100) + remaining_bars = total_bars - completed_bars + progress_bar = "█" * completed_bars + "░" * remaining_bars + return progress_bar diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/log.py b/src/parsers/Telegram/telegram_media_downloader/utils/log.py new file mode 100644 index 0000000..5d54bbe --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/log.py @@ -0,0 +1,16 @@ +"""Util module to handle logs.""" +import logging + + +class LogFilter(logging.Filter): + """ + Custom Log Filter. + + Ignore logs from specific functions. + """ + + # pylint: disable = W0221 + def filter(self, record): + if record.funcName in ("invoke"): + return False + return True diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/meta.py b/src/parsers/Telegram/telegram_media_downloader/utils/meta.py new file mode 100644 index 0000000..90354be --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/meta.py @@ -0,0 +1,23 @@ +"""Utility module to manage meta info.""" +import platform + +from rich.console import Console + +from . import __copyright__, __license__, __version__ + +APP_VERSION = f"Telegram Media Downloader {__version__}" +DEVICE_MODEL = f"{platform.python_implementation()} {platform.python_version()}" +SYSTEM_VERSION = f"{platform.system()} {platform.release()}" +LANG_CODE = "en" + + +def print_meta(logger): + """Prints meta-data of the downloader script.""" + console = Console() + # pylint: disable = C0301 + console.log( + f"[bold]Telegram Media Downloader v{__version__}[/bold],\n[i]{__copyright__}[/i]" + ) + console.log(f"Licensed under the terms of the {__license__}", end="\n\n") + logger.info(f"Device: {DEVICE_MODEL} - {APP_VERSION}") + logger.info(f"System: {SYSTEM_VERSION} ({LANG_CODE.upper()})") diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/meta_data.py b/src/parsers/Telegram/telegram_media_downloader/utils/meta_data.py new file mode 100644 index 0000000..b2ab858 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/meta_data.py @@ -0,0 +1,98 @@ +"""Meta data for download filter""" + + +class ReString: + """for re match""" + + def __init__(self, re_string: str): + self.re_string = re_string + + +class NoneObj: + """for None obj to match""" + + def __init__(self): + pass + + +# pylint: disable=R0902 +# pylint: disable=R0913 +class MetaData: + """ + * `message_date` : - Date the message was sent + * like: message_date > 2022.03.04 && message_date < 2022.03.08 + * `message_id` : - Message 's id + * `media_file_size` : - File size + * `media_width` : - Include photo and video + * `media_height` : - Include photo and video + * `media_file_name` : - file name + * `message_caption` : - message_caption + * `message_duration` : - message_duration + * `sender_id` : - Sender id, empty for messages sent to channels. + * `sender_name` : - Sender name, empty for messages sent to channels. + " `reply_to_message_id` : - reply_to_message_id + """ + + AVAILABLE_MEDIA = ( + "audio", + "document", + "photo", + "sticker", + "animation", + "video", + "voice", + "video_note", + "new_chat_photo", + ) + + def __init__( + self, + message_date: str = None, + message_id: int = None, + message_caption: str = None, + media_file_size: int = None, + media_width: int = None, + media_height: int = None, + media_file_name: str = None, + media_duration: int = None, + media_type: str = None, + file_extension: str = None, + sender_id: int = None, + sender_name: str = None, + reply_to_message_id: int = None, + ): + self.message_date = message_date + self.message_id = message_id + self.message_caption = message_caption + self.media_file_size = media_file_size + self.media_width = media_width + self.media_height = media_height + self.media_file_name = media_file_name + self.media_duration = media_duration + self.media_type = media_type + self.file_extension = file_extension + self.sender_id = sender_id + self.sender_name = sender_name + self.reply_to_message_id = reply_to_message_id + + def data(self) -> dict: + """Meta map""" + return { + "message_date": self.message_date, + "message_id": self.message_id, + "message_caption": self.message_caption, + "media_file_size": self.media_file_size, + "media_width": self.media_width, + "media_height": self.media_height, + "media_file_name": self.media_file_name, + "media_duration": self.media_duration, + "id": self.message_id, + "caption": self.message_caption, + "file_size": self.media_file_size, + "file_name": self.media_file_name, + "media_type": self.media_type, + "file_extension": self.file_extension, + "sender_id": self.sender_id, + "sender_name": self.sender_name, + "reply_to_message_id": self.reply_to_message_id, + } diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/platform.py b/src/parsers/Telegram/telegram_media_downloader/utils/platform.py new file mode 100644 index 0000000..60c1d44 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/platform.py @@ -0,0 +1,35 @@ +"""for package download""" + +import platform + +# def get_platform() -> str: +# """Get platform title +# Returns +# ------- +# str +# window amd64 return "windows-amd64" +# """ +# sys_platform = platform.system().lower() +# platform_str: str = sys_platform +# if "macos" in sys_platform: +# platform_str = "osx" + +# machine = platform.machine().lower() + +# if "i386" in machine: +# platform_str += "-386" +# else: +# platform_str += "-" + machine + +# return platform_str + + +def get_exe_ext() -> str: + """Get exe ext + Returns + str + if in window then return "exe" other return "" + """ + if "windows" in platform.system().lower(): + return ".exe" + return "" diff --git a/src/parsers/Telegram/telegram_media_downloader/utils/updates.py b/src/parsers/Telegram/telegram_media_downloader/utils/updates.py new file mode 100644 index 0000000..ed4d8a2 --- /dev/null +++ b/src/parsers/Telegram/telegram_media_downloader/utils/updates.py @@ -0,0 +1,41 @@ +"""Utility module to check for new release of telegram-media-downloader""" +import http.client +import json + +from rich.console import Console +from rich.markdown import Markdown + +from . import __version__ + + +# pylint: disable = C0301 +def check_for_updates() -> None: + """Checks for new releases. + + Using Github API checks for new release and prints information of new release if available. + """ + console = Console() + try: + headers: dict = { + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", + } + conn = http.client.HTTPSConnection("api.github.com") + conn.request( + method="GET", + url="/repos/tangyoha/telegram_media_downloader/releases/latest", + headers=headers, + ) + res = conn.getresponse() + latest_release: dict = json.loads(res.read().decode("utf-8")) + if f"v{__version__}" != latest_release["tag_name"]: + update_message: str = ( + f"## New version of Telegram-Media-Downloader is available - {latest_release['name']}\n" + f"You are using an outdated version v{__version__} please pull in the changes using `git pull` or download the latest release.\n\n" + f"Find more details about the latest release here - {latest_release['html_url']}" + ) + console.print(Markdown(update_message)) + except Exception as e: + console.log( + f"Following error occurred when checking for updates\n{e.__class__}, {e}" + ) diff --git a/src/parsers/parser_mapping.py b/src/parsers/parser_mapping.py index b149a2c..d913a3b 100644 --- a/src/parsers/parser_mapping.py +++ b/src/parsers/parser_mapping.py @@ -5,6 +5,7 @@ from src.parsers.Bing.bing_parser import BingParser from src.parsers.Dzen.dzen_parser import DzenParser from src.parsers.MyMail.my_mail_parser import MyMailParser from src.parsers.Okru.ok_parser import OkParser +from src.parsers.Telegram.telegram_media_downloader.telegram_parser import TelegramParser from src.parsers.Yahoo.yahoo_parser import YahooParser from src.parsers.Yappy.yappy_parser import YappyParser from src.parsers.base_parser import BaseParser @@ -29,6 +30,7 @@ parser_mapping = OrderedDict( compile_regex(r"^.*\.livejournal.com/"): BaseParser, compile_regex(r"^.*\.dzen.ru/"): BaseParser, compile_regex(r"^.*\.bing.com/"): BingParser, + compile_regex(r"^t.me/"): TelegramParser, } )