diff --git a/README.md b/README.md index 464a716..ed786ea 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Extract TOTP/HOTP secret keys from Google Authenticator -[](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci.yml) +[](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci.yml)  -[](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci_docker.yml) +[](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci_docker.yml)  [](https://github.com/scito/extract_otp_secret_keys/blob/master/Pipfile.lock)  @@ -16,7 +16,8 @@ TODO add src/ TODO rename extract_otp_secret_keys Extract two-factor authentication (2FA, TFA, OTP) secret keys from export QR codes of "Google Authenticator" app. -The secret and otp values can be printed and exported to json or csv. The QR codes can be printed or saved as PNG images. +The QR codes can captured from the camera in a GUI, imported from images or from text files containing the QR code data. +The secret and otp values can be printed and exported to json or csv, as well as printed or saved as PNG images. ## Installation @@ -25,7 +26,7 @@ cd extract_otp_secret_keys ## Usage -### Capture QR codes from camera +### Capture QR codes from camera (since v2.0.0) 1. Open "Google Authenticator" app on the mobile phone 2. Export the QR codes from "Google Authenticator" app @@ -36,7 +37,7 @@ cd extract_otp_secret_keys  -### With builtin QR decoder from image files +### With builtin QR decoder from image files (since v2.0.0) 1. Open "Google Authenticator" app on the mobile phone 2. Export the QR codes from "Google Authenticator" app @@ -59,7 +60,7 @@ cd extract_otp_secret_keys ## Program help: arguments and options -
usage: extract_otp_secrets.py [-h] [--camera NUMBER] [--qr {QREADER,DEEP_QREADER,ZBAR,CV2,CV2_WECHAT}] [--json FILE] [--csv FILE] [--keepass FILE] [--printqr] [--saveqr DIR] [--no-color] [--verbose | --quiet] [infile ...]
+usage: extract_otp_secrets.py [-h] [--camera NUMBER] [--qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}] [--json FILE] [--csv FILE] [--keepass FILE] [--printqr] [--saveqr DIR] [--no-color] [--verbose | --quiet] [infile ...]
Extracts one time password (OTP) secret keys from QR codes, e.g. from Google Authenticator app.
If no infiles are provided, the QR codes are interactively captured from the camera.
@@ -71,7 +72,7 @@ positional arguments:
options:
-h, --help show this help message and exit
--camera NUMBER, -C NUMBER camera number of system (default camera: 0)
- --qr {QREADER,DEEP_QREADER,ZBAR,CV2,CV2_WECHAT}, -Q {QREADER,DEEP_QREADER,ZBAR,CV2,CV2_WECHAT}
+ --qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}, -Q {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}
QR reader (default: ZBAR)
--json FILE, -j FILE export json file or - for stdout
--csv FILE, -c FILE export csv file or - for stdout
@@ -102,40 +103,11 @@ For protobuf versions 3.14.0 or similar or Python 3.6, use the extract_otp_secre
### Shared libs installation for reading QR code images
-For reading QR code images the zbar library must be installed.
-If you do not extract directly from images, you do not need to install the zbar shared library.
+For reading QR code images the zbar library must be installed for `ZBAR` QR reader.
+If you do not extract directly from images or using catpuring from camera, you do not need to install the zbar shared library.
For a detailed installation documentation of [pyzbar](https://github.com/NaturalHistoryMuseum/pyzbar#installation).
-#### Windows
-
-The zbar DLLs are included with the Windows Python wheels. On other operating systems, you will need to install the zbar shared library.
-
-TODO Write installation, not error message
-
-##### Windows error message
-
-If you see an ugly ImportError when importing [pyzbar](https://pypi.org/project/pyzbar/) on Windows you will most likely need the [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-US/download/details.aspx?id=40784). Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python.
-
-```
-Traceback (most recent call last):
- File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 58, in load
- dependencies, libzbar = load_objects(Path(''))
- ^^^^^^^^^^^^^^^^^^^^^^
- File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 50, in load_objects
- deps = [
- ^
- File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 51, in
- cdll.LoadLibrary(str(directory.joinpath(dep)))
- File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 454, in LoadLibrary
- return self._dlltype(name)
- ^^^^^^^^^^^^^^^^^^^
- File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 376, in __init__
- self._handle = _dlopen(self._name, mode)
- ^^^^^^^^^^^^^^^^^^^^^^^^^
-FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependencies). Try using the full path with constructor syntax.
-```
-
#### Linux (Debian, Ubuntu, ...)
sudo apt-get install libzbar0
@@ -152,6 +124,10 @@ FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependenc
brew install zbar
+#### Windows
+
+The zbar DLLs are included with the Windows Python wheels. However, you might need to install [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-US/download/details.aspx?id=40784). Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python.
+
## Examples
### Printing otp secrets form text file
@@ -193,7 +169,12 @@ FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependenc
* Free and open source
* Supports Google Authenticator exports (and compatible apps like Aegis Authenticator)
-* Captures the the QR codes directly from the camera using QR code detection (based on OpenCV)
+* Captures the the QR codes directly from the camera using different QR code readers (based on OpenCV)
+ * ZBAR: fast and reliable, good for images and video capture (default/recommended) [pyzbar](https://github.com/NaturalHistoryMuseum/pyzbar)
+ * QREADER: fast [QReader](https://github.com/Eric-Canas/QReader)
+ * QREADER_DEEP: slow, not good for camera [QReader](https://github.com/Eric-Canas/QReader)
+ * CV2: fast [QRCodeDetector](https://docs.opencv.org/4.x/de/dc3/classcv_1_1QRCodeDetector.html)
+ * CV2_WECHAT: fast [WeChatQRCode](https://docs.opencv.org/4.x/dd/d63/group__wechat__qrcode.html)
* Supports TOTP and HOTP
* Generates QR codes
* Exports to various formats:
@@ -390,6 +371,8 @@ docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets example_export.txt
docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets example_export.png
```
+TODO link to docker/github repos
+
docker run --rm -v "$(pwd)":/files:ro -i extract_otp_secrets = < example_export.png
docker run --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro extract_otp_secrets
docker run --pull always --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro scit0/extract_otp_secrets
@@ -410,6 +393,17 @@ docker pull scit0/extract_otp_secrets_only_txt
docker pull ghcr.io/scito/extract_otp_secrets
docker pull ghcr.io/scito/extract_otp_secrets_only_txt
+### Docker examples
+
+
+docker run --pull always --rm -v \"$(pwd)\":/files:ro scit0/extract_otp_secrets example_export.png
+
+docker run --pull always --rm -i -v \"$(pwd)\":/files:ro scit0/extract_otp_secrets_only_txt - < example_export.txt
+
+cat example_export.txt | docker run --pull always --rm -i -v \"$(pwd)\":/files:ro scit0/extract_otp_secrets_only_txt - -c - > example_out.csv
+
+docker run --pull always --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro scit0/extract_otp_secrets
+
## Tests
### PyTest
@@ -484,6 +478,35 @@ pip install -U -r requirements.txt
https://github.com/opencv/opencv/issues/23072
+## Problems and Troubleshooting
+
+### Windows error message
+
+If you see an ugly ImportError on Windows you will most likely need the [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-US/download/details.aspx?id=40784). Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python.
+
+This library shared library is required by [pyzbar](https://pypi.org/project/pyzbar/).
+
+```
+Traceback (most recent call last):
+ File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 58, in load
+ dependencies, libzbar = load_objects(Path(''))
+ ^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 50, in load_objects
+ deps = [
+ ^
+ File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 51, in
+ cdll.LoadLibrary(str(directory.joinpath(dep)))
+ File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 454, in LoadLibrary
+ return self._dlltype(name)
+ ^^^^^^^^^^^^^^^^^^^
+ File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 376, in __init__
+ self._handle = _dlopen(self._name, mode)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependencies). Try using the full path with constructor syntax.
+```
+
+
+
## Related projects
* [ZBar](https://github.com/mchehab/zbar) is an open source software suite for reading bar codes from various sources, including webcams.
diff --git a/build.sh b/build.sh
index e75d827..03bfd2e 100755
--- a/build.sh
+++ b/build.sh
@@ -82,6 +82,7 @@ interactive=true
ignore_version_check=true
clean=false
build_docker=true
+run_gui=true
while test $# -gt 0; do
case $1 in
@@ -94,6 +95,7 @@ while test $# -gt 0; do
echo "-a Automatic mode"
echo "-C Ignore version check"
echo "-D No docker build"
+ echo "-G No not run gui"
echo "-c Clean"
echo "-h, --help Help"
quit
@@ -110,6 +112,10 @@ while test $# -gt 0; do
build_docker=false
shift
;;
+ -G)
+ run_gui=false
+ shift
+ ;;
-c)
clean=true
shift
@@ -204,7 +210,7 @@ fi
# Upgrade pip requirements
-cmd="sudo pip install --upgrade pip"
+cmd="sudo pip install -U pip"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
@@ -266,7 +272,7 @@ eval "$cmd"
# pip install
-cmd="$PIP install -e ."
+cmd="$PIP install -U -e ."
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
@@ -324,6 +330,7 @@ if $build_docker; then
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
+
# Build extract_otp_secrets (Debian)
cmd="docker build . -t extract_otp_secrets --pull --build-arg RUN_TESTS=false"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
@@ -333,7 +340,11 @@ if $build_docker; then
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
- cmd="docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets - < example_export.txt"
+ cmd="cat mple_export.txt | docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets - -c - > example_output.csv"
+ if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
+ eval "$cmd"
+
+ cmd="docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets = < example_export.png"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
@@ -344,10 +355,20 @@ if $build_docker; then
cmd="docker image prune -f || echo 'No docker image pruned'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
+
+ if $run_gui; then
+ cmd="docker run --pull always --rm -v "$(pwd)":/files:ro --device=\"/dev/video0:/dev/video0\" --env=\"DISPLAY\" -v /tmp/.X11-unix:/tmp/.X11-unix:ro extract_otp_secrets &"
+ if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
+ fi
+ eval "$cmd"
fi
-cmd="$PYTHON src/extract_otp_secrets.py &"
-if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
-eval "$cmd"
+if $run_gui; then
+ cmd="$PYTHON src/extract_otp_secrets.py &"
+ if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
+ eval "$cmd"
+fi
+
+echo -e "${greenBold}Sucessful${reset}"
quit
diff --git a/src/extract_otp_secrets.py b/src/extract_otp_secrets.py
index d7423a0..2900b83 100644
--- a/src/extract_otp_secrets.py
+++ b/src/extract_otp_secrets.py
@@ -1,3 +1,4 @@
+# TODO rewrite
# Extract two-factor authentication (2FA, TFA) secret keys from export QR codes of "Google Authenticator" app
#
# Usage:
@@ -118,7 +119,7 @@ Otps = List[Otp]
# workaround for PYTHON <= 3.9: OtpUrls = list[OtpUrl]
OtpUrls = List[OtpUrl]
-QRMode = Enum('QRMode', ['QREADER', 'DEEP_QREADER', 'ZBAR', 'CV2', 'CV2_WECHAT'], start=0)
+QRMode = Enum('QRMode', ['ZBAR', 'QREADER', 'QREADER_DEEP', 'CV2', 'CV2_WECHAT'], start=0)
# Constants
@@ -256,9 +257,9 @@ def extract_otps_from_camera(args: Args) -> Otps:
log_error("Failed to capture image from camera")
break
try:
- if qr_mode in [QRMode.QREADER, QRMode.DEEP_QREADER]:
+ if qr_mode in [QRMode.QREADER, QRMode.QREADER_DEEP]:
found, bbox = qreader.detect(img)
- if qr_mode == QRMode.DEEP_QREADER:
+ if qr_mode == QRMode.QREADER_DEEP:
otp_url = qreader.detect_and_decode(img, True)
elif qr_mode == QRMode.QREADER:
otp_url = qreader.decode(img, bbox) if found else None
@@ -448,8 +449,8 @@ def convert_img_to_otp_url(filename: str, args: Args) -> OtpUrls:
qr_mode = QRMode[args.qr]
otp_urls: OtpUrls = []
- if qr_mode in [QRMode.QREADER, QRMode.DEEP_QREADER]:
- otp_url = QReader().detect_and_decode(img, qr_mode == QRMode.DEEP_QREADER)
+ if qr_mode in [QRMode.QREADER, QRMode.QREADER_DEEP]:
+ otp_url = QReader().detect_and_decode(img, qr_mode == QRMode.QREADER_DEEP)
otp_urls.append(otp_url)
elif qr_mode == QRMode.CV2:
otp_url, _, _ = cv2.QRCodeDetector().detectAndDecode(img)