Compare commits

...

13 Commits

Author SHA1 Message Date
scito
2610afe5d8 remove Python 3.7 workarounds, fixes #103 2023-08-06 19:29:59 +02:00
scito
8a4e2e3641 upgrade docker debian from bullseye (11) to bookworm (12) 2023-08-06 19:29:59 +02:00
scito
a0cf4246c1 remove deprecated pkg_resources package 2023-08-06 19:29:59 +02:00
dependabot[bot]
b3c0912e1f Bump nuitka from 1.7.5 to 1.7.9
Bumps [nuitka](https://github.com/Nuitka/Nuitka) from 1.7.5 to 1.7.9.
- [Changelog](https://github.com/Nuitka/Nuitka/blob/develop/Changelog.rst)
- [Commits](https://github.com/Nuitka/Nuitka/commits)

---
updated-dependencies:
- dependency-name: nuitka
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-04 17:20:06 +02:00
dependabot[bot]
1d8b49efcc Bump pylint from 2.17.4 to 2.17.5
Bumps [pylint](https://github.com/pylint-dev/pylint) from 2.17.4 to 2.17.5.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v2.17.4...v2.17.5)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-04 15:28:28 +02:00
dependabot[bot]
f846ee40af Bump flake8 from 6.0.0 to 6.1.0
Bumps [flake8](https://github.com/pycqa/flake8) from 6.0.0 to 6.1.0.
- [Commits](https://github.com/pycqa/flake8/compare/6.0.0...6.1.0)

---
updated-dependencies:
- dependency-name: flake8
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-04 09:11:18 +02:00
dependabot[bot]
f8b0283bdd Bump mypy-protobuf from 3.4.0 to 3.5.0
Bumps [mypy-protobuf](https://github.com/nipunn1313/mypy-protobuf) from 3.4.0 to 3.5.0.
- [Changelog](https://github.com/nipunn1313/mypy-protobuf/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nipunn1313/mypy-protobuf/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: mypy-protobuf
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-03 19:31:41 +02:00
dependabot[bot]
bcbf189289 Bump setuptools-git-versioning from 1.13.3 to 1.13.4
Bumps [setuptools-git-versioning](https://github.com/dolfinus/setuptools-git-versioning) from 1.13.3 to 1.13.4.
- [Release notes](https://github.com/dolfinus/setuptools-git-versioning/releases)
- [Changelog](https://github.com/dolfinus/setuptools-git-versioning/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/dolfinus/setuptools-git-versioning/compare/v1.13.3...v1.13.4)

---
updated-dependencies:
- dependency-name: setuptools-git-versioning
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-03 11:34:40 +02:00
scito
7c295e0963 fix #106: avoid UnboundLocalError for count_Xotp_entries: check has_Xotp 2023-07-23 14:32:42 +02:00
dependabot[bot]
6b72fad3c7 Bump wheel from 0.40.0 to 0.41.0
Bumps [wheel](https://github.com/pypa/wheel) from 0.40.0 to 0.41.0.
- [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst)
- [Commits](https://github.com/pypa/wheel/compare/0.40.0...0.41.0)

---
updated-dependencies:
- dependency-name: wheel
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-23 14:07:00 +02:00
dependabot[bot]
c937bede32 Bump types-protobuf from 4.23.0.1 to 4.23.0.2
Bumps [types-protobuf](https://github.com/python/typeshed) from 4.23.0.1 to 4.23.0.2.
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-protobuf
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-23 14:06:49 +02:00
dependabot[bot]
7402263dfe Bump nuitka from 1.7.3 to 1.7.5
Bumps [nuitka](https://github.com/Nuitka/Nuitka) from 1.7.3 to 1.7.5.
- [Changelog](https://github.com/Nuitka/Nuitka/blob/develop/Changelog.rst)
- [Commits](https://github.com/Nuitka/Nuitka/compare/1.7.3...1.7.5)

---
updated-dependencies:
- dependency-name: nuitka
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-23 13:21:05 +02:00
dependabot[bot]
b721571101 Bump nuitka from 1.7.1 to 1.7.3
Bumps [nuitka](https://github.com/Nuitka/Nuitka) from 1.7.1 to 1.7.3.
- [Changelog](https://github.com/Nuitka/Nuitka/blob/develop/Changelog.rst)
- [Commits](https://github.com/Nuitka/Nuitka/compare/1.7.1...1.7.3)

---
updated-dependencies:
- dependency-name: nuitka
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-16 18:23:42 +02:00
9 changed files with 99 additions and 127 deletions

View File

@@ -20,7 +20,7 @@ jobs:
strategy: strategy:
matrix: matrix:
python-version: ["3.x", "3.11", "3.10", "3.9", "3.8", "3.7"] python-version: ["3.x", "3.11", "3.10", "3.9", "3.8"]
platform: [ubuntu-latest, macos-latest, windows-latest] platform: [ubuntu-latest, macos-latest, windows-latest]
# exclude: # exclude:

1
.gitignore vendored
View File

@@ -27,6 +27,7 @@ file_version_info.txt
assets/* assets/*
extract_otp_secrets_linux_arm64.spec extract_otp_secrets_linux_arm64.spec
extract_otp_secrets_linux_x86_64_bullseye.spec extract_otp_secrets_linux_x86_64_bullseye.spec
extract_otp_secrets_linux_x86_64_bookworm.spec
extract_otp_secrets_linux_x86_64.spec extract_otp_secrets_linux_x86_64.spec
extract_otp_secrets.spec extract_otp_secrets.spec
test.txt test.txt

View File

@@ -7,7 +7,6 @@ name = "pypi"
colorama = ">=0.4.6" colorama = ">=0.4.6"
opencv-contrib-python = "*" opencv-contrib-python = "*"
# for macOS: opencv-contrib-python = "<=4.7.0" # for macOS: opencv-contrib-python = "<=4.7.0"
# for PYTHON <= 3.7: typing_extensions = "*"
pillow = "*" pillow = "*"
pyzbar = "*" pyzbar = "*"
protobuf = "*" protobuf = "*"

134
Pipfile.lock generated
View File

@@ -26,34 +26,34 @@
}, },
"numpy": { "numpy": {
"hashes": [ "hashes": [
"sha256:0ac6edfb35d2a99aaf102b509c8e9319c499ebd4978df4971b94419a116d0790", "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2",
"sha256:26815c6c8498dc49d81faa76d61078c4f9f0859ce7817919021b9eba72b425e3", "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55",
"sha256:4aedd08f15d3045a4e9c648f1e04daca2ab1044256959f1f95aafeeb3d794c16", "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf",
"sha256:4c69fe5f05eea336b7a740e114dec995e2f927003c30702d896892403df6dbf0", "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01",
"sha256:5177310ac2e63d6603f659fadc1e7bab33dd5a8db4e0596df34214eeab0fee3b", "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca",
"sha256:5aa48bebfb41f93043a796128854b84407d4df730d3fb6e5dc36402f5cd594c0", "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901",
"sha256:5b1b90860bf7d8a8c313b372d4f27343a54f415b20fb69dd601b7efe1029c91e", "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d",
"sha256:6c284907e37f5e04d2412950960894b143a648dea3f79290757eb878b91acbd1", "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4",
"sha256:6d183b5c58513f74225c376643234c369468e02947b47942eacbb23c1671f25d", "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf",
"sha256:7412125b4f18aeddca2ecd7219ea2d2708f697943e6f624be41aa5f8a9852cc4", "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380",
"sha256:7cd981ccc0afe49b9883f14761bb57c964df71124dcd155b0cba2b591f0d64b9", "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044",
"sha256:85cdae87d8c136fd4da4dad1e48064d700f63e923d5af6c8c782ac0df8044542", "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545",
"sha256:8aa130c3042052d656751df5e81f6d61edff3e289b5994edcf77f54118a8d9f4", "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f",
"sha256:95367ccd88c07af21b379be1725b5322362bb83679d36691f124a16357390153", "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f",
"sha256:9c7211d7920b97aeca7b3773a6783492b5b93baba39e7c36054f6e749fc7490c", "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3",
"sha256:9e3f2b96e3b63c978bc29daaa3700c028fe3f049ea3031b58aa33fe2a5809d24", "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364",
"sha256:b76aa836a952059d70a2788a2d98cb2a533ccd46222558b6970348939e55fc24", "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9",
"sha256:b792164e539d99d93e4e5e09ae10f8cbe5466de7d759fc155e075237e0c274e4", "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418",
"sha256:c0dc071017bc00abb7d7201bac06fa80333c6314477b3d10b52b58fa6a6e38f6", "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f",
"sha256:cc3fda2b36482891db1060f00f881c77f9423eead4c3579629940a3e12095fe8", "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295",
"sha256:d6b267f349a99d3908b56645eebf340cb58f01bd1e773b4eea1a905b3f0e4208", "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3",
"sha256:d76a84998c51b8b68b40448ddd02bd1081bb33abcdc28beee6cd284fe11036c6", "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187",
"sha256:e559c6afbca484072a98a51b6fa466aae785cfe89b69e8b856c3191bc8872a82", "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926",
"sha256:ecc68f11404930e9c7ecfc937aa423e1e50158317bf67ca91736a9864eae0232", "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357",
"sha256:f1accae9a28dc3cda46a91de86acf69de0d1b5f4edd44a9b0c3ceb8036dfff19" "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"
], ],
"markers": "python_version >= '3.10'", "markers": "python_version >= '3.10'",
"version": "==1.25.0" "version": "==1.25.2"
}, },
"opencv-contrib-python": { "opencv-contrib-python": {
"hashes": [ "hashes": [
@@ -86,6 +86,7 @@
"sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5", "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5",
"sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530", "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530",
"sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d", "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d",
"sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca",
"sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891", "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891",
"sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992", "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992",
"sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7", "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7",
@@ -115,6 +116,7 @@
"sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485", "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485",
"sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf", "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf",
"sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43", "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43",
"sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37",
"sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2", "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2",
"sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd", "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd",
"sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86", "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86",
@@ -203,11 +205,11 @@
"develop": { "develop": {
"astroid": { "astroid": {
"hashes": [ "hashes": [
"sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324", "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c",
"sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f" "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"
], ],
"markers": "python_full_version >= '3.7.2'", "markers": "python_full_version >= '3.7.2'",
"version": "==2.15.5" "version": "==2.15.6"
}, },
"build": { "build": {
"hashes": [ "hashes": [
@@ -288,19 +290,19 @@
}, },
"dill": { "dill": {
"hashes": [ "hashes": [
"sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0", "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e",
"sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373" "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"
], ],
"markers": "python_version >= '3.11'", "markers": "python_version >= '3.11'",
"version": "==0.3.6" "version": "==0.3.7"
}, },
"flake8": { "flake8": {
"hashes": [ "hashes": [
"sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7", "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23",
"sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181" "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"
], ],
"index": "pypi", "index": "pypi",
"version": "==6.0.0" "version": "==6.1.0"
}, },
"gfm-toc": { "gfm-toc": {
"hashes": [ "hashes": [
@@ -418,18 +420,18 @@
}, },
"mypy-protobuf": { "mypy-protobuf": {
"hashes": [ "hashes": [
"sha256:7d75a079651b105076776a35a5405e3fa773b8a167118f1b712e443e9a6c18a2", "sha256:0d0548c6b9a6faf14ce1a9ce2831c403a5c1f2a9363e85b1e2c51d5d57aa8393",
"sha256:da33dfde7547ff57e5ba5564126cbfa114f14413b2fa50759b1fa5de1e4ab511" "sha256:21f270da0a9792a9dac76b0df463c027e561664ab6973c59be4e4d064dfe67dc"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.4.0" "version": "==3.5.0"
}, },
"nuitka": { "nuitka": {
"hashes": [ "hashes": [
"sha256:be2dda0ab994585faa85836a8563a47d0f983d659bfc8f4f69faac85572ae3a7" "sha256:f910c95bb3406930b8ccbc3eba6a7874a0d4fdfe05adccbaa130ef82efeafbb1"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.7.1" "version": "==1.7.9"
}, },
"ordered-set": { "ordered-set": {
"hashes": [ "hashes": [
@@ -449,11 +451,11 @@
}, },
"platformdirs": { "platformdirs": {
"hashes": [ "hashes": [
"sha256:cec7b889196b9144d088e4c57d9ceef7374f6c39694ad1577a0aab50d27ea28c", "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d",
"sha256:f87ca4fcff7d2b0f81c6a748a77973d7af0f4d526f98f308477c3c436c74d528" "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==3.8.1" "version": "==3.10.0"
}, },
"pluggy": { "pluggy": {
"hashes": [ "hashes": [
@@ -484,27 +486,27 @@
}, },
"pycodestyle": { "pycodestyle": {
"hashes": [ "hashes": [
"sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053", "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0",
"sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610" "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"
], ],
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.8'",
"version": "==2.10.0" "version": "==2.11.0"
}, },
"pyflakes": { "pyflakes": {
"hashes": [ "hashes": [
"sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf", "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774",
"sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd" "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"
], ],
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.8'",
"version": "==3.0.1" "version": "==3.1.0"
}, },
"pylint": { "pylint": {
"hashes": [ "hashes": [
"sha256:5dcf1d9e19f41f38e4e85d10f511e5b9c35e1aa74251bf95cdd8cb23584e2db1", "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413",
"sha256:7a1145fb08c251bdb5cca11739722ce64a63db479283d10ce718b2460e54123c" "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.17.4" "version": "==2.17.5"
}, },
"pyproject-hooks": { "pyproject-hooks": {
"hashes": [ "hashes": [
@@ -548,27 +550,27 @@
}, },
"setuptools-git-versioning": { "setuptools-git-versioning": {
"hashes": [ "hashes": [
"sha256:0ae47836c30563c30f06d2e1e97fab4455a6b770f7a0496793239eccf4a6dd9f", "sha256:0edb4aef1661eb84b6eff729e66c13ac8bc34baad035a05aaccfb46d4bbd5fcd",
"sha256:9dfc59a31dcadcae04bcddc50534ccfc07a25a3180ab5cc1b1e3730217971c63" "sha256:9d6fba8b68ff8c296bd89422fed6c3500b4af48a606d8835a887292acc1a9867"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.13.3" "version": "==1.13.4"
}, },
"tomlkit": { "tomlkit": {
"hashes": [ "hashes": [
"sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171", "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86",
"sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3" "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==0.11.8" "version": "==0.12.1"
}, },
"types-protobuf": { "types-protobuf": {
"hashes": [ "hashes": [
"sha256:7bd5ea122a057b11a82b785d9de464932a1e9175fe977a4128adef11d7f35547", "sha256:1066b069d4f0e09bdebb64ca4f35cc6b8accf52f808368046ccec96744af0375",
"sha256:c926104f69ea62103846681b35b690d8d100ecf86c6cdda16c850a1313a272e4" "sha256:ee1a1ac8c099870075ef4457c01f3d56e189d8af1c13c3aa9f8dc207ca35337c"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.23.0.1" "version": "==4.23.0.2"
}, },
"typing-extensions": { "typing-extensions": {
"hashes": [ "hashes": [
@@ -580,11 +582,11 @@
}, },
"wheel": { "wheel": {
"hashes": [ "hashes": [
"sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873", "sha256:12b911f083e876e10c595779709f8a88a59f45aacc646492a67fe9ef796c1b47",
"sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247" "sha256:473219bd4cbedc62cea0cb309089b593e47c15c4a2531015f94e4e3b9a0f6981"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.40.0" "version": "==0.41.1"
}, },
"wrapt": { "wrapt": {
"hashes": [ "hashes": [

View File

@@ -5,7 +5,7 @@
![coverage](https://img.shields.io/badge/coverage-94%25-brightgreen) ![coverage](https://img.shields.io/badge/coverage-94%25-brightgreen)
[![License](https://img.shields.io/github/license/scito/extract_otp_secrets)](https://github.com/scito/extract_otp_secrets/blob/master/LICENSE) [![License](https://img.shields.io/github/license/scito/extract_otp_secrets)](https://github.com/scito/extract_otp_secrets/blob/master/LICENSE)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/scito/extract_otp_secrets?sort=semver)](https://github.com/scito/extract_otp_secrets/releases/latest) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/scito/extract_otp_secrets?sort=semver)](https://github.com/scito/extract_otp_secrets/releases/latest)
![python versions](https://img.shields.io/badge/python-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue) ![python versions](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue)
[![Docker image](https://img.shields.io/badge/docker-image-blue)](https://hub.docker.com/repository/docker/scit0/extract_otp_secrets/general) [![Docker image](https://img.shields.io/badge/docker-image-blue)](https://hub.docker.com/repository/docker/scit0/extract_otp_secrets/general)
[![Linux](https://img.shields.io/badge/os-linux-yellow)](https://github.com/scito/extract_otp_secrets/releases/latest) [![Linux](https://img.shields.io/badge/os-linux-yellow)](https://github.com/scito/extract_otp_secrets/releases/latest)
[![Windows](https://img.shields.io/badge/os-windows-yellow)](https://github.com/scito/extract_otp_secrets/releases/latest) [![Windows](https://img.shields.io/badge/os-windows-yellow)](https://github.com/scito/extract_otp_secrets/releases/latest)
@@ -367,7 +367,7 @@ python extract_otp_secrets.py = < example_export.png</pre>
* macOS * macOS
* Windows * Windows
* Uses UTF-8 on all platforms * Uses UTF-8 on all platforms
* Supports Python >= 3.7 * Supports Python >= 3.8
* Installation of shared system libraries is optional (🆕 since v2.3) * Installation of shared system libraries is optional (🆕 since v2.3)
* Provides a debug mode (-d) for analyzing import problems * Provides a debug mode (-d) for analyzing import problems
* Written in modern Python using type hints and following best practices * Written in modern Python using type hints and following best practices

View File

@@ -477,8 +477,8 @@ if $build_docker; then
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
# Build extract_otp_secrets (Debian Bullseye) # Build extract_otp_secrets (Debian Bookworm)
cmd="docker build . -t extract_otp_secrets -t extract_otp_secrets:bullseye --pull -f docker/Dockerfile --build-arg RUN_TESTS=false" cmd="docker build . -t extract_otp_secrets -t extract_otp_secrets:bookworm --pull -f docker/Dockerfile --build-arg RUN_TESTS=false"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
@@ -521,8 +521,8 @@ if $build_docker; then
# Build executable from Docker latest # Build executable from Docker latest
# sed "1!d" is workaround for head -n 1 since it head procduces exit code != 0 # sed "1!d" is workaround for head -n 1 since it head procduces exit code != 0
BULLSEYE_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"') BOOKWORM_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
echo "Bullseye glibc: $BULLSEYE_GLIBC_VERSION" echo "Bookworm glibc: $BOOKWORM_GLIBC_VERSION"
fi fi
if $build_arm; then if $build_arm; then
@@ -539,17 +539,17 @@ if $build_docker; then
if $build_exe; then if $build_exe; then
if $build_x86_64; then if $build_x86_64; then
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64_bullseye --distpath /files/dist/ /files/src/extract_otp_secrets.py'" cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64_bookworm --distpath /files/dist/ /files/src/extract_otp_secrets.py'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
cmd="dist/extract_otp_secrets_linux_x86_64_bullseye -h" cmd="dist/extract_otp_secrets_linux_x86_64_bookworm -h || echo 'Could not run exe; see error message above'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
# Build executable from Docker buster # Build executable from Docker buster
BUSTER_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets:buster -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"') BUSTER_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets:buster -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
echo "Bullseye glibc: $BUSTER_GLIBC_VERSION" echo "Bookworm glibc: $BUSTER_GLIBC_VERSION"
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:buster -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64 --distpath /files/dist/ /files/src/extract_otp_secrets.py'" cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:buster -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64 --distpath /files/dist/ /files/src/extract_otp_secrets.py'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
@@ -574,21 +574,21 @@ if $build_docker; then
if $build_nuitka_exe; then if $build_nuitka_exe; then
if $build_x86_64; then if $build_x86_64; then
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_bullseye_compiled /files/src/extract_otp_secrets.py'" cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_bookworm_compiled /files/src/extract_otp_secrets.py'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
cmd="build/docker/nuitka/extract_otp_secrets_linux_x86_64_bullseye_compiled -h" cmd="build/docker/nuitka/extract_otp_secrets_linux_x86_64_bookworm_compiled -h"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
cmd="cp build/docker/nuitka/extract_otp_secrets_linux_x86_64_bullseye_compiled dist/" cmd="cp build/docker/nuitka/extract_otp_secrets_linux_x86_64_bookworm_compiled dist/"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
# Build executable from Docker buster # Build executable from Docker buster
BUSTER_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets:buster -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"') BUSTER_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets:buster -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
echo "Bullseye glibc: $BUSTER_GLIBC_VERSION" echo "Bookworm glibc: $BUSTER_GLIBC_VERSION"
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:buster -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_buster_compiled /files/src/extract_otp_secrets.py'" cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:buster -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_buster_compiled /files/src/extract_otp_secrets.py'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi

View File

@@ -1,5 +1,5 @@
# --build-arg BASE_IMAGE=python:3.11-slim-buster # --build-arg BASE_IMAGE=python:3.11-slim-buster
ARG BASE_IMAGE=python:3.11-slim-bullseye ARG BASE_IMAGE=python:3.11-slim-bookworm
FROM $BASE_IMAGE FROM $BASE_IMAGE
# https://docs.docker.com/engine/reference/builder/ # https://docs.docker.com/engine/reference/builder/

View File

@@ -47,9 +47,6 @@ dependencies = [
"pyzbar", "pyzbar",
"qrcode", "qrcode",
"qreader<2.0.0", "qreader<2.0.0",
# workaround for PYTHON <= 3.7: compatibility
"typing_extensions; python_version<='3.7'",
"importlib_metadata; python_version<='3.7'",
] ]
description = "Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps such as 'Google Authenticator'" description = "Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps such as 'Google Authenticator'"
dynamic = ["version"] dynamic = ["version"]

View File

@@ -43,27 +43,15 @@ import re
import sys import sys
import urllib.parse as urlparse import urllib.parse as urlparse
from enum import Enum, IntEnum from enum import Enum, IntEnum
from typing import Any, List, Optional, Sequence, TextIO, Tuple, Union, TYPE_CHECKING from importlib.metadata import PackageNotFoundError, version
from typing import (Any, Final, List, Optional, Sequence, TextIO, Tuple,
TypedDict, Union)
import colorama import colorama
from pkg_resources import DistributionNotFound, get_distribution
from qrcode import QRCode # type: ignore from qrcode import QRCode # type: ignore
import protobuf_generated_python.google_auth_pb2 as pb import protobuf_generated_python.google_auth_pb2 as pb
# workaround for PYTHON <= 3.7: compatibility
if sys.version_info >= (3, 8):
from typing import Final, TypedDict
else:
from typing_extensions import Final, TypedDict
# workaround for PYTHON <= 3.7: compatibility
if sys.version_info >= (3, 8):
from importlib.metadata import PackageNotFoundError, version
else:
from importlib_metadata import PackageNotFoundError, version
debug_mode = '-d' in sys.argv[1:] or '--debug' in sys.argv[1:] debug_mode = '-d' in sys.argv[1:] or '--debug' in sys.argv[1:]
quiet = '-q' in sys.argv[1:] or '--quiet' in sys.argv[1:] quiet = '-q' in sys.argv[1:] or '--quiet' in sys.argv[1:]
headless: bool = False headless: bool = False
@@ -104,9 +92,8 @@ Exception: {e}\n""", file=sys.stderr)
FONT_SCALE: Final[float] = 1.3 FONT_SCALE: Final[float] = 1.3
FONT_THICKNESS: Final[int] = 1 FONT_THICKNESS: Final[int] = 1
FONT_LINE_STYLE: Final[int] = cv2.LINE_AA FONT_LINE_STYLE: Final[int] = cv2.LINE_AA
FONT_COLOR: Final[ColorBGR] = (255, 0, 0) FONT_COLOR: Final[ColorBGR] = 255, 0, 0
BOX_THICKNESS: Final[int] = 5 BOX_THICKNESS: Final[int] = 5
# workaround for PYTHON <= 3.7: must use () for assignments
WINDOW_X: Final[int] = 0 WINDOW_X: Final[int] = 0
WINDOW_Y: Final[int] = 1 WINDOW_Y: Final[int] = 1
WINDOW_WIDTH: Final[int] = 2 WINDOW_WIDTH: Final[int] = 2
@@ -115,10 +102,10 @@ Exception: {e}\n""", file=sys.stderr)
TEXT_HEIGHT: Final[int] = 1 TEXT_HEIGHT: Final[int] = 1
BORDER: Final[int] = 5 BORDER: Final[int] = 5
START_Y: Final[int] = 20 START_Y: Final[int] = 20
START_POS_TEXT: Final[Point] = (BORDER, START_Y) START_POS_TEXT: Final[Point] = BORDER, START_Y
NORMAL_COLOR: Final[ColorBGR] = (255, 0, 255) NORMAL_COLOR: Final[ColorBGR] = 255, 0, 255
SUCCESS_COLOR: Final[ColorBGR] = (0, 255, 0) SUCCESS_COLOR: Final[ColorBGR] = 0, 255, 0
FAILURE_COLOR: Final[ColorBGR] = (0, 0, 255) FAILURE_COLOR: Final[ColorBGR] = 0, 0, 255
CHAR_DX: Final[int] = (lambda text: cv2.getTextSize(text, FONT, FONT_SCALE, FONT_THICKNESS)[0][TEXT_WIDTH] // len(text))("28 QR codes capturedMMM") CHAR_DX: Final[int] = (lambda text: cv2.getTextSize(text, FONT, FONT_SCALE, FONT_THICKNESS)[0][TEXT_WIDTH] // len(text))("28 QR codes capturedMMM")
FONT_DY: Final[int] = cv2.getTextSize("M", FONT, FONT_SCALE, FONT_THICKNESS)[0][TEXT_HEIGHT] + 5 FONT_DY: Final[int] = cv2.getTextSize("M", FONT, FONT_SCALE, FONT_THICKNESS)[0][TEXT_HEIGHT] + 5
WINDOW_NAME: Final[str] = "Extract OTP Secrets: Capture QR Codes from Camera" WINDOW_NAME: Final[str] = "Extract OTP Secrets: Capture QR Codes from Camera"
@@ -131,12 +118,12 @@ except ImportError as e:
if debug_mode: if debug_mode:
raise e raise e
# Workaround for PYTHON <= 3.9: Union[int, None] used instead of int | None # Workaround for PYTHON <= 3.9: Generally Union[int, None] used instead of int | None
# Types # Types
Args = argparse.Namespace Args = argparse.Namespace
OtpUrl = str OtpUrl = str
# workaround for PYTHON <= 3.7: Otp = TypedDict('Otp', {'name': str, 'secret': str, 'issuer': str, 'type': str, 'counter': int | None, 'url': OtpUrl}) # Workaround for PYTHON <= 3.9: Otp = TypedDict('Otp', {'name': str, 'secret': str, 'issuer': str, 'type': str, 'counter': int | None, 'url': OtpUrl})
Otp = TypedDict('Otp', {'name': str, 'secret': str, 'issuer': str, 'type': str, 'counter': Union[int, None], 'url': OtpUrl}) Otp = TypedDict('Otp', {'name': str, 'secret': str, 'issuer': str, 'type': str, 'counter': Union[int, None], 'url': OtpUrl})
# workaround for PYTHON <= 3.9: Otps = list[Otp] # workaround for PYTHON <= 3.9: Otps = list[Otp]
Otps = List[Otp] Otps = List[Otp]
@@ -276,9 +263,7 @@ def extract_otp_from_otp_url(otpauth_migration_url: str, otps: Otps, urls_count:
def parse_args(sys_args: list[str]) -> Args: def parse_args(sys_args: list[str]) -> Args:
global verbose, quiet, colored global verbose, quiet, colored
# For PYTHON <= 3.7: Use := cmd = f"python {name}" if (name := os.path.basename(sys.argv[0])).endswith('.py') else f"{name}"
name = os.path.basename(sys.argv[0])
cmd = f"python {name}" if name.endswith('.py') else f"{name}"
description_text = "Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps" description_text = "Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps"
if cv2_available: if cv2_available:
description_text += "\nIf no infiles are provided, a GUI window starts and QR codes are captured from the camera." description_text += "\nIf no infiles are provided, a GUI window starts and QR codes are captured from the camera."
@@ -325,7 +310,7 @@ b) image file containing a QR code or = for stdin for an image containing a QR c
quiet = True if args.quiet else False quiet = True if args.quiet else False
if verbose: print(f"QReader installed: {cv2_available}") if verbose: print(f"QReader installed: {cv2_available}")
if cv2_available: if cv2_available:
if verbose >= LogLevel.VERBOSE: print(f"CV2 version: -") # TODO {cv2.__version__} if verbose >= LogLevel.VERBOSE: print(f"CV2 version: {cv2.__version__}") # type: ignore # cv2.__version__ is not available
if verbose: print(f"QR reading mode: {args.qr}\n") if verbose: print(f"QR reading mode: {args.qr}\n")
return args return args
@@ -735,8 +720,8 @@ def write_keepass_csv(file: str, otps: Otps) -> None:
if has_hotp: if has_hotp:
count_hotp_entries = write_keepass_htop_csv(otp_filename_hotp, otps) count_hotp_entries = write_keepass_htop_csv(otp_filename_hotp, otps)
if not quiet: if not quiet:
if count_totp_entries: print(f"Exported {count_totp_entries} totp entrie{'s'[:count_totp_entries != 1]} to keepass csv file {otp_filename_totp}") if has_totp and count_totp_entries: print(f"Exported {count_totp_entries} totp entrie{'s'[:count_totp_entries != 1]} to keepass csv file {otp_filename_totp}")
if count_hotp_entries: print(f"Exported {count_hotp_entries} hotp entrie{'s'[:count_hotp_entries != 1]} to keepass csv file {otp_filename_hotp}") if has_hotp and count_hotp_entries: print(f"Exported {count_hotp_entries} hotp entrie{'s'[:count_hotp_entries != 1]} to keepass csv file {otp_filename_hotp}")
def write_keepass_totp_csv(file: str, otps: Otps) -> int: def write_keepass_totp_csv(file: str, otps: Otps) -> int:
@@ -898,19 +883,7 @@ def get_raw_version() -> str:
return __version__ return __version__
except PackageNotFoundError: except PackageNotFoundError:
# package is not installed # package is not installed
pass return ''
# In some cases importlib cannot properly detect package version, for example it was compiled into executable file, so it uses some custom import mechanism.
# Instead, use pkg_resources which is included in setuptools (but has a significant runtime cost)
try:
__version__ = get_distribution("package-name").version
return __version__
except DistributionNotFound:
# package is not installed
pass
return ''
# workaround for PYTHON <= 3.9 use: BaseException | None # workaround for PYTHON <= 3.9 use: BaseException | None