docker remove python3-opencv, but add required libs; add debug mode
This commit is contained in:
@@ -15,9 +15,10 @@ COPY . .
|
||||
ARG RUN_TESTS=true
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libgl1 \
|
||||
libglib2.0-0 \
|
||||
libsm6 \
|
||||
libzbar0 \
|
||||
python3-opencv \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir -U -r \
|
||||
requirements.txt \
|
||||
|
||||
20
README.md
20
README.md
@@ -29,9 +29,13 @@ This script/project was renamed from extract_otp_secret_keys to extract_otp_secr
|
||||
git clone https://github.com/scito/extract_otp_secrets.git
|
||||
cd extract_otp_secrets
|
||||
pip install -U -r requirements.txt
|
||||
|
||||
python src/extract_otp_secrets.py example_export.txt
|
||||
```
|
||||
|
||||
### Installation of shared libraries for ZBAR QR reader
|
||||
In case this script is not starting properly, the debug mode can be activated by adding parameter `-d` in the command line.
|
||||
|
||||
### Installation of shared system libraries
|
||||
|
||||
For reading QR codes with `ZBAR` QR reader, the zbar library must be installed.
|
||||
If you do not use the `ZBAR` QR reader, you do not need to install the zbar shared library. Note: The `ZBAR` QR reader is the showed for me the best results and is thus default QR Reader.
|
||||
@@ -56,7 +60,13 @@ For a detailed installation documentation of [pyzbar](https://github.com/Natural
|
||||
|
||||
#### Windows
|
||||
|
||||
The zbar DLLs are included with the Windows Python wheels. However, you might need additionally 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.
|
||||
##### zbar
|
||||
|
||||
The zbar DLLs are included with the Windows Python wheels. However, you might need additionally 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. For more information see [pyzbar](https://github.com/NaturalHistoryMuseum/pyzbar)
|
||||
|
||||
##### OpenCV
|
||||
|
||||
OpenCV requires [Visual C++ redistributable 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145). For more information see [opencv-python](https://pypi.org/project/opencv-python/)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -94,7 +104,9 @@ The zbar DLLs are included with the Windows Python wheels. However, you might ne
|
||||
|
||||
## Program help: arguments and options
|
||||
|
||||
<pre>Extracts one time password (OTP) secrets from QR codes exported by two-factor authentication (2FA) apps
|
||||
<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] [-d | -v | -q] [infile ...]
|
||||
|
||||
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.
|
||||
|
||||
positional arguments:
|
||||
@@ -113,6 +125,7 @@ options:
|
||||
QR reader (default: ZBAR)
|
||||
-i, --ignore ignore duplicate otps
|
||||
--no-color, -n do not use ANSI colors in console output
|
||||
-d, --debug enter debug mode, do checks and quit
|
||||
-v, --verbose verbose output
|
||||
-q, --quiet no stdout output, except output set by -
|
||||
|
||||
@@ -460,6 +473,7 @@ docker build . -t extract_otp_secrets_only_txt --pull -f Dockerfile_only_txt --b
|
||||
```
|
||||
|
||||
Run tests in docker container:
|
||||
|
||||
```bash
|
||||
docker run --entrypoint /extract/run_pytest.sh --rm -v "$(pwd)":/files:ro extract_otp_secrets
|
||||
```
|
||||
|
||||
98
build.sh
98
build.sh
@@ -230,30 +230,6 @@ cmd="$PIP install --use-pep517 -U -r requirements-dev.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PIP install -U pipenv"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="sudo $PIP install --use-pep517 -U -r requirements.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="sudo $PIP install --use-pep517 -U -r requirements-dev.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="sudo $PIP install -U pipenv"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
$PIPENV --version
|
||||
|
||||
cmd="$PIPENV update && $PIPENV --rm && $PIPENV install"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
$PIPENV run python --version
|
||||
|
||||
# Lint
|
||||
|
||||
LINT_OUT_FILE="tests/reports/flake8_results.txt"
|
||||
@@ -278,7 +254,54 @@ cmd="$MYPY --strict src/*.py tests/*.py | tee $TYPE_CHECK_OUT_FILE"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# pip install
|
||||
# Test
|
||||
|
||||
cmd="$PYTHON src/extract_otp_secrets.py example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PYTHON src/extract_otp_secrets.py - < example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
COVERAGE_OUT_FILE="tests/reports/pytest-coverage.txt"
|
||||
cmd="pytest --cov=extract_otp_secrets_test --junitxml=tests/reports/pytest.xml --cov-report html:tests/reports/html --cov-report=term-missing tests/ | tee $COVERAGE_OUT_FILE"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Pipenv
|
||||
|
||||
cmd="$PIP install -U pipenv"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
$PIPENV --version
|
||||
|
||||
cmd="$PIPENV update && $PIPENV --rm && $PIPENV install"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
$PIPENV run python --version
|
||||
|
||||
cmd="$PIPENV run pytest --cov=extract_otp_secrets_test tests/"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# sudo pip
|
||||
|
||||
cmd="sudo $PIP install --use-pep517 -U -r requirements.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="sudo $PIP install --use-pep517 -U -r requirements-dev.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="sudo $PIP install -U pipenv"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# pip -e install (must be after other pip installs in order to have this environment for development)
|
||||
|
||||
cmd="$PIP install -U -e ."
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
@@ -300,25 +323,6 @@ if $generate_result_files; then
|
||||
eval "$cmd"
|
||||
fi
|
||||
|
||||
# Test
|
||||
|
||||
cmd="$PYTHON src/extract_otp_secrets.py example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PYTHON src/extract_otp_secrets.py - < example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
COVERAGE_OUT_FILE="tests/reports/pytest-coverage.txt"
|
||||
cmd="pytest --cov=extract_otp_secrets_test --junitxml=tests/reports/pytest.xml --cov-report html:tests/reports/html --cov-report=term-missing tests/ | tee $COVERAGE_OUT_FILE"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PIPENV run pytest --cov=extract_otp_secrets_test tests/"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Update Code Coverage in README.md
|
||||
|
||||
# https://github.com/marketplace/actions/pytest-coverage-comment
|
||||
@@ -356,7 +360,7 @@ if $build_docker; then
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="cat mple_export.txt | docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets - -c - > example_output.csv"
|
||||
cmd="cat example_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"
|
||||
|
||||
@@ -373,10 +377,10 @@ if $build_docker; then
|
||||
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 &"
|
||||
cmd="docker run --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
|
||||
eval "$cmd"
|
||||
fi
|
||||
eval "$cmd"
|
||||
fi
|
||||
|
||||
if $run_gui; then
|
||||
|
||||
@@ -55,6 +55,8 @@ from qrcode import QRCode # type: ignore
|
||||
import protobuf_generated_python.google_auth_pb2 as pb
|
||||
import colorama
|
||||
|
||||
debug_mode = '-d' in sys.argv[1:] or '--debug' in sys.argv[1:]
|
||||
|
||||
try:
|
||||
import cv2 # type: ignore # TODO use cv2 types if available
|
||||
|
||||
@@ -64,11 +66,12 @@ try:
|
||||
import pyzbar.pyzbar as zbar # type: ignore
|
||||
from qreader import QReader # type: ignore
|
||||
except ImportError as e:
|
||||
raise SystemExit(f"""
|
||||
print(f"""
|
||||
ERROR: Cannot import QReader module. This problem is probably due to the missing zbar shared library.
|
||||
On Linux and macOS libzbar0 must be installed.
|
||||
See in README.md for the installation of the libzbar0.
|
||||
Exception: {e}""")
|
||||
Exception: {e}\n""", file=sys.stderr)
|
||||
raise e
|
||||
|
||||
# Types
|
||||
# workaround for PYTHON <= 3.9: Final[tuple[int]]
|
||||
@@ -102,8 +105,10 @@ Exception: {e}""")
|
||||
TextPosition = Enum('TextPosition', ['LEFT', 'RIGHT'])
|
||||
|
||||
qreader_available = True
|
||||
except ImportError:
|
||||
except ImportError as e:
|
||||
qreader_available = False
|
||||
if debug_mode:
|
||||
raise e
|
||||
|
||||
# Workaround for PYTHON <= 3.9: Union[int, None] used instead of int | None
|
||||
|
||||
@@ -150,6 +155,9 @@ def main(sys_args: list[str]) -> None:
|
||||
if colored:
|
||||
colorama.just_fix_windows_console()
|
||||
|
||||
if args.debug:
|
||||
sys.exit(0 if do_debug_checks() else 1)
|
||||
|
||||
otps = extract_otps(args)
|
||||
write_csv(args, otps)
|
||||
write_keepass_csv(args, otps)
|
||||
@@ -184,15 +192,19 @@ b) image file containing a QR code or = for stdin for an image containing a QR c
|
||||
arg_parser.add_argument('-i', '--ignore', help='ignore duplicate otps', action='store_true')
|
||||
arg_parser.add_argument('--no-color', '-n', help='do not use ANSI colors in console output', action='store_true')
|
||||
output_group = arg_parser.add_mutually_exclusive_group()
|
||||
output_group.add_argument('-d', '--debug', help='enter debug mode, do checks and quit', action='count')
|
||||
output_group.add_argument('-v', '--verbose', help='verbose output', action='count')
|
||||
output_group.add_argument('-q', '--quiet', help='no stdout output, except output set by -', action='store_true')
|
||||
args = arg_parser.parse_args(sys_args)
|
||||
colored = not args.no_color
|
||||
if args.csv == '-' or args.json == '-' or args.keepass == '-':
|
||||
args.quiet = args.q = True
|
||||
|
||||
verbose = args.verbose if args.verbose else LogLevel.NORMAL
|
||||
if args.debug:
|
||||
verbose = LogLevel.DEBUG
|
||||
log_debug('Debug mode start')
|
||||
quiet = True if args.quiet else False
|
||||
colored = not args.no_color
|
||||
if verbose: print(f"QReader installed: {qreader_available}")
|
||||
if qreader_available:
|
||||
if verbose >= LogLevel.VERBOSE: print(f"CV2 version: {cv2.__version__}")
|
||||
@@ -706,6 +718,16 @@ def next_qr_mode(qr_mode: QRMode) -> QRMode:
|
||||
return QRMode((qr_mode.value + 1) % len(QRMode))
|
||||
|
||||
|
||||
def do_debug_checks() -> bool:
|
||||
log_debug('Do debug checks')
|
||||
log_debug('Try: import cv2')
|
||||
import cv2 # noqa: F401 # This is only a debug import
|
||||
log_debug('Try: import numpy as np')
|
||||
import numpy as np # noqa: F401 # This is only a debug import
|
||||
print(color('\nDebug checks passed', colorama.Fore.GREEN))
|
||||
return True
|
||||
|
||||
|
||||
# workaround for PYTHON <= 3.9 use: BaseException | None
|
||||
def log_debug(*values: object, sep: Optional[str] = ' ') -> None:
|
||||
if colored:
|
||||
|
||||
Reference in New Issue
Block a user