Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9c552ab45 | ||
|
|
01a38e570c | ||
|
|
91b9490afb | ||
|
|
11e530e04a | ||
|
|
9e334748ac | ||
|
|
05f3d89c42 | ||
|
|
6bf02d045c |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -72,6 +72,6 @@ jobs:
|
|||||||
pytest-coverage-path: ./pytest-coverage.txt
|
pytest-coverage-path: ./pytest-coverage.txt
|
||||||
junitxml-path: ./pytest.xml
|
junitxml-path: ./pytest.xml
|
||||||
if: |
|
if: |
|
||||||
matrix.python-version == '3.x' && matrix.platform == 'ubuntu-latest'
|
false && matrix.python-version == '3.x' && matrix.platform == 'ubuntu-latest'
|
||||||
&& !contains(github.ref, 'refs/tags/')
|
&& !contains(github.ref, 'refs/tags/')
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/ci_docker.yml
vendored
6
.github/workflows/ci_docker.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
|||||||
# relative path to the place where source code with Dockerfile is located
|
# relative path to the place where source code with Dockerfile is located
|
||||||
# TODO file:, move to docker/
|
# TODO file:, move to docker/
|
||||||
context: .
|
context: .
|
||||||
file: Dockerfile
|
file: docker/Dockerfile
|
||||||
# builder: ${{ steps.buildx.outputs.name }}
|
# builder: ${{ steps.buildx.outputs.name }}
|
||||||
# Note: tags has to be all lower-case
|
# Note: tags has to be all lower-case
|
||||||
pull: true
|
pull: true
|
||||||
@@ -152,7 +152,7 @@ jobs:
|
|||||||
# relative path to the place where source code with Dockerfile is located
|
# relative path to the place where source code with Dockerfile is located
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
context: .
|
context: .
|
||||||
file: Dockerfile_only_txt
|
file: docker/Dockerfile_only_txt
|
||||||
# builder: ${{ steps.buildx.outputs.name }}
|
# builder: ${{ steps.buildx.outputs.name }}
|
||||||
# Note: tags has to be all lower-case
|
# Note: tags has to be all lower-case
|
||||||
pull: true
|
pull: true
|
||||||
@@ -235,7 +235,7 @@ jobs:
|
|||||||
# relative path to the place where source code with Dockerfile is located
|
# relative path to the place where source code with Dockerfile is located
|
||||||
# TODO file:, move to docker/
|
# TODO file:, move to docker/
|
||||||
context: .
|
context: .
|
||||||
file: Dockerfile
|
file: docker/Dockerfile
|
||||||
# builder: ${{ steps.buildx.outputs.name }}
|
# builder: ${{ steps.buildx.outputs.name }}
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=python:3.11-slim-buster
|
BASE_IMAGE=python:3.11-slim-buster
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,3 +29,4 @@ 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.spec
|
extract_otp_secrets_linux_x86_64.spec
|
||||||
extract_otp_secrets.spec
|
extract_otp_secrets.spec
|
||||||
|
test.txt
|
||||||
|
|||||||
285
Pipfile.lock
generated
285
Pipfile.lock
generated
@@ -60,36 +60,29 @@
|
|||||||
},
|
},
|
||||||
"opencv-contrib-python": {
|
"opencv-contrib-python": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1a48c2f24440cfd6e49c84dbe39c39feff5efbc90be8299c76e7141973d403b6",
|
"sha256:641ca83b34a9d3e8ef2da70533c6e4e3f076ffb0db69b963d82899cc53e9b3c2",
|
||||||
"sha256:2b8e3a1a7af31ebed28487d161ca4be0edd0b0e241667c6e9c842ac683313b2f",
|
"sha256:698c6b6203831f6573e04258be197e3bfde97fb7279fb614e39d75a8bd5818fb",
|
||||||
"sha256:2f0c32b0f2f55255632a44bdcfa185f88c7fb6d2616869942aff9d5a39df4997",
|
"sha256:8cad628ea6cc493f6c56140d7edc86f7ed8de528e18e44311e42b390a7d9996e",
|
||||||
"sha256:35e9a3809da10a47189c06d4d78b8e7821b9a3578dec8cbddf6ee1675bd83557",
|
"sha256:ab33fa2385ec7e70b9d484293f6f1f3707933045af4d18bb3b0a0290fa44370f",
|
||||||
"sha256:3a00e12546e5578f6bb7ed408c37fcfea533d74e9691cfaf40926f6b43295577",
|
"sha256:b54c2e8bb636e367d29bde48fae2aa52c43b782265cf65838a1fe852006cdd94",
|
||||||
"sha256:6d1c993811f92ddd7919314ada7b9be1f23db1c73f1384915c834dee8549c0b9",
|
"sha256:d1fef5ae16dfa73022749165e029e85eb0f399503470c0df1f84c95633f4ae52",
|
||||||
"sha256:7a08f9d1f9dd52de63a7bb448ab7d6d4a1a85b767c2358501d968d1e4d95098d",
|
"sha256:fefc5f7f1eef3125f78242afe5c989057b36c2f015619698c741b04f4503f913"
|
||||||
"sha256:7a75f1775790106e54bcfb101c0e00e1f801a57d9baebc82d0b6758fc83a4ca0",
|
|
||||||
"sha256:86f4b60b9536948f16d2170ba3a9b22d3955a957dc61a9bc56e53692c6db2c7e",
|
|
||||||
"sha256:9829e6efedde1d1b8419c5bd4d62d289ecbf44ae35b843c6da9e3cbcba1a9a8a",
|
|
||||||
"sha256:abc6adfa8694f71a4caffa922b279bd9d96954a37eee40b147f613c64310b411",
|
|
||||||
"sha256:b4033a164b2e2ea0049ba8c1194dab82dca680953ac36f33d1cc2c060906555f",
|
|
||||||
"sha256:e3967b1f3d74b8c70be724dbc07921faec87e8806cc87b2db5e7057815d6a08c",
|
|
||||||
"sha256:e770e9f653a0e5e72b973adb8213fae2df4642730ba1faf31e73a54287a4d5d4"
|
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.7.0.68"
|
"version": "==4.7.0.72"
|
||||||
},
|
},
|
||||||
"opencv-python": {
|
"opencv-python": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3a00e12546e5578f6bb7ed408c37fcfea533d74e9691cfaf40926f6b43295577",
|
"sha256:3424794a711f33284581f3c1e4b071cfc827d02b99d6fd9a35391f517c453306",
|
||||||
"sha256:6d1c993811f92ddd7919314ada7b9be1f23db1c73f1384915c834dee8549c0b9",
|
"sha256:7a297e7651e22eb17c265ddbbc80e2ba2a8ff4f4a1696a67c45e5f5798245842",
|
||||||
"sha256:7a08f9d1f9dd52de63a7bb448ab7d6d4a1a85b767c2358501d968d1e4d95098d",
|
"sha256:812af57553ec1c6709060c63f6b7e9ad07ddc0f592f3ccc6d00c71e0fe0e6376",
|
||||||
"sha256:86f4b60b9536948f16d2170ba3a9b22d3955a957dc61a9bc56e53692c6db2c7e",
|
"sha256:cd08343654c6b88c5a8c25bf425f8025aed2e3189b4d7306b5861d32affaf737",
|
||||||
"sha256:9829e6efedde1d1b8419c5bd4d62d289ecbf44ae35b843c6da9e3cbcba1a9a8a",
|
"sha256:d4f8880440c433a0025d78804dda6901d1e8e541a561dda66892d90290aef881",
|
||||||
"sha256:abc6adfa8694f71a4caffa922b279bd9d96954a37eee40b147f613c64310b411",
|
"sha256:ebfc0a3a2f57716e709028b992e4de7fd8752105d7a768531c4f434043c6f9ff",
|
||||||
"sha256:e770e9f653a0e5e72b973adb8213fae2df4642730ba1faf31e73a54287a4d5d4"
|
"sha256:eda115797b114fc16ca6f182b91c5d984f0015c19bec3145e55d33d708e9bae1"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==4.7.0.68"
|
"version": "==4.7.0.72"
|
||||||
},
|
},
|
||||||
"pillow": {
|
"pillow": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -176,23 +169,22 @@
|
|||||||
},
|
},
|
||||||
"protobuf": {
|
"protobuf": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30",
|
"sha256:1669cb7524221a8e2d9008d0842453dbefdd0fcdd64d67672f657244867635fb",
|
||||||
"sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b",
|
"sha256:29288813aacaa302afa2381db1d6e0482165737b0afdf2811df5fa99185c457b",
|
||||||
"sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc",
|
"sha256:47d31bdf58222dd296976aa1646c68c6ee80b96d22e0a3c336c9174e253fd35e",
|
||||||
"sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791",
|
"sha256:652d8dfece122a24d98eebfef30e31e455d300efa41999d1182e015984ac5930",
|
||||||
"sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717",
|
"sha256:7c535d126e7dcc714105ab20b418c4fedbd28f8b8afc42b7350b1e317bbbcc71",
|
||||||
"sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec",
|
"sha256:86c3d20428b007537ba6792b475c0853bba7f66b1f60e610d913b77d94b486e4",
|
||||||
"sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7",
|
"sha256:a33a273d21852f911b8bda47f39f4383fe7c061eb1814db2c76c9875c89c2491",
|
||||||
"sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab",
|
"sha256:ab4d043865dd04e6b09386981fe8f80b39a1e46139fb4a3c206229d6b9f36ff6",
|
||||||
"sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2",
|
"sha256:b2fea9dc8e3c0f32c38124790ef16cba2ee0628fe2022a52e435e1117bfef9b1",
|
||||||
"sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5",
|
"sha256:c27f371f0159feb70e6ea52ed7e768b3f3a4c5676c1900a7e51a24740381650e",
|
||||||
"sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1",
|
"sha256:c3325803095fb4c2a48649c321d2fbde59f8fbfcb9bfc7a86df27d112831c571",
|
||||||
"sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462",
|
"sha256:e474b63bab0a2ea32a7b26a4d8eec59e33e709321e5e16fb66e766b61b82a95e",
|
||||||
"sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97",
|
"sha256:e894e9ae603e963f0842498c4cd5d39c6a60f0d7e4c103df50ee939564298658"
|
||||||
"sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574"
|
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.21.12"
|
"version": "==4.22.0"
|
||||||
},
|
},
|
||||||
"pypng": {
|
"pypng": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -227,11 +219,11 @@
|
|||||||
},
|
},
|
||||||
"typing-extensions": {
|
"typing-extensions": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
|
"sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb",
|
||||||
"sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
|
"sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==4.4.0"
|
"version": "==4.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {
|
"develop": {
|
||||||
@@ -264,60 +256,60 @@
|
|||||||
"toml"
|
"toml"
|
||||||
],
|
],
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab",
|
"sha256:049806ae2df69468c130f04f0fab4212c46b34ba5590296281423bb1ae379df2",
|
||||||
"sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851",
|
"sha256:08e3dd256b8d3e07bb230896c8c96ec6c5dffbe5a133ba21f8be82b275b900e8",
|
||||||
"sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265",
|
"sha256:0f03c229f1453b936916f68a47b3dfb5e84e7ad48e160488168a5e35115320c8",
|
||||||
"sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0",
|
"sha256:171dd3aa71a49274a7e4fc26f5bc167bfae5a4421a668bc074e21a0522a0af4b",
|
||||||
"sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a",
|
"sha256:1856a8c4aa77eb7ca0d42c996d0ca395ecafae658c1432b9da4528c429f2575c",
|
||||||
"sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5",
|
"sha256:28563a35ef4a82b5bc5160a01853ce62b9fceee00760e583ffc8acf9e3413753",
|
||||||
"sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6",
|
"sha256:2c15bd09fd5009f3a79c8b3682b52973df29761030b692043f9834fc780947c4",
|
||||||
"sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311",
|
"sha256:2c9fffbc39dc4a6277e1525cab06c161d11ee3995bbc97543dc74fcec33e045b",
|
||||||
"sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada",
|
"sha256:2d7daf3da9c7e0ed742b3e6b4de6cc464552e787b8a6449d16517b31bbdaddf5",
|
||||||
"sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f",
|
"sha256:32e6a730fd18b2556716039ab93278ccebbefa1af81e6aa0c8dba888cf659e6e",
|
||||||
"sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8",
|
"sha256:34d7211be69b215ad92298a962b2cd5a4ef4b17c7871d85e15d3d1b6dc8d8c96",
|
||||||
"sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc",
|
"sha256:358d3bce1468f298b19a3e35183bdb13c06cdda029643537a0cc37e55e74e8f1",
|
||||||
"sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73",
|
"sha256:3713a8ec18781fda408f0e853bf8c85963e2d3327c99a82a22e5c91baffcb934",
|
||||||
"sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf",
|
"sha256:40785553d68c61e61100262b73f665024fd2bb3c6f0f8e2cd5b13e10e4df027b",
|
||||||
"sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e",
|
"sha256:4655ecd813f4ba44857af3e9cffd133ab409774e9d2a7d8fdaf4fdfd2941b789",
|
||||||
"sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352",
|
"sha256:465ea431c3b78a87e32d7d9ea6d081a1003c43a442982375cf2c247a19971961",
|
||||||
"sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c",
|
"sha256:4b8fd32f85b256fc096deeb4872aeb8137474da0c0351236f93cbedc359353d6",
|
||||||
"sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c",
|
"sha256:4c1153a6156715db9d6ae8283480ae67fb67452aa693a56d7dae9ffe8f7a80da",
|
||||||
"sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c",
|
"sha256:577a8bc40c01ad88bb9ab1b3a1814f2f860ff5c5099827da2a3cafc5522dadea",
|
||||||
"sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda",
|
"sha256:59a427f8a005aa7254074719441acb25ac2c2f60c1f1026d43f846d4254c1c2f",
|
||||||
"sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d",
|
"sha256:5e29a64e9586194ea271048bc80c83cdd4587830110d1e07b109e6ff435e5dbc",
|
||||||
"sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0",
|
"sha256:74cd60fa00f46f28bd40048d6ca26bd58e9bee61d2b0eb4ec18cea13493c003f",
|
||||||
"sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3",
|
"sha256:7efa21611ffc91156e6f053997285c6fe88cfef3fb7533692d0692d2cb30c846",
|
||||||
"sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d",
|
"sha256:7f992b32286c86c38f07a8b5c3fc88384199e82434040a729ec06b067ee0d52c",
|
||||||
"sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038",
|
"sha256:875b03d92ac939fbfa8ae74a35b2c468fc4f070f613d5b1692f9980099a3a210",
|
||||||
"sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c",
|
"sha256:88ae5929f0ef668b582fd7cad09b5e7277f50f912183cf969b36e82a1c26e49a",
|
||||||
"sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8",
|
"sha256:8d5302eb84c61e758c9d68b8a2f93a398b272073a046d07da83d77b0edc8d76b",
|
||||||
"sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa",
|
"sha256:90e7a4cbbb7b1916937d380beb1315b12957b8e895d7d9fb032e2038ac367525",
|
||||||
"sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09",
|
"sha256:9240a0335365c29c968131bdf624bb25a8a653a9c0d8c5dbfcabf80b59c1973c",
|
||||||
"sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b",
|
"sha256:932048364ff9c39030c6ba360c31bf4500036d4e15c02a2afc5a76e7623140d4",
|
||||||
"sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c",
|
"sha256:93db11da6e728587e943dff8ae1b739002311f035831b6ecdb15e308224a4247",
|
||||||
"sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a",
|
"sha256:971b49dbf713044c3e5f6451b39f65615d4d1c1d9a19948fa0f41b0245a98765",
|
||||||
"sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52",
|
"sha256:9cc9c41aa5af16d845b53287051340c363dd03b7ef408e45eec3af52be77810d",
|
||||||
"sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3",
|
"sha256:9dbb21561b0e04acabe62d2c274f02df0d715e8769485353ddf3cf84727e31ce",
|
||||||
"sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146",
|
"sha256:a6ceeab5fca62bca072eba6865a12d881f281c74231d2990f8a398226e1a5d96",
|
||||||
"sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a",
|
"sha256:ad12c74c6ce53a027f5a5ecbac9be20758a41c85425c1bbab7078441794b04ee",
|
||||||
"sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f",
|
"sha256:b09dd7bef59448c66e6b490cc3f3c25c14bc85d4e3c193b81a6204be8dd355de",
|
||||||
"sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4",
|
"sha256:bd67df6b48db18c10790635060858e2ea4109601e84a1e9bfdd92e898dc7dc79",
|
||||||
"sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c",
|
"sha256:bf9e02bc3dee792b9d145af30db8686f328e781bd212fdef499db5e9e4dd8377",
|
||||||
"sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75",
|
"sha256:bfa065307667f1c6e1f4c3e13f415b0925e34e56441f5fda2c84110a4a1d8bda",
|
||||||
"sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040",
|
"sha256:c160e34e388277f10c50dc2c7b5e78abe6d07357d9fe7fcb2f3c156713fd647e",
|
||||||
"sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063",
|
"sha256:c243b25051440386179591a8d5a5caff4484f92c980fb6e061b9559da7cc3f64",
|
||||||
"sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050",
|
"sha256:c3c4beddee01c8125a75cde3b71be273995e2e9ec08fbc260dd206b46bb99969",
|
||||||
"sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7",
|
"sha256:cd38140b56538855d3d5722c6d1b752b35237e7ea3f360047ce57f3fade82d98",
|
||||||
"sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222",
|
"sha256:d7f2a7df523791e6a63b40360afa6792a11869651307031160dc10802df9a252",
|
||||||
"sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912",
|
"sha256:da32526326e8da0effb452dc32a21ffad282c485a85a02aeff2393156f69c1c3",
|
||||||
"sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801",
|
"sha256:dc4f9a89c82faf6254d646180b2e3aa4daf5ff75bdb2c296b9f6a6cf547e26a7",
|
||||||
"sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d",
|
"sha256:f0557289260125a6c453ad5673ba79e5b6841d9a20c9e101f758bfbedf928a77",
|
||||||
"sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06",
|
"sha256:f332d61fbff353e2ef0f3130a166f499c3fad3a196e7f7ae72076d41a6bfb259",
|
||||||
"sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8",
|
"sha256:f3ff4205aff999164834792a3949f82435bc7c7655c849226d5836c3242d7451",
|
||||||
"sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"
|
"sha256:ffa637a2d5883298449a5434b699b22ef98dd8e2ef8a1d9e60fa9cfe79813411"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==7.1.0"
|
"version": "==7.2.0"
|
||||||
},
|
},
|
||||||
"dill": {
|
"dill": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -411,35 +403,35 @@
|
|||||||
},
|
},
|
||||||
"mypy": {
|
"mypy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:01b1b9e1ed40544ef486fa8ac022232ccc57109f379611633ede8e71630d07d2",
|
"sha256:0af4f0e20706aadf4e6f8f8dc5ab739089146b83fd53cb4a7e0e850ef3de0bb6",
|
||||||
"sha256:0ab090d9240d6b4e99e1fa998c2d0aa5b29fc0fb06bd30e7ad6183c95fa07593",
|
"sha256:15b5a824b58c7c822c51bc66308e759243c32631896743f030daf449fe3677f3",
|
||||||
"sha256:14d776869a3e6c89c17eb943100f7868f677703c8a4e00b3803918f86aafbc52",
|
"sha256:17455cda53eeee0a4adb6371a21dd3dbf465897de82843751cf822605d152c8c",
|
||||||
"sha256:1ace23f6bb4aec4604b86c4843276e8fa548d667dbbd0cb83a3ae14b18b2db6c",
|
"sha256:2013226d17f20468f34feddd6aae4635a55f79626549099354ce641bc7d40262",
|
||||||
"sha256:2efa963bdddb27cb4a0d42545cd137a8d2b883bd181bbc4525b568ef6eca258f",
|
"sha256:24189f23dc66f83b839bd1cce2dfc356020dfc9a8bae03978477b15be61b062e",
|
||||||
"sha256:2f6ac8c87e046dc18c7d1d7f6653a66787a4555085b056fe2d599f1f1a2a2d21",
|
"sha256:27a0f74a298769d9fdc8498fcb4f2beb86f0564bcdb1a37b58cbbe78e55cf8c0",
|
||||||
"sha256:3ae4c7a99e5153496243146a3baf33b9beff714464ca386b5f62daad601d87af",
|
"sha256:28cea5a6392bb43d266782983b5a4216c25544cd7d80be681a155ddcdafd152d",
|
||||||
"sha256:3cfad08f16a9c6611e6143485a93de0e1e13f48cfb90bcad7d5fde1c0cec3d36",
|
"sha256:448de661536d270ce04f2d7dddaa49b2fdba6e3bd8a83212164d4174ff43aa65",
|
||||||
"sha256:4e5175026618c178dfba6188228b845b64131034ab3ba52acaffa8f6c361f805",
|
"sha256:48525aec92b47baed9b3380371ab8ab6e63a5aab317347dfe9e55e02aaad22e8",
|
||||||
"sha256:50979d5efff8d4135d9db293c6cb2c42260e70fb010cbc697b1311a4d7a39ddb",
|
"sha256:5bc8d6bd3b274dd3846597855d96d38d947aedba18776aa998a8d46fabdaed76",
|
||||||
"sha256:5cd187d92b6939617f1168a4fe68f68add749902c010e66fe574c165c742ed88",
|
"sha256:5deb252fd42a77add936b463033a59b8e48eb2eaec2976d76b6878d031933fe4",
|
||||||
"sha256:5cfca124f0ac6707747544c127880893ad72a656e136adc935c8600740b21ff5",
|
"sha256:5f546ac34093c6ce33f6278f7c88f0f147a4849386d3bf3ae193702f4fe31407",
|
||||||
"sha256:5e398652d005a198a7f3c132426b33c6b85d98aa7dc852137a2a3be8890c4072",
|
"sha256:5fdd63e4f50e3538617887e9aee91855368d9fc1dea30da743837b0df7373bc4",
|
||||||
"sha256:67cced7f15654710386e5c10b96608f1ee3d5c94ca1da5a2aad5889793a824c1",
|
"sha256:65b122a993d9c81ea0bfde7689b3365318a88bde952e4dfa1b3a8b4ac05d168b",
|
||||||
"sha256:7306edca1c6f1b5fa0bc9aa645e6ac8393014fa82d0fa180d0ebc990ebe15964",
|
"sha256:71a808334d3f41ef011faa5a5cd8153606df5fc0b56de5b2e89566c8093a0c9a",
|
||||||
"sha256:7cc2c01dfc5a3cbddfa6c13f530ef3b95292f926329929001d45e124342cd6b7",
|
"sha256:920169f0184215eef19294fa86ea49ffd4635dedfdea2b57e45cb4ee85d5ccaf",
|
||||||
"sha256:87edfaf344c9401942883fad030909116aa77b0fa7e6e8e1c5407e14549afe9a",
|
"sha256:93a85495fb13dc484251b4c1fd7a5ac370cd0d812bbfc3b39c1bafefe95275d5",
|
||||||
"sha256:8845125d0b7c57838a10fd8925b0f5f709d0e08568ce587cc862aacce453e3dd",
|
"sha256:a2948c40a7dd46c1c33765718936669dc1f628f134013b02ff5ac6c7ef6942bf",
|
||||||
"sha256:92024447a339400ea00ac228369cd242e988dd775640755fa4ac0c126e49bb74",
|
"sha256:c6c2ccb7af7154673c591189c3687b013122c5a891bb5651eca3db8e6c6c55bd",
|
||||||
"sha256:a86b794e8a56ada65c573183756eac8ac5b8d3d59daf9d5ebd72ecdbb7867a43",
|
"sha256:c96b8a0c019fe29040d520d9257d8c8f122a7343a8307bf8d6d4a43f5c5bfcc8",
|
||||||
"sha256:bb2782a036d9eb6b5a6efcdda0986774bf798beef86a62da86cb73e2a10b423d",
|
"sha256:d42a98e76070a365a1d1c220fcac8aa4ada12ae0db679cb4d910fabefc88b994",
|
||||||
"sha256:be78077064d016bc1b639c2cbcc5be945b47b4261a4f4b7d8923f6c69c5c9457",
|
"sha256:dbeb24514c4acbc78d205f85dd0e800f34062efcc1f4a4857c57e4b4b8712bff",
|
||||||
"sha256:c7cf862aef988b5fbaa17764ad1d21b4831436701c7d2b653156a9497d92c83c",
|
"sha256:e60d0b09f62ae97a94605c3f73fd952395286cf3e3b9e7b97f60b01ddfbbda88",
|
||||||
"sha256:e0626db16705ab9f7fa6c249c017c887baf20738ce7f9129da162bb3075fc1af",
|
"sha256:e64f48c6176e243ad015e995de05af7f22bbe370dbb5b32bd6988438ec873919",
|
||||||
"sha256:f34495079c8d9da05b183f9f7daec2878280c2ad7cc81da686ef0b484cea2ecf",
|
"sha256:e831662208055b006eef68392a768ff83596035ffd6d846786578ba1714ba8f6",
|
||||||
"sha256:fe523fcbd52c05040c7bee370d66fee8373c5972171e4fbc323153433198592d"
|
"sha256:eda5c8b9949ed411ff752b9a01adda31afe7eae1e53e946dbdf9db23865e66c4"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.0.0"
|
"version": "==1.0.1"
|
||||||
},
|
},
|
||||||
"mypy-extensions": {
|
"mypy-extensions": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -483,23 +475,22 @@
|
|||||||
},
|
},
|
||||||
"protobuf": {
|
"protobuf": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30",
|
"sha256:1669cb7524221a8e2d9008d0842453dbefdd0fcdd64d67672f657244867635fb",
|
||||||
"sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b",
|
"sha256:29288813aacaa302afa2381db1d6e0482165737b0afdf2811df5fa99185c457b",
|
||||||
"sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc",
|
"sha256:47d31bdf58222dd296976aa1646c68c6ee80b96d22e0a3c336c9174e253fd35e",
|
||||||
"sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791",
|
"sha256:652d8dfece122a24d98eebfef30e31e455d300efa41999d1182e015984ac5930",
|
||||||
"sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717",
|
"sha256:7c535d126e7dcc714105ab20b418c4fedbd28f8b8afc42b7350b1e317bbbcc71",
|
||||||
"sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec",
|
"sha256:86c3d20428b007537ba6792b475c0853bba7f66b1f60e610d913b77d94b486e4",
|
||||||
"sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7",
|
"sha256:a33a273d21852f911b8bda47f39f4383fe7c061eb1814db2c76c9875c89c2491",
|
||||||
"sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab",
|
"sha256:ab4d043865dd04e6b09386981fe8f80b39a1e46139fb4a3c206229d6b9f36ff6",
|
||||||
"sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2",
|
"sha256:b2fea9dc8e3c0f32c38124790ef16cba2ee0628fe2022a52e435e1117bfef9b1",
|
||||||
"sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5",
|
"sha256:c27f371f0159feb70e6ea52ed7e768b3f3a4c5676c1900a7e51a24740381650e",
|
||||||
"sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1",
|
"sha256:c3325803095fb4c2a48649c321d2fbde59f8fbfcb9bfc7a86df27d112831c571",
|
||||||
"sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462",
|
"sha256:e474b63bab0a2ea32a7b26a4d8eec59e33e709321e5e16fb66e766b61b82a95e",
|
||||||
"sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97",
|
"sha256:e894e9ae603e963f0842498c4cd5d39c6a60f0d7e4c103df50ee939564298658"
|
||||||
"sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574"
|
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.21.12"
|
"version": "==4.22.0"
|
||||||
},
|
},
|
||||||
"pycodestyle": {
|
"pycodestyle": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -519,11 +510,11 @@
|
|||||||
},
|
},
|
||||||
"pylint": {
|
"pylint": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:bad9d7c36037f6043a1e848a43004dfd5ea5ceb05815d713ba56ca4503a9fe37",
|
"sha256:13b2c805a404a9bf57d002cd5f054ca4d40b0b87542bdaba5e05321ae8262c84",
|
||||||
"sha256:ffe7fa536bb38ba35006a7c8a6d2efbfdd3d95bbf21199cad31f76b1c50aaf30"
|
"sha256:ff22dde9c2128cd257c145cfd51adeff0be7df4d80d669055f24a962b351bbe4"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==2.16.1"
|
"version": "==2.16.2"
|
||||||
},
|
},
|
||||||
"pyproject-hooks": {
|
"pyproject-hooks": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -559,11 +550,11 @@
|
|||||||
},
|
},
|
||||||
"setuptools": {
|
"setuptools": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c",
|
"sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330",
|
||||||
"sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"
|
"sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==67.2.0"
|
"version": "==67.4.0"
|
||||||
},
|
},
|
||||||
"setuptools-git-versioning": {
|
"setuptools-git-versioning": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@@ -583,19 +574,19 @@
|
|||||||
},
|
},
|
||||||
"types-protobuf": {
|
"types-protobuf": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:46ffa6647e2f8d53a4828e905f8fb0e8ff8c918309b425572dd34ab4d0b48553",
|
"sha256:5f4c0ba5840d66a9f32bcfd153a5d41c503f409223eae4fda876cdd6b50a638a",
|
||||||
"sha256:819a7c67e69476e39c3f0c9871bbb9ee82313645d317b6daeb60ac95a309dbd3"
|
"sha256:6ecaddcc7aed2c636745a17c1411932cdef7a035304d50ffd4140297b6b882e8"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.21.0.5"
|
"version": "==4.21.0.7"
|
||||||
},
|
},
|
||||||
"typing-extensions": {
|
"typing-extensions": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
|
"sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb",
|
||||||
"sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
|
"sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==4.4.0"
|
"version": "==4.5.0"
|
||||||
},
|
},
|
||||||
"wheel": {
|
"wheel": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -14,7 +14,7 @@
|
|||||||
[](https://stand-with-ukraine.pp.ua)
|
[](https://stand-with-ukraine.pp.ua)
|
||||||
<!-- 
|
<!-- 
|
||||||
[](https://github.com/scito/extract_otp_secrets/blob/master/Pipfile.lock)
|
[](https://github.com/scito/extract_otp_secrets/blob/master/Pipfile.lock)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- [](https://GitHub.com/scito/extract_otp_secrets/releases/) -->
|
<!-- [](https://GitHub.com/scito/extract_otp_secrets/releases/) -->
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
|||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
- [Download and run binary executable (🆕 since v2.1)](#download-and-run-binary-executable--since-v21)
|
- [Download and run binary executable (🆕 since v2.1)](#download-and-run-binary-executable--since-v21)
|
||||||
- [MacOS application](#macos-application)
|
- [MacOS](#macos)
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Capture QR codes from camera (🆕 since version 2.0)](#capture-qr-codes-from-camera--since-version-20)
|
- [Capture QR codes from camera (🆕 since version 2.0)](#capture-qr-codes-from-camera--since-version-20)
|
||||||
- [With builtin QR decoder from image files (🆕 since version 2.0)](#with-builtin-qr-decoder-from-image-files--since-version-20)
|
- [With builtin QR decoder from image files (🆕 since version 2.0)](#with-builtin-qr-decoder-from-image-files--since-version-20)
|
||||||
@@ -90,8 +90,8 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
|||||||
## Download and run binary executable (🆕 since v2.1)
|
## Download and run binary executable (🆕 since v2.1)
|
||||||
|
|
||||||
1. Download executable for your platform from [latest release](https://github.com/scito/extract_otp_secrets/releases/latest), see assets
|
1. Download executable for your platform from [latest release](https://github.com/scito/extract_otp_secrets/releases/latest), see assets
|
||||||
2. Linux and macOS: Set executable bit for the downloaded file, e.g in terminal with `chmod +x extract_otp_secrets_OS_vX.X.X`
|
2. Linux and macOS: Set executable bit for the downloaded file, e.g in terminal with `chmod +x extract_otp_secrets_X.Y.Z_OS_ARCH`
|
||||||
3. Start executable by clicking or from command line (macOS: startable only from command line, see [below](#macOS-application))
|
3. Start executable by clicking or from command line (macOS: startable only from command line, see [below](#macos))
|
||||||
|
|
||||||
:heavy_check_mark: Everything is just packed in one executable.
|
:heavy_check_mark: Everything is just packed in one executable.
|
||||||
:heavy_check_mark: No installation needed, neither Python nor any dependencies have to be installed.
|
:heavy_check_mark: No installation needed, neither Python nor any dependencies have to be installed.
|
||||||
@@ -108,7 +108,7 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
|||||||
|
|
||||||
:information_source: The executables are not signed. Thus, the operating system may show a warning about download from unknown source.
|
:information_source: The executables are not signed. Thus, the operating system may show a warning about download from unknown source.
|
||||||
|
|
||||||
### MacOS application
|
### MacOS
|
||||||
|
|
||||||
> Beginning in macOS 10.15, all software built after June 1, 2019, and distributed with Developer ID must be notarized. However, you aren’t required to notarize software that you distribute through the Mac App Store because the App Store submission process already includes equivalent security checks. <small>[developer.apple.com](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution)</small>
|
> Beginning in macOS 10.15, all software built after June 1, 2019, and distributed with Developer ID must be notarized. However, you aren’t required to notarize software that you distribute through the Mac App Store because the App Store submission process already includes equivalent security checks. <small>[developer.apple.com](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution)</small>
|
||||||
|
|
||||||
@@ -119,8 +119,17 @@ However, the bare executable can be executed from the command line:
|
|||||||
1. Download executable for macOS platform from [latest release](https://github.com/scito/extract_otp_secrets/releases/latest), see assets
|
1. Download executable for macOS platform from [latest release](https://github.com/scito/extract_otp_secrets/releases/latest), see assets
|
||||||
2. Open Terminal application
|
2. Open Terminal application
|
||||||
3. Change to Downloads: `cd $HOME/Downloads`
|
3. Change to Downloads: `cd $HOME/Downloads`
|
||||||
4. Set executable bit for the downloaded file: `chmod +x extract_otp_secrets_OS_vX.X.X`
|
4. Set executable bit for the downloaded file: `chmod +x extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||||
5. Start executable from command line: `./extract_otp_secrets_OS_vX.X.X`
|
5. Start executable from command line: `./extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||||
|
|
||||||
|
#### Apple Silicon (ARM)
|
||||||
|
|
||||||
|
Currently, there is no build for M1 and M2 Apple Silicon processors due to lack of hardware. However, the binary executable should be runnable by Rosetta2 emulation.
|
||||||
|
|
||||||
|
```
|
||||||
|
arch -x86_64 extract_otp_secrets_X.Y.Z_macos_x86_64
|
||||||
|
```
|
||||||
|
:warning: This command is untested due to lack of hardware.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -206,7 +215,7 @@ For a detailed installation documentation of [pyzbar](https://github.com/Natural
|
|||||||
|
|
||||||
#### Linux (Fedora)
|
#### Linux (Fedora)
|
||||||
|
|
||||||
sudo dnf install libzbar0
|
sudo dnf install zbar
|
||||||
|
|
||||||
#### Linux (Arch Linux)
|
#### Linux (Arch Linux)
|
||||||
|
|
||||||
@@ -228,7 +237,7 @@ OpenCV requires [Visual C++ redistributable 2015](https://www.microsoft.com/en-u
|
|||||||
|
|
||||||
## Program help: arguments and options
|
## Program help: arguments and options
|
||||||
|
|
||||||
<pre>usage: extract_otp_secrets.py [-h] [--csv FILE] [--keepass FILE] [--json FILE] [--printqr] [--saveqr DIR] [--camera NUMBER] [--qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}] [-i] [--no-color] [--version] [-d | -v | -q] [infile ...]
|
<pre>usage: extract_otp_secrets.py [-h] [--csv FILE] [--keepass FILE] [--json FILE] [--txt FILE] [--printqr] [--saveqr DIR] [--camera NUMBER] [--qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}] [-i] [--no-color] [--version] [-d | -v | -q] [infile ...]
|
||||||
|
|
||||||
Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps
|
Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps
|
||||||
If no infiles are provided, a GUI window starts and QR codes are captured from the camera.
|
If no infiles are provided, a GUI window starts and QR codes are captured from the camera.
|
||||||
@@ -242,8 +251,9 @@ options:
|
|||||||
--csv FILE, -c FILE export csv file or - for stdout
|
--csv FILE, -c FILE export csv file or - for stdout
|
||||||
--keepass FILE, -k FILE export totp/hotp csv file(s) for KeePass, - for stdout
|
--keepass FILE, -k FILE export totp/hotp csv file(s) for KeePass, - for stdout
|
||||||
--json FILE, -j FILE export json file or - for stdout
|
--json FILE, -j FILE export json file or - for stdout
|
||||||
--printqr, -p print QR code(s) as text to the terminal (requires qrcode module)
|
--txt FILE, -t FILE export txt file or - for stdout
|
||||||
--saveqr DIR, -s DIR save QR code(s) as images to the given folder (requires qrcode module)
|
--printqr, -p print QR code(s) as text to the terminal
|
||||||
|
--saveqr DIR, -s DIR save QR code(s) as images to directory
|
||||||
--camera NUMBER, -C NUMBER camera number of system (default camera: 0)
|
--camera NUMBER, -C NUMBER camera number of system (default camera: 0)
|
||||||
--qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}, -Q {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}
|
--qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}, -Q {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}
|
||||||
QR reader (default: ZBAR)
|
QR reader (default: ZBAR)
|
||||||
@@ -344,8 +354,8 @@ python extract_otp_secrets.py = < example_export.png</pre>
|
|||||||
* extract_otp_secrets_linux_arm64 (requires glibc >= 2.28)
|
* extract_otp_secrets_linux_arm64 (requires glibc >= 2.28)
|
||||||
* extract_otp_secrets_win_x86_64.exe
|
* extract_otp_secrets_win_x86_64.exe
|
||||||
* extract_otp_secrets_macos_x86_64 (optional [libzbar](#installation-of-optional-shared-system-libraries-recommended) needs to be installed manually if needed)
|
* extract_otp_secrets_macos_x86_64 (optional [libzbar](#installation-of-optional-shared-system-libraries-recommended) needs to be installed manually if needed)
|
||||||
* extract_otp_secrets_macos_x86_64.dmg N/A, see [why](#macos-application)
|
* extract_otp_secrets_macos_x86_64.dmg N/A, see [why](#macos)
|
||||||
* extract_otp_secrets_macos_x86_64.pkg N/A, see [why](#macos-application)
|
* extract_otp_secrets_macos_x86_64.pkg N/A, see [why](#macos)
|
||||||
* Prebuilt Docker images provided for amd64 and arm64 (🆕 since v2.0)
|
* Prebuilt Docker images provided for amd64 and arm64 (🆕 since v2.0)
|
||||||
* Many ways to run the script:
|
* Many ways to run the script:
|
||||||
* Native Python
|
* Native Python
|
||||||
@@ -621,7 +631,7 @@ pip install -U -r requirements.txt
|
|||||||
Build and run the app within the container:
|
Build and run the app within the container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build . -t extract_otp_secrets --pull --build-arg RUN_TESTS=false
|
docker build . -t extract_otp_secrets --pull -f docker/Dockerfile --build-arg RUN_TESTS=false
|
||||||
```
|
```
|
||||||
|
|
||||||
Run tests in docker container:
|
Run tests in docker container:
|
||||||
@@ -633,7 +643,7 @@ docker run --entrypoint /extract/run_pytest.sh --rm -v "$(pwd)":/files:ro extrac
|
|||||||
#### Alpine (only text file processing)
|
#### Alpine (only text file processing)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build . -t extract_otp_secrets:only_txt --pull -f Dockerfile_only_txt --build-arg RUN_TESTS=false
|
docker build . -t extract_otp_secrets:only_txt --pull -f docker/Dockerfile_only_txt --build-arg RUN_TESTS=false
|
||||||
```
|
```
|
||||||
|
|
||||||
Run tests in docker container:
|
Run tests in docker container:
|
||||||
@@ -678,11 +688,13 @@ Build extract_otp_secrets project
|
|||||||
Options:
|
Options:
|
||||||
-i Interactive mode, all steps must be confirmed
|
-i Interactive mode, all steps must be confirmed
|
||||||
-C Ignore version check of protobuf/protoc
|
-C Ignore version check of protobuf/protoc
|
||||||
|
-E Do not build exe
|
||||||
-D Do not build docker
|
-D Do not build docker
|
||||||
|
-V Do not run pipenv
|
||||||
-G Do not start extract_otp_secrets.py in GUI mode
|
-G Do not start extract_otp_secrets.py in GUI mode
|
||||||
-c Clean everything
|
-c Clean everything
|
||||||
-r Generate result files
|
-r Generate result files
|
||||||
-h, --help Help
|
-h, --help Show help and quit
|
||||||
```
|
```
|
||||||
|
|
||||||
## Technical background
|
## Technical background
|
||||||
@@ -694,7 +706,7 @@ Command for regeneration of Python code from proto3 message definition file (onl
|
|||||||
|
|
||||||
protoc --plugin=protoc-gen-mypy=path/to/protoc-gen-mypy --python_out=src/protobuf_generated_python --mypy_out=src/protobuf_generated_python src/google_auth.proto
|
protoc --plugin=protoc-gen-mypy=path/to/protoc-gen-mypy --python_out=src/protobuf_generated_python --mypy_out=src/protobuf_generated_python src/google_auth.proto
|
||||||
|
|
||||||
The generated protobuf Python code was generated by protoc 21.12 (https://github.com/protocolbuffers/protobuf/releases/tag/v21.12).
|
The generated protobuf Python code was generated by protoc 22.0 (https://github.com/protocolbuffers/protobuf/releases/tag/v22.0).
|
||||||
|
|
||||||
For Python type hint generation the [mypy-protobuf](https://github.com/nipunn1313/mypy-protobuf) package is used.
|
For Python type hint generation the [mypy-protobuf](https://github.com/nipunn1313/mypy-protobuf) package is used.
|
||||||
|
|
||||||
|
|||||||
142
build.sh
142
build.sh
@@ -78,6 +78,8 @@ ignore_version_check=true
|
|||||||
clean=false
|
clean=false
|
||||||
clean_flag=""
|
clean_flag=""
|
||||||
build_docker=true
|
build_docker=true
|
||||||
|
build_exe=true
|
||||||
|
run_pipenv=true
|
||||||
run_gui=true
|
run_gui=true
|
||||||
generate_result_files=false
|
generate_result_files=false
|
||||||
PYTHONHASHSEED=31
|
PYTHONHASHSEED=31
|
||||||
@@ -92,11 +94,13 @@ while test $# -gt 0; do
|
|||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo "-i Interactive mode, all steps must be confirmed"
|
echo "-i Interactive mode, all steps must be confirmed"
|
||||||
echo "-C Ignore version check of protobuf/protoc"
|
echo "-C Ignore version check of protobuf/protoc"
|
||||||
|
echo "-E Do not build exe"
|
||||||
echo "-D Do not build docker"
|
echo "-D Do not build docker"
|
||||||
|
echo "-V Do not run pipenv"
|
||||||
echo "-G Do not start extract_otp_secrets.py in GUI mode"
|
echo "-G Do not start extract_otp_secrets.py in GUI mode"
|
||||||
echo "-c Clean everything"
|
echo "-c Clean everything"
|
||||||
echo "-r Generate result files"
|
echo "-r Generate result files"
|
||||||
echo "-h, --help Help"
|
echo "-h, --help Show help and quit"
|
||||||
quit
|
quit
|
||||||
;;
|
;;
|
||||||
-a)
|
-a)
|
||||||
@@ -107,10 +111,18 @@ while test $# -gt 0; do
|
|||||||
ignore_version_check=false
|
ignore_version_check=false
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-E)
|
||||||
|
build_exe=false
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-D)
|
-D)
|
||||||
build_docker=false
|
build_docker=false
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-V)
|
||||||
|
run_pipenv=false
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-G)
|
-G)
|
||||||
run_gui=false
|
run_gui=false
|
||||||
shift
|
shift
|
||||||
@@ -320,21 +332,23 @@ eval "$cmd"
|
|||||||
|
|
||||||
# Pipenv
|
# Pipenv
|
||||||
|
|
||||||
cmd="$PIP install -U pipenv"
|
if $run_pipenv; then
|
||||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
cmd="$PIP install -U pipenv"
|
||||||
eval "$cmd"
|
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||||
|
eval "$cmd"
|
||||||
|
|
||||||
$PIPENV --version
|
$PIPENV --version
|
||||||
|
|
||||||
cmd="$PIPENV update && $PIPENV --rm && $PIPENV install"
|
cmd="$PIPENV update && $PIPENV --rm && $PIPENV install"
|
||||||
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"
|
||||||
|
|
||||||
$PIPENV run python --version
|
$PIPENV run python --version
|
||||||
|
|
||||||
cmd="$PIPENV run pytest --cov=extract_otp_secrets_test tests/"
|
cmd="$PIPENV run pytest --cov=extract_otp_secrets_test tests/"
|
||||||
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"
|
||||||
|
fi
|
||||||
|
|
||||||
# Build wheel
|
# Build wheel
|
||||||
|
|
||||||
@@ -344,18 +358,20 @@ eval "$cmd"
|
|||||||
|
|
||||||
# Build executable
|
# Build executable
|
||||||
|
|
||||||
cmd="LOCAL_GLIBC_VERSION=$(ldd --version | sed '1!d' | sed -E 's/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/')"
|
if $build_exe; then
|
||||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
cmd="LOCAL_GLIBC_VERSION=$(ldd --version | sed '1!d' | sed -E 's/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/')"
|
||||||
eval "$cmd"
|
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||||
echo "local glibc: $LOCAL_GLIBC_VERSION"
|
eval "$cmd"
|
||||||
|
echo "local glibc: $LOCAL_GLIBC_VERSION"
|
||||||
|
|
||||||
cmd="pyinstaller -y --specpath installer --add-data $HOME/.local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile $clean_flag src/extract_otp_secrets.py"
|
cmd="pyinstaller -y --specpath installer --add-data $HOME/.local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile $clean_flag 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 -h"
|
cmd="dist/extract_otp_secrets -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"
|
||||||
|
fi
|
||||||
|
|
||||||
# Generate README.md TOC
|
# Generate README.md TOC
|
||||||
|
|
||||||
@@ -374,7 +390,7 @@ if $build_docker; then
|
|||||||
# Build docker
|
# Build docker
|
||||||
|
|
||||||
# Build Dockerfile_only_txt (Alpine)
|
# Build Dockerfile_only_txt (Alpine)
|
||||||
cmd="docker build . -t extract_otp_secrets_only_txt -t extract_otp_secrets:only-txt -t extract_otp_secrets:alpine -f Dockerfile_only_txt --pull --build-arg RUN_TESTS=false"
|
cmd="docker build . -t extract_otp_secrets_only_txt -t extract_otp_secrets:only-txt -t extract_otp_secrets:alpine -f docker/Dockerfile_only_txt --pull --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"
|
||||||
|
|
||||||
@@ -391,7 +407,7 @@ if $build_docker; then
|
|||||||
eval "$cmd"
|
eval "$cmd"
|
||||||
|
|
||||||
# Build extract_otp_secrets (Debian Bullseye)
|
# Build extract_otp_secrets (Debian Bullseye)
|
||||||
cmd="docker build . -t extract_otp_secrets -t extract_otp_secrets:bullseye --pull --build-arg RUN_TESTS=false"
|
cmd="docker build . -t extract_otp_secrets -t extract_otp_secrets:bullseye --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"
|
||||||
|
|
||||||
@@ -412,7 +428,7 @@ if $build_docker; then
|
|||||||
eval "$cmd"
|
eval "$cmd"
|
||||||
|
|
||||||
# Build extract_otp_secrets (Debian Buster)
|
# Build extract_otp_secrets (Debian Buster)
|
||||||
cmd="docker build . -t extract_otp_secrets:buster --pull --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.11-slim-buster"
|
cmd="docker build . -t extract_otp_secrets:buster --pull -f docker/Dockerfile --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.11-slim-buster"
|
||||||
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"
|
||||||
|
|
||||||
@@ -437,53 +453,55 @@ if $build_docker; then
|
|||||||
BULLSEYE_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
BULLSEYE_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 "Bullseye glibc: $BULLSEYE_GLIBC_VERSION"
|
||||||
|
|
||||||
cmd="docker run --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'"
|
if $build_exe; then
|
||||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
cmd="docker run --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'"
|
||||||
eval "$cmd"
|
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||||
|
eval "$cmd"
|
||||||
|
|
||||||
cmd="dist/extract_otp_secrets_linux_x86_64_bullseye -h"
|
cmd="dist/extract_otp_secrets_linux_x86_64_bullseye -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"
|
||||||
|
|
||||||
# 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 "Bullseye glibc: $BUSTER_GLIBC_VERSION"
|
||||||
|
|
||||||
cmd="docker run --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 --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
|
||||||
eval "$cmd"
|
eval "$cmd"
|
||||||
|
|
||||||
cmd="dist/extract_otp_secrets_linux_x86_64 -h"
|
cmd="dist/extract_otp_secrets_linux_x86_64 -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"
|
||||||
|
|
||||||
# create Windows win_file_version_info.txt
|
# create Windows win_file_version_info.txt
|
||||||
cmd="VERSION_STR=$(setuptools-git-versioning) VERSION_MAJOR=$(cut -d '.' -f 1 <<< "$(setuptools-git-versioning)") VERSION_MINOR=$(cut -d '.' -f 2 <<< "$(setuptools-git-versioning)") VERSION_PATCH=$(cut -d '.' -f 3 <<< "$(setuptools-git-versioning)") VERSION_BUILD=$(($(git rev-list --count $(git tag | sort -V -r | sed '1!d')..HEAD))) COPYRIGHT_YEARS='2020-2023' envsubst < installer/win_file_version_info_template.txt > build/win_file_version_info.txt"
|
cmd="VERSION_STR=$(setuptools-git-versioning) VERSION_MAJOR=$(cut -d '.' -f 1 <<< "$(setuptools-git-versioning)") VERSION_MINOR=$(cut -d '.' -f 2 <<< "$(setuptools-git-versioning)") VERSION_PATCH=$(cut -d '.' -f 3 <<< "$(setuptools-git-versioning)") VERSION_BUILD=$(($(git rev-list --count $(git tag | sort -V -r | sed '1!d')..HEAD))) COPYRIGHT_YEARS='2020-2023' envsubst < installer/win_file_version_info_template.txt > build/win_file_version_info.txt"
|
||||||
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"
|
||||||
|
|
||||||
# create macOS extract_otp_secrets_macos.spec from extract_otp_secrets_macos_template.spec
|
# create macOS extract_otp_secrets_macos.spec from extract_otp_secrets_macos_template.spec
|
||||||
cmd="VERSION_STR=$(setuptools-git-versioning) COPYRIGHT_YEARS='2020-2023' envsubst < installer/extract_otp_secrets_macos_template.spec > build/extract_otp_secrets_macos.spec"
|
cmd="VERSION_STR=$(setuptools-git-versioning) COPYRIGHT_YEARS='2020-2023' envsubst < installer/extract_otp_secrets_macos_template.spec > build/extract_otp_secrets_macos.spec"
|
||||||
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 linux/arm64
|
# build linux/arm64
|
||||||
# Build extract_otp_secrets (Debian Buster)
|
# Build extract_otp_secrets (Debian Buster)
|
||||||
cmd="docker buildx build --platform=linux/arm64 . -t extract_otp_secrets:buster --pull --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.11-slim-buster"
|
cmd="docker buildx build --platform=linux/arm64 . -t extract_otp_secrets:buster --pull -f docker/Dockerfile --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.11-slim-buster"
|
||||||
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="docker run --pull always --rm --privileged multiarch/qemu-user-static --reset -p yes"
|
cmd="docker run --pull always --rm --privileged multiarch/qemu-user-static --reset -p yes"
|
||||||
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="docker run --platform linux/arm64 --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 --specpath installer -y --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_arm64 --distpath /files/dist/ /files/src/extract_otp_secrets.py'"
|
cmd="docker run --platform linux/arm64 --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 --specpath installer -y --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_arm64 --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="PLATFORM='linux/arm64' && EXE='dist/extract_otp_secrets_linux_arm64' && docker run --platform \"\$PLATFORM\" --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:buster -c \"\$EXE -V && \$EXE -h && \$EXE example_export.png && \$EXE - < example_export.txt && \$EXE --qr ZBAR example_export.png && \$EXE --qr QREADER example_export.png && \$EXE --qr QREADER_DEEP example_export.png && \$EXE --qr CV2 example_export.png && \$EXE --qr CV2_WECHAT example_export.png\""
|
cmd="PLATFORM='linux/arm64' && EXE='dist/extract_otp_secrets_linux_arm64' && docker run --platform \"\$PLATFORM\" --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:buster -c \"\$EXE -V && \$EXE -h && \$EXE example_export.png && \$EXE - < example_export.txt && \$EXE --qr ZBAR example_export.png && \$EXE --qr QREADER example_export.png && \$EXE --qr QREADER_DEEP example_export.png && \$EXE --qr CV2 example_export.png && \$EXE --qr CV2_WECHAT example_export.png\""
|
||||||
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"
|
||||||
|
fi
|
||||||
|
|
||||||
# Run GUI from Docker
|
# Run GUI from Docker
|
||||||
if $run_gui; then
|
if $run_gui; then
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ COPY requirements*.txt src/ run_pytest.sh pytest.ini tests/ example_*.txt exampl
|
|||||||
|
|
||||||
ARG RUN_TESTS=true
|
ARG RUN_TESTS=true
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
libgl1 \
|
libgl1 \
|
||||||
libglib2.0-0 \
|
libglib2.0-0 \
|
||||||
libsm6 \
|
libsm6 \
|
||||||
@@ -4,7 +4,7 @@ Generate from file: README.md
|
|||||||
|
|
||||||
- [Table of contents](#table-of-contents)
|
- [Table of contents](#table-of-contents)
|
||||||
- [Download and run binary executable (🆕 since v2.1)](#download-and-run-binary-executable--since-v21)
|
- [Download and run binary executable (🆕 since v2.1)](#download-and-run-binary-executable--since-v21)
|
||||||
- [MacOS application](#macos-application)
|
- [MacOS](#macos)
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Capture QR codes from camera (🆕 since version 2.0)](#capture-qr-codes-from-camera--since-version-20)
|
- [Capture QR codes from camera (🆕 since version 2.0)](#capture-qr-codes-from-camera--since-version-20)
|
||||||
- [With builtin QR decoder from image files (🆕 since version 2.0)](#with-builtin-qr-decoder-from-image-files--since-version-20)
|
- [With builtin QR decoder from image files (🆕 since version 2.0)](#with-builtin-qr-decoder-from-image-files--since-version-20)
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"colorama>=0.4.6",
|
"colorama>=0.4.6",
|
||||||
"opencv-contrib-python; sys_platform != 'darwin'",
|
"opencv-contrib-python",
|
||||||
"opencv-contrib-python<=4.7.0; sys_platform == 'darwin'",
|
# "opencv-contrib-python<=4.7.0; sys_platform == 'darwin'",
|
||||||
"Pillow",
|
"Pillow",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
"pyzbar",
|
"pyzbar",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
colorama>=0.4.6
|
colorama>=0.4.6
|
||||||
importlib_metadata; python_version<='3.7'
|
importlib_metadata; python_version<='3.7'
|
||||||
opencv-contrib-python; sys_platform != 'darwin'
|
opencv-contrib-python
|
||||||
opencv-contrib-python<=4.7.0; sys_platform == 'darwin'
|
# opencv-contrib-python<=4.7.0; sys_platform == 'darwin'
|
||||||
Pillow
|
Pillow
|
||||||
protobuf
|
protobuf
|
||||||
pyzbar
|
pyzbar
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ 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
|
from typing import Any, List, Optional, Sequence, TextIO, Tuple, Union, TYPE_CHECKING
|
||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
from pkg_resources import DistributionNotFound, get_distribution
|
from pkg_resources import DistributionNotFound, get_distribution
|
||||||
@@ -200,6 +200,7 @@ def main(sys_args: list[str]) -> None:
|
|||||||
write_csv(args.csv, otps)
|
write_csv(args.csv, otps)
|
||||||
write_keepass_csv(args.keepass, otps)
|
write_keepass_csv(args.keepass, otps)
|
||||||
write_json(args.json, otps)
|
write_json(args.json, otps)
|
||||||
|
write_txt(args.txt, otps, True)
|
||||||
|
|
||||||
|
|
||||||
# workaround for PYTHON <= 3.9 use: pb.MigrationPayload | None
|
# workaround for PYTHON <= 3.9 use: pb.MigrationPayload | None
|
||||||
@@ -262,9 +263,9 @@ def extract_otp_from_otp_url(otpauth_migration_url: str, otps: Otps, urls_count:
|
|||||||
if not quiet:
|
if not quiet:
|
||||||
print_otp(otp)
|
print_otp(otp)
|
||||||
if args.printqr:
|
if args.printqr:
|
||||||
print_qr(args, otp_url)
|
print_qr(otp_url)
|
||||||
if args.saveqr:
|
if args.saveqr:
|
||||||
save_qr(otp, args, len(otps))
|
save_qr_image(otp, args.saveqr, len(otps))
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print()
|
print()
|
||||||
elif args.ignore and not quiet:
|
elif args.ignore and not quiet:
|
||||||
@@ -297,8 +298,9 @@ b) image file containing a QR code or = for stdin for an image containing a QR c
|
|||||||
arg_parser.add_argument('--csv', '-c', help='export csv file or - for stdout', metavar=('FILE'))
|
arg_parser.add_argument('--csv', '-c', help='export csv file or - for stdout', metavar=('FILE'))
|
||||||
arg_parser.add_argument('--keepass', '-k', help='export totp/hotp csv file(s) for KeePass, - for stdout', metavar=('FILE'))
|
arg_parser.add_argument('--keepass', '-k', help='export totp/hotp csv file(s) for KeePass, - for stdout', metavar=('FILE'))
|
||||||
arg_parser.add_argument('--json', '-j', help='export json file or - for stdout', metavar=('FILE'))
|
arg_parser.add_argument('--json', '-j', help='export json file or - for stdout', metavar=('FILE'))
|
||||||
arg_parser.add_argument('--printqr', '-p', help='print QR code(s) as text to the terminal (requires qrcode module)', action='store_true')
|
arg_parser.add_argument('--txt', '-t', help='export txt file or - for stdout', metavar=('FILE'))
|
||||||
arg_parser.add_argument('--saveqr', '-s', help='save QR code(s) as images to the given folder (requires qrcode module)', metavar=('DIR'))
|
arg_parser.add_argument('--printqr', '-p', help='print QR code(s) as text to the terminal', action='store_true')
|
||||||
|
arg_parser.add_argument('--saveqr', '-s', help='save QR code(s) as images to directory', metavar=('DIR'))
|
||||||
if cv2_available:
|
if cv2_available:
|
||||||
arg_parser.add_argument('--camera', '-C', help='camera number of system (default camera: 0)', default=0, type=int, metavar=('NUMBER'))
|
arg_parser.add_argument('--camera', '-C', help='camera number of system (default camera: 0)', default=0, type=int, metavar=('NUMBER'))
|
||||||
if not zbar_available:
|
if not zbar_available:
|
||||||
@@ -314,7 +316,7 @@ b) image file containing a QR code or = for stdin for an image containing a QR c
|
|||||||
output_group.add_argument('-q', '--quiet', help='no stdout output, except output set by -', action='store_true')
|
output_group.add_argument('-q', '--quiet', help='no stdout output, except output set by -', action='store_true')
|
||||||
args = arg_parser.parse_args(sys_args)
|
args = arg_parser.parse_args(sys_args)
|
||||||
colored = not args.no_color
|
colored = not args.no_color
|
||||||
if args.csv == '-' or args.json == '-' or args.keepass == '-':
|
if args.csv == '-' or args.json == '-' or args.keepass == '-' or args.txt == '-':
|
||||||
args.quiet = args.q = True
|
args.quiet = args.q = True
|
||||||
|
|
||||||
verbose = args.verbose if args.verbose else LogLevel.NORMAL
|
verbose = args.verbose if args.verbose else LogLevel.NORMAL
|
||||||
@@ -391,7 +393,7 @@ def extract_otps_from_camera(args: Args) -> Otps:
|
|||||||
|
|
||||||
cv2_print_text(img, f"Mode: {qr_mode.name} (Hit SPACE to change)", 0, TextPosition.LEFT, FONT_COLOR, 20)
|
cv2_print_text(img, f"Mode: {qr_mode.name} (Hit SPACE to change)", 0, TextPosition.LEFT, FONT_COLOR, 20)
|
||||||
cv2_print_text(img, "Press ESC to quit", 1, TextPosition.LEFT, FONT_COLOR, 17)
|
cv2_print_text(img, "Press ESC to quit", 1, TextPosition.LEFT, FONT_COLOR, 17)
|
||||||
cv2_print_text(img, "Press C/J/K to save as csv/json/keepass file", 2, TextPosition.LEFT, FONT_COLOR, None)
|
cv2_print_text(img, "Press C/J/K/T to save as csv/json/keepass/txt file", 2, TextPosition.LEFT, FONT_COLOR, None)
|
||||||
|
|
||||||
cv2_print_text(img, f"{len(otp_urls)} QR code{'s'[:len(otp_urls) != 1]} captured", 0, TextPosition.RIGHT, FONT_COLOR)
|
cv2_print_text(img, f"{len(otp_urls)} QR code{'s'[:len(otp_urls) != 1]} captured", 0, TextPosition.RIGHT, FONT_COLOR)
|
||||||
cv2_print_text(img, f"{len(otps)} otp{'s'[:len(otps) != 1]} extracted", 1, TextPosition.RIGHT, FONT_COLOR)
|
cv2_print_text(img, f"{len(otps)} otp{'s'[:len(otps) != 1]} extracted", 1, TextPosition.RIGHT, FONT_COLOR)
|
||||||
@@ -486,6 +488,18 @@ def cv2_handle_pressed_keys(qr_mode: QRMode, otps: Otps) -> Tuple[bool, QRMode]:
|
|||||||
tk_root.update()
|
tk_root.update()
|
||||||
if len(file_name) > 0:
|
if len(file_name) > 0:
|
||||||
write_keepass_csv(file_name, otps)
|
write_keepass_csv(file_name, otps)
|
||||||
|
elif (key == ord('t') or key == ord('T')) and is_not_headless():
|
||||||
|
if has_no_otps_show_warning(otps):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
file_name = tkinter.filedialog.asksaveasfilename(
|
||||||
|
title="Save extracted otp secrets as text",
|
||||||
|
defaultextension='.txt',
|
||||||
|
filetypes=[('Text', '*.txt'), ('All', '*.*')]
|
||||||
|
)
|
||||||
|
tk_root.update()
|
||||||
|
if len(file_name) > 0:
|
||||||
|
write_txt(file_name, otps, True)
|
||||||
elif key == 32:
|
elif key == 32:
|
||||||
qr_mode = next_valid_qr_mode(qr_mode, zbar_available)
|
qr_mode = next_valid_qr_mode(qr_mode, zbar_available)
|
||||||
if verbose >= LogLevel.MORE_VERBOSE: print(f"QR reading mode: {qr_mode}")
|
if verbose >= LogLevel.MORE_VERBOSE: print(f"QR reading mode: {qr_mode}")
|
||||||
@@ -655,28 +669,27 @@ def build_otp_url(secret: str, raw_otp: pb.MigrationPayload.OtpParameters) -> st
|
|||||||
return otp_url
|
return otp_url
|
||||||
|
|
||||||
|
|
||||||
def print_otp(otp: Otp) -> None:
|
def print_otp(otp: Otp, out: Optional[TextIO] = None) -> None:
|
||||||
print(f"Name: {otp['name']}")
|
print(f"Name: {otp['name']}", file=out)
|
||||||
print(f"Secret: {otp['secret']}")
|
print(f"Secret: {otp['secret']}", file=out)
|
||||||
if otp['issuer']: print(f"Issuer: {otp['issuer']}")
|
if otp['issuer']: print(f"Issuer: {otp['issuer']}", file=out)
|
||||||
print(f"Type: {otp['type']}")
|
print(f"Type: {otp['type']}", file=out)
|
||||||
if otp['type'] == 'hotp':
|
if otp['type'] == 'hotp':
|
||||||
print(f"Counter: {otp['counter']}")
|
print(f"Counter: {otp['counter']}", file=out)
|
||||||
if verbose:
|
if verbose:
|
||||||
print(otp['url'])
|
print(otp['url'], file=out)
|
||||||
|
|
||||||
|
|
||||||
def save_qr(otp: Otp, args: Args, j: int) -> str:
|
def save_qr_image(otp: Otp, dir: str, j: int) -> str:
|
||||||
dir = args.saveqr
|
|
||||||
if not (os.path.exists(dir)): os.makedirs(dir, exist_ok=True)
|
if not (os.path.exists(dir)): os.makedirs(dir, exist_ok=True)
|
||||||
pattern = re.compile(r'[\W_]+')
|
pattern = re.compile(r'[\W_]+')
|
||||||
file_otp_name = pattern.sub('', otp['name'])
|
file_otp_name = pattern.sub('', otp['name'])
|
||||||
file_otp_issuer = pattern.sub('', otp['issuer'])
|
file_otp_issuer = pattern.sub('', otp['issuer'])
|
||||||
save_qr_file(args, otp['url'], f"{dir}/{j}-{file_otp_name}{'-' + file_otp_issuer if file_otp_issuer else ''}.png")
|
save_qr_image_file(otp['url'], f"{dir}/{j}-{file_otp_name}{'-' + file_otp_issuer if file_otp_issuer else ''}.png")
|
||||||
return file_otp_name
|
return file_otp_name
|
||||||
|
|
||||||
|
|
||||||
def save_qr_file(args: Args, otp_url: OtpUrl, name: str) -> None:
|
def save_qr_image_file(otp_url: OtpUrl, name: str) -> None:
|
||||||
qr = QRCode()
|
qr = QRCode()
|
||||||
qr.add_data(otp_url)
|
qr.add_data(otp_url)
|
||||||
img = qr.make_image(fill_color='black', back_color='white')
|
img = qr.make_image(fill_color='black', back_color='white')
|
||||||
@@ -684,10 +697,20 @@ def save_qr_file(args: Args, otp_url: OtpUrl, name: str) -> None:
|
|||||||
img.save(name)
|
img.save(name)
|
||||||
|
|
||||||
|
|
||||||
def print_qr(args: Args, otp_url: str) -> None:
|
def print_qr(otp_url: str, out: Optional[TextIO] = None) -> None:
|
||||||
qr = QRCode()
|
qr = QRCode()
|
||||||
qr.add_data(otp_url)
|
qr.add_data(otp_url)
|
||||||
qr.print_ascii()
|
qr.print_ascii(out)
|
||||||
|
|
||||||
|
|
||||||
|
def write_txt(file: str, otps: Otps, write_qr: bool = False) -> None:
|
||||||
|
if file and len(file) > 0 and len(otps) > 0:
|
||||||
|
with open_file_or_stdout(file) as outfile:
|
||||||
|
for otp in otps:
|
||||||
|
print_otp(otp, outfile)
|
||||||
|
if write_qr:
|
||||||
|
print_qr(otp['url'], outfile)
|
||||||
|
print(file=outfile)
|
||||||
|
|
||||||
|
|
||||||
def write_csv(file: str, otps: Otps) -> None:
|
def write_csv(file: str, otps: Otps) -> None:
|
||||||
|
|||||||
@@ -15,17 +15,18 @@ _sym_db = _symbol_database.Default()
|
|||||||
|
|
||||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11google_auth.proto\"\xb7\x03\n\x10MigrationPayload\x12\x37\n\x0eotp_parameters\x18\x01 \x03(\x0b\x32\x1f.MigrationPayload.OtpParameters\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x12\n\nbatch_size\x18\x03 \x01(\x05\x12\x13\n\x0b\x62\x61tch_index\x18\x04 \x01(\x05\x12\x10\n\x08\x62\x61tch_id\x18\x05 \x01(\x05\x1a\xb7\x01\n\rOtpParameters\x12\x0e\n\x06secret\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06issuer\x18\x03 \x01(\t\x12.\n\talgorithm\x18\x04 \x01(\x0e\x32\x1b.MigrationPayload.Algorithm\x12\x0e\n\x06\x64igits\x18\x05 \x01(\x05\x12\'\n\x04type\x18\x06 \x01(\x0e\x32\x19.MigrationPayload.OtpType\x12\x0f\n\x07\x63ounter\x18\x07 \x01(\x03\",\n\tAlgorithm\x12\x10\n\x0c\x41LGO_INVALID\x10\x00\x12\r\n\tALGO_SHA1\x10\x01\"6\n\x07OtpType\x12\x0f\n\x0bOTP_INVALID\x10\x00\x12\x0c\n\x08OTP_HOTP\x10\x01\x12\x0c\n\x08OTP_TOTP\x10\x02\x62\x06proto3')
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11google_auth.proto\"\xb7\x03\n\x10MigrationPayload\x12\x37\n\x0eotp_parameters\x18\x01 \x03(\x0b\x32\x1f.MigrationPayload.OtpParameters\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x12\n\nbatch_size\x18\x03 \x01(\x05\x12\x13\n\x0b\x62\x61tch_index\x18\x04 \x01(\x05\x12\x10\n\x08\x62\x61tch_id\x18\x05 \x01(\x05\x1a\xb7\x01\n\rOtpParameters\x12\x0e\n\x06secret\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06issuer\x18\x03 \x01(\t\x12.\n\talgorithm\x18\x04 \x01(\x0e\x32\x1b.MigrationPayload.Algorithm\x12\x0e\n\x06\x64igits\x18\x05 \x01(\x05\x12\'\n\x04type\x18\x06 \x01(\x0e\x32\x19.MigrationPayload.OtpType\x12\x0f\n\x07\x63ounter\x18\x07 \x01(\x03\",\n\tAlgorithm\x12\x10\n\x0c\x41LGO_INVALID\x10\x00\x12\r\n\tALGO_SHA1\x10\x01\"6\n\x07OtpType\x12\x0f\n\x0bOTP_INVALID\x10\x00\x12\x0c\n\x08OTP_HOTP\x10\x01\x12\x0c\n\x08OTP_TOTP\x10\x02\x62\x06proto3')
|
||||||
|
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
_globals = globals()
|
||||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google_auth_pb2', globals())
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google_auth_pb2', _globals)
|
||||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
|
||||||
DESCRIPTOR._options = None
|
DESCRIPTOR._options = None
|
||||||
_MIGRATIONPAYLOAD._serialized_start=22
|
_globals['_MIGRATIONPAYLOAD']._serialized_start=22
|
||||||
_MIGRATIONPAYLOAD._serialized_end=461
|
_globals['_MIGRATIONPAYLOAD']._serialized_end=461
|
||||||
_MIGRATIONPAYLOAD_OTPPARAMETERS._serialized_start=176
|
_globals['_MIGRATIONPAYLOAD_OTPPARAMETERS']._serialized_start=176
|
||||||
_MIGRATIONPAYLOAD_OTPPARAMETERS._serialized_end=359
|
_globals['_MIGRATIONPAYLOAD_OTPPARAMETERS']._serialized_end=359
|
||||||
_MIGRATIONPAYLOAD_ALGORITHM._serialized_start=361
|
_globals['_MIGRATIONPAYLOAD_ALGORITHM']._serialized_start=361
|
||||||
_MIGRATIONPAYLOAD_ALGORITHM._serialized_end=405
|
_globals['_MIGRATIONPAYLOAD_ALGORITHM']._serialized_end=405
|
||||||
_MIGRATIONPAYLOAD_OTPTYPE._serialized_start=407
|
_globals['_MIGRATIONPAYLOAD_OTPTYPE']._serialized_start=407
|
||||||
_MIGRATIONPAYLOAD_OTPTYPE._serialized_end=461
|
_globals['_MIGRATIONPAYLOAD_OTPTYPE']._serialized_end=461
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
@@ -376,6 +376,48 @@ def test_extract_json_stdout_only_comments(capsys: pytest.CaptureFixture[str]) -
|
|||||||
assert captured.err == ''
|
assert captured.err == ''
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_txt(capsys: pytest.CaptureFixture[str], tmp_path: pathlib.Path) -> None:
|
||||||
|
# Arrange
|
||||||
|
output_file = str(tmp_path / 'test_example_output.txt')
|
||||||
|
|
||||||
|
# Act
|
||||||
|
extract_otp_secrets.main(['-q', '-t', output_file, 'example_export.txt'])
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
expected_txt = read_file_to_str('tests/data/printqr_output.txt')
|
||||||
|
actual_txt = read_file_to_str(output_file)
|
||||||
|
|
||||||
|
assert actual_txt == expected_txt
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
|
assert captured.out == ''
|
||||||
|
assert captured.err == ''
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_txt_stdout(capsys: pytest.CaptureFixture[str]) -> None:
|
||||||
|
# Act
|
||||||
|
extract_otp_secrets.main(['-t', '-', 'example_export.txt'])
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
expected_txt = read_file_to_str('tests/data/printqr_output.txt')
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
|
assert captured.out == expected_txt
|
||||||
|
assert captured.err == ''
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_txt_stdout_only_comments(capsys: pytest.CaptureFixture[str]) -> None:
|
||||||
|
# Act
|
||||||
|
extract_otp_secrets.main(['-t', '-', 'tests/data/only_comments.txt'])
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
|
assert captured.out == ''
|
||||||
|
assert captured.err == ''
|
||||||
|
|
||||||
|
|
||||||
def test_extract_not_encoded_plus(capsys: pytest.CaptureFixture[str]) -> None:
|
def test_extract_not_encoded_plus(capsys: pytest.CaptureFixture[str]) -> None:
|
||||||
# Act
|
# Act
|
||||||
extract_otp_secrets.main(['tests/data/test_plus_problem_export.txt'])
|
extract_otp_secrets.main(['tests/data/test_plus_problem_export.txt'])
|
||||||
@@ -724,8 +766,10 @@ def test_verbose_and_quiet(capsys: pytest.CaptureFixture[str]) -> None:
|
|||||||
('-k', 'outfile', False, False),
|
('-k', 'outfile', False, False),
|
||||||
('-k', '-', True, False),
|
('-k', '-', True, False),
|
||||||
('-j', 'outfile', False, False),
|
('-j', 'outfile', False, False),
|
||||||
('-s', 'outfile', False, False),
|
|
||||||
('-j', '-', True, False),
|
('-j', '-', True, False),
|
||||||
|
('-t', 'outfile', False, False),
|
||||||
|
('-t', '-', True, False),
|
||||||
|
('-s', 'outfile', False, False),
|
||||||
('-i', None, False, False),
|
('-i', None, False, False),
|
||||||
('-p', None, True, False),
|
('-p', None, True, False),
|
||||||
('-Q', 'CV2', False, False),
|
('-Q', 'CV2', False, False),
|
||||||
|
|||||||
Reference in New Issue
Block a user