Skip to content

Commit 4ba0fad

Browse files
committed
capture QR codes from camera and major refactoring
- add GUI for QR code capturing from camera (CV2 is used) - support different QR readers: ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT - support several input files - add option to ignore duplicate otps - write warnings and errors to stderr - add output coloring - rename project from extract_otp_secret_keys to extract_otp_secrets - improve help - clean verbose level output - use Python type hints and check with mypy - use f-strings - clean up code - add more tests - calculate code coverage - use src-layout: move files and folders - support wheel packing - enhance README.md - bugfixes * fix -k - * fix utf-8 encoding on windows
1 parent 9d052dc commit 4ba0fad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3793
-1945
lines changed

.editorconfig

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,11 @@ indent_style = space
55
indent_size = 4
66
charset = utf-8
77
trim_trailing_whitespace = true
8-
insert_final_newline = true
8+
insert_final_newline = true
9+
10+
[*.md]
11+
indent_size = 4
12+
trim_trailing_whitespace = false
13+
14+
[*.{yml,toml}]
15+
indent_size = 2

.github/workflows/ci.yml

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
name: tests
22

3+
# https://docs.github.com/de/actions/using-workflows/workflow-syntax-for-github-actions
4+
# https://docs.github.com/en/actions/using-workflows
5+
36
on:
47
push:
58
pull_request:
69
schedule:
10+
# Run daily on default branch
711
- cron: '37 3 * * *'
812

913
jobs:
@@ -13,9 +17,7 @@ jobs:
1317
matrix:
1418
python-version: ["3.x", "3.11", "3.10", "3.9", "3.8", "3.7"]
1519
platform: [ubuntu-latest, macos-latest, windows-latest]
16-
exclude:
17-
- platform: windows-latest
18-
- python-version: [pypy-3.9]
20+
# exclude:
1921

2022
runs-on: ${{ matrix.platform }}
2123

@@ -36,13 +38,31 @@ jobs:
3638
- name: Install dependencies
3739
run: |
3840
python -m pip install --upgrade pip
39-
pip install flake8 pytest
40-
pip install --use-pep517 -r requirements.txt
41+
pip install -U -r requirements-dev.txt
42+
pip install -U .
4143
- name: Lint with flake8
4244
run: |
4345
# stop the build if there are Python syntax errors or undefined names
4446
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
4547
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
4648
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=200 --statistics
49+
if: matrix.python-version != '3.7'
50+
- name: Type checking with mypy
51+
run: |
52+
mypy --install-types --non-interactive src/*.py tests/*.py
53+
mypy --strict src/*.py tests/*.py
54+
if: matrix.python-version == '3.x' && matrix.platform == 'ubuntu-latest'
4755
- name: Test with pytest
4856
run: pytest
57+
if: (matrix.python-version != '3.x' || matrix.platform != 'ubuntu-latest')
58+
# && matrix.platform != 'macos-latest'
59+
- name: Test with pytest (with code coverage)
60+
run: pytest --cov=extract_otp_secrets_test --junitxml=pytest.xml --cov-report=term-missing | tee pytest-coverage.txt
61+
if: matrix.python-version == '3.x' && matrix.platform == 'ubuntu-latest'
62+
# https://github.com/marketplace/actions/pytest-coverage-comment
63+
- name: Pytest coverage comment
64+
uses: MishaKav/pytest-coverage-comment@main
65+
with:
66+
pytest-coverage-path: ./pytest-coverage.txt
67+
junitxml-path: ./pytest.xml
68+
if: matrix.python-version == '3.x' && matrix.platform == 'ubuntu-latest'

.github/workflows/ci_docker.yml

+32-14
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
name: "Docker: build and publish"
1+
name: docker
2+
3+
# https://docs.github.com/de/actions/using-workflows/workflow-syntax-for-github-actions
4+
# https://docs.github.com/en/actions/using-workflows
25

36
# How to setup: https://event-driven.io/en/how_to_buid_and_push_docker_image_with_github_actions/
47
# How to run: https://aschmelyun.com/blog/using-docker-run-inside-of-github-actions/
58

69
on:
710
# run it on push to the default repository branch
811
push:
9-
# branches: [master]
10-
# run it during pull request
11-
# pull_request:
12+
schedule:
13+
# Run weekly on default branch
14+
- cron: '47 3 * * 6'
1215

1316
jobs:
1417
# define job to build and publish docker image
@@ -22,6 +25,15 @@ jobs:
2225
- name: Checkout code
2326
uses: actions/checkout@v3
2427

28+
# avoid building if there are testing errors
29+
- name: Run smoke test
30+
run: |
31+
sudo apt-get install -y libzbar0
32+
python -m pip install --upgrade pip
33+
pip install -U -r requirements-dev.txt
34+
pip install -U .
35+
pytest
36+
2537
- name: Set up QEMU
2638
uses: docker/setup-qemu-action@v2
2739

@@ -44,33 +56,39 @@ jobs:
4456
password: ${{ secrets.GHCR_IO_TOKEN }}
4557

4658
- name: "no_qr_reader: Build image and push to Docker Hub and GitHub Container Registry"
59+
id: docker_build_only_txt
4760
uses: docker/build-push-action@v2
4861
with:
4962
# relative path to the place where source code with Dockerfile is located
5063
platforms: linux/amd64,linux/arm64
5164
context: .
52-
file: Dockerfile_no_qr_reader
65+
file: Dockerfile_only_txt
66+
# builder: ${{ steps.buildx.outputs.name }}
5367
# Note: tags has to be all lower-case
5468
tags: |
55-
scit0/extract_otp_secret_keys_no_qr_reader:latest
56-
ghcr.io/scito/extract_otp_secret_keys_no_qr_reader:latest
69+
scit0/extract_otp_secrets:latest-only-txt
70+
ghcr.io/scito/extract_otp_secrets:latest-only-txt
5771
# build on feature branches, push only on master branch
58-
# TODO push: ${{ github.ref == 'refs/heads/master' }}
59-
push: true
72+
push: ${{ github.ref == 'refs/heads/master' }}
73+
build-args: |
74+
RUN_TESTS=true
6075
6176
- name: "qr_reader: Build image and push to Docker Hub and GitHub Container Registry"
77+
id: docker_build_qr_reader
6278
uses: docker/build-push-action@v2
6379
with:
6480
platforms: linux/amd64,linux/arm64
6581
# relative path to the place where source code with Dockerfile is located
6682
context: .
83+
# builder: ${{ steps.buildx.outputs.name }}
6784
# Note: tags has to be all lower-case
6885
tags: |
69-
scit0/extract_otp_secret_keys:latest
70-
ghcr.io/scito/extract_otp_secret_keys:latest
86+
scit0/extract_otp_secrets:latest
87+
ghcr.io/scito/extract_otp_secrets:latest
7188
# build on feature branches, push only on master branch
72-
# TODO push: ${{ github.ref == 'refs/heads/master' }}
73-
push: true
89+
push: ${{ github.ref == 'refs/heads/master' }}
7490

7591
- name: Image digest
76-
run: echo ${{ steps.docker_build.outputs.digest }}
92+
run: |
93+
echo "extract_otp_secrets: ${{ steps.docker_build_qr_reader.outputs.digest }}"
94+
echo "extract_otp_secrets_only_txt: ${{ steps.docker_build_only_txt.outputs.digest }}"

.gitignore

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ venv/
99
!example_output.csv
1010
!.github/
1111
!.flake8
12-
.vscode
13-
!.vscode/settings.json
12+
!.vscode/
1413
!.devcontainer/
1514
!.devcontainer/*.json
1615
*.whl
1716
build/
18-
extract_otp_secret_keys.egg-info/
17+
dist/
18+
*.egg-info/
19+
*.xml
20+
pytest-coverage.txt
21+
tests/reports/

.vscode/extensions.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"recommendations": [
3-
"ms-python.python"
3+
"ms-python.python",
4+
"ms-python.isort",
5+
"tamasfe.even-better-toml",
46
]
57
}

.vscode/launch.json

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python: extract_otp_secrets.py",
9+
"type": "python",
10+
"request": "launch",
11+
"program": "src/extract_otp_secrets.py",
12+
"args": [
13+
"example_export.txt"
14+
],
15+
"console": "integratedTerminal"
16+
},
17+
{
18+
"name": "Python: extract_otp_secrets.py stdin pic",
19+
"type": "python",
20+
"request": "launch",
21+
"program": "src/extract_otp_secrets.py",
22+
"args": [
23+
"-",
24+
"<",
25+
"test/test_googleauth_export.png",
26+
],
27+
"console": "integratedTerminal"
28+
},
29+
{
30+
"name": "Python: extract_otp_secrets.py capture",
31+
"type": "python",
32+
"request": "launch",
33+
"program": "src/extract_otp_secrets.py",
34+
"args": [
35+
],
36+
"console": "integratedTerminal"
37+
},
38+
]
39+
}

.vscode/settings.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"python.testing.pytestArgs": [
33
"."
44
],
5-
"python.testing.unittestEnabled": false,
5+
"python.testing.unittestEnabled": true,
66
"python.testing.pytestEnabled": true,
77
"cSpell.words": [
88
"devbox",
@@ -16,5 +16,9 @@
1616
"qrcode",
1717
"TOTP",
1818
"venv"
19-
]
19+
],
20+
"search.exclude": {
21+
"**/build": true,
22+
"**/dist": true
23+
},
2024
}

Dockerfile

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
FROM python:3.11-slim-bullseye
22

3+
# https://docs.docker.com/engine/reference/builder/
4+
5+
# For debugging
6+
# docker build . -t extract_otp_secrets --pull --build-arg RUN_TESTS=false
7+
# docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets
8+
# docker run --entrypoint /extract/run_pytest.sh --rm -v "$(pwd)":/files:ro extract_otp_secrets
9+
# docker run --entrypoint /bin/bash -it --rm -v "$(pwd)":/files:ro --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro extract_otp_secrets
10+
311
WORKDIR /extract
412

513
COPY . .
614

7-
ARG run_tests=true
15+
ARG RUN_TESTS=true
816

9-
RUN apt-get update && apt-get install -y libzbar0 python3-opencv nano \
10-
&& pip install -r requirements.txt \
11-
&& if [[ "$run_tests" == "true" ]] ; then /extract/run_pytest.sh ; else echo "Not running tests..." ; fi
17+
RUN apt-get update && apt-get install -y \
18+
libgl1 \
19+
libglib2.0-0 \
20+
libsm6 \
21+
libzbar0 \
22+
&& rm -rf /var/lib/apt/lists/* \
23+
&& pip install --no-cache-dir -U -r \
24+
requirements.txt \
25+
&& if [ "$RUN_TESTS" = "true" ]; then /extract/run_pytest.sh; else echo "Not running tests..."; fi
1226

1327
WORKDIR /files
1428

15-
ENTRYPOINT ["python", "/extract/extract_otp_secret_keys.py"]
29+
ENTRYPOINT ["python", "/extract/src/extract_otp_secrets.py"]
1630

17-
LABEL org.opencontainers.image.source https://github.com/scito/extract_otp_secret_keys
31+
LABEL org.opencontainers.image.source https://github.com/scito/extract_otp_secrets
32+
LABEL org.opencontainers.image.license GPL-3.0+

Dockerfile_no_qr_reader

-16
This file was deleted.

Dockerfile_only_txt

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM python:3.11-alpine
2+
3+
# https://docs.docker.com/engine/reference/builder/
4+
5+
# For debugging
6+
# docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets_only_txt
7+
# docker build . -t extract_otp_secrets_only_txt -f Dockerfile_only_txt --pull --build-arg RUN_TESTS=false
8+
# docker run --entrypoint /bin/sh -it --rm -v "$(pwd)":/files:ro extract_otp_secrets_only_txt
9+
# docker run --entrypoint /extract/run_pytest.sh --rm -v "$(pwd)":/files:ro extract_otp_secrets_only_txt tests/extract_otp_secrets_test.py -k "not qreader" --relaxed -vvv -s
10+
11+
WORKDIR /extract
12+
13+
COPY . .
14+
15+
ARG RUN_TESTS=true
16+
17+
RUN apk add --no-cache \
18+
jpeg \
19+
zlib \
20+
&& echo "Arch: $(apk --print-arch)" \
21+
&& if [[ "$(apk --print-arch)" == "aarch64" ]]; then apk add --no-cache --virtual .build-deps \
22+
gcc \
23+
jpeg-dev \
24+
libc-dev \
25+
py3-setuptools \
26+
python3-dev \
27+
zlib-dev \
28+
; fi \
29+
&& pip install --no-cache-dir -U \
30+
colorama \
31+
Pillow \
32+
protobuf \
33+
qrcode \
34+
&& if [[ "$(apk --print-arch)" == "aarch64" ]]; then apk del .build-deps; fi \
35+
&& if [[ "$RUN_TESTS" == "true" ]]; then /extract/run_pytest.sh tests/extract_otp_secrets_test.py -k "not qreader" --relaxed; else echo "Not running tests..."; fi
36+
37+
WORKDIR /files
38+
39+
ENTRYPOINT ["python", "/extract/src/extract_otp_secrets.py"]
40+
41+
LABEL org.opencontainers.image.source https://github.com/scito/extract_otp_secrets
42+
LABEL org.opencontainers.image.license GPL-3.0+

Pipfile

+8-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,20 @@ protobuf = "*"
88
qrcode = "*"
99
pillow = "*"
1010
qreader = "*"
11-
opencv-python = "*"
11+
opencv-contrib-python = "*"
12+
colorama = ">=0.4.6"
13+
# for macOS: opencv-contrib-python = "<=4.7.0"
14+
# for PYTHON <= 3.7: typing_extensions = "*"
1215

1316
[dev-packages]
1417
pytest = "*"
18+
pytest-mock = "*"
19+
pytest-cov = "*"
1520
wheel = "*"
1621
flake8 = "*"
1722
pylint = "*"
23+
mypy = "*"
24+
types-protobuf = "*"
1825

1926
[requires]
2027
python_version = "3.11"

0 commit comments

Comments
 (0)