mirror of
https://github.com/scito/extract_otp_secrets.git
synced 2025-12-12 09:49:46 +01:00
Compare commits
195 Commits
v2.8.1
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04a7271611 | ||
|
|
214662e419 | ||
|
|
47f2f9f4f7 | ||
|
|
3ec381df53 | ||
|
|
c366a4eece | ||
|
|
9d54cd6c3a | ||
|
|
865aaaef28 | ||
|
|
7616ee094f | ||
|
|
6edefa9cb8 | ||
|
|
897e4051c1 | ||
|
|
8856f648f6 | ||
|
|
000acbf8b9 | ||
|
|
bb852f382b | ||
|
|
1be8e4ed1c | ||
|
|
3d0be22e4a | ||
|
|
c38ebd4d1a | ||
|
|
531f9660f3 | ||
|
|
13231a4f61 | ||
|
|
2b990376a6 | ||
|
|
e323db3216 | ||
|
|
27418b6675 | ||
|
|
54e1a03b6b | ||
|
|
8dd1db7081 | ||
|
|
384b105346 | ||
|
|
4ceb5e78e4 | ||
|
|
b59187bd82 | ||
|
|
f386aa9d1d | ||
|
|
a8fe2cd32c | ||
|
|
6b1bc4ee06 | ||
|
|
f4b81d890c | ||
|
|
7ab0744495 | ||
|
|
0a0baebaad | ||
|
|
96e92dc295 | ||
|
|
6b163cd377 | ||
|
|
c9d30e8aca | ||
|
|
3aad6677d8 | ||
|
|
957a9d1f8f | ||
|
|
d6677623ec | ||
|
|
5febef269a | ||
|
|
7c3530cf27 | ||
|
|
d9b6211715 | ||
|
|
dab2599d29 | ||
|
|
37738e8990 | ||
|
|
4e968334ca | ||
|
|
d04902e749 | ||
|
|
4ea404f16f | ||
|
|
4d0b5db83f | ||
|
|
7f8e69fe8c | ||
|
|
c8fa3bb6c0 | ||
|
|
93406cfcbb | ||
|
|
c11854e164 | ||
|
|
0094422e9d | ||
|
|
d4d22e692b | ||
|
|
66e166c51c | ||
|
|
c51ac0bdde | ||
|
|
949ee29fa4 | ||
|
|
6e20d73b12 | ||
|
|
f629c7f3e4 | ||
|
|
6c3dbe48e9 | ||
|
|
b5dedda9a8 | ||
|
|
6e32b7b18e | ||
|
|
5fa99a17d7 | ||
|
|
563308700a | ||
|
|
716194da48 | ||
|
|
bb41c737ef | ||
|
|
bb4c3da0bf | ||
|
|
e0dac0fd99 | ||
|
|
3040965d79 | ||
|
|
3899f5f826 | ||
|
|
f82c79aa7d | ||
|
|
68ced0f2ec | ||
|
|
d1ce4c0ba4 | ||
|
|
ed7a9f5143 | ||
|
|
8f7c267153 | ||
|
|
0c68efd06e | ||
|
|
5f01b50635 | ||
|
|
cf618281d8 | ||
|
|
e3a1443b9b | ||
|
|
863f3f3128 | ||
|
|
edee97a54c | ||
|
|
e01c81aca1 | ||
|
|
f713a8ef39 | ||
|
|
bfc2c0d853 | ||
|
|
8a8e92bfef | ||
|
|
d26a521997 | ||
|
|
223f1e4b5b | ||
|
|
5ffa2d9dcc | ||
|
|
5c9c680561 | ||
|
|
c9cdc10a73 | ||
|
|
750ca3e13b | ||
|
|
a2bf1533ae | ||
|
|
7fa0e3f555 | ||
|
|
56e74d5ccb | ||
|
|
10737a91c4 | ||
|
|
d29eab943e | ||
|
|
e17fed8704 | ||
|
|
b09d2c6c1f | ||
|
|
208e6e60fc | ||
|
|
1851664c96 | ||
|
|
ab0cd6717a | ||
|
|
ccb52cc8b5 | ||
|
|
41ed2b62d4 | ||
|
|
b6ab6417cb | ||
|
|
e857912c74 | ||
|
|
ac18fbf020 | ||
|
|
494a9f8446 | ||
|
|
cec47852d8 | ||
|
|
d5a8b6f0c0 | ||
|
|
95c34277ca | ||
|
|
ca6ca1f0e6 | ||
|
|
026db54551 | ||
|
|
793b061d3f | ||
|
|
7557ae125a | ||
|
|
f94120b84c | ||
|
|
787a975009 | ||
|
|
95c1cc3cfe | ||
|
|
95176ee9de | ||
|
|
7b379b58a3 | ||
|
|
10a60ab556 | ||
|
|
38e7e8b40b | ||
|
|
6b25cc96e2 | ||
|
|
4799483b2b | ||
|
|
3e6eeffff5 | ||
|
|
00d25e89d9 | ||
|
|
f7453c7720 | ||
|
|
77d799a461 | ||
|
|
9a0d8dbc80 | ||
|
|
9f39cc4508 | ||
|
|
08dbda3b80 | ||
|
|
8317ef0bf2 | ||
|
|
b9c5833374 | ||
|
|
b6f5c41559 | ||
|
|
e665d159f6 | ||
|
|
d9bd792394 | ||
|
|
cb8ef2ae22 | ||
|
|
fa8506935f | ||
|
|
c49ba82f1b | ||
|
|
f11b2d2483 | ||
|
|
894edb4561 | ||
|
|
4c4b033aa4 | ||
|
|
f6a003d707 | ||
|
|
6a2dc80ad4 | ||
|
|
b54974e584 | ||
|
|
a2845556a4 | ||
|
|
7ce765ddb1 | ||
|
|
fc9b36d281 | ||
|
|
556d1350b8 | ||
|
|
a84d52fb38 | ||
|
|
2928168bc2 | ||
|
|
5714d71e7c | ||
|
|
170fbf6edb | ||
|
|
d2993c093c | ||
|
|
c9a2784e56 | ||
|
|
59804c9970 | ||
|
|
5955c1dc69 | ||
|
|
bfb63ebf49 | ||
|
|
396071f15a | ||
|
|
6503b442f1 | ||
|
|
5c5e2096b8 | ||
|
|
eb8bb38aa5 | ||
|
|
d486a94c6f | ||
|
|
ee932c05e3 | ||
|
|
e13a4584fb | ||
|
|
91e2efe7e1 | ||
|
|
b5442a0d94 | ||
|
|
2318c3a185 | ||
|
|
fcfdf1cbf6 | ||
|
|
f07db1b74f | ||
|
|
5d5453231f | ||
|
|
5d7afeeed3 | ||
|
|
d9f760ad97 | ||
|
|
6c54a438cb | ||
|
|
9d4f8c83b4 | ||
|
|
9b8c79b232 | ||
|
|
50151c4f3f | ||
|
|
5c7fe2352e | ||
|
|
7c31f988c8 | ||
|
|
fce36ee279 | ||
|
|
9463dc3e88 | ||
|
|
5986cf32ff | ||
|
|
64980e71df | ||
|
|
b8c7979c78 | ||
|
|
7f34488ad2 | ||
|
|
c553d9ae90 | ||
|
|
8599683cc7 | ||
|
|
d026a245ed | ||
|
|
f12c5df41c | ||
|
|
79c01e5b88 | ||
|
|
60de43cd44 | ||
|
|
c57d6a681f | ||
|
|
dd537ccbf4 | ||
|
|
ed9ab3af07 | ||
|
|
99291ed2be | ||
|
|
3ea20f245c | ||
|
|
bd5be0239d |
@@ -6,7 +6,7 @@
|
||||
"context": "..",
|
||||
//Update 'VARIANT' to pick a Python version: 3, 3.10, ...
|
||||
"args": {
|
||||
"VARIANT": "3.11"
|
||||
"VARIANT": "3.14"
|
||||
}
|
||||
},
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
|
||||
3
.envrc
Normal file
3
.envrc
Normal file
@@ -0,0 +1,3 @@
|
||||
source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0="
|
||||
|
||||
use devenv
|
||||
21
.gitattributes
vendored
Normal file
21
.gitattributes
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
* text eol=lf
|
||||
*.csv text eol=auto
|
||||
*.txt text eol=auto
|
||||
*.md text eol=auto
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
*.png binary
|
||||
*.webp binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.zip binary
|
||||
*.tar binary
|
||||
*.gz binary
|
||||
*.7z binary
|
||||
*.exe binary
|
||||
*.dll binary
|
||||
*.pdf binary
|
||||
17
.github/copilot-instructions.md
vendored
Normal file
17
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copilot Instructions
|
||||
|
||||
This project is a web application that allows users to create and manage tasks. The application is built using Python.
|
||||
|
||||
## Coding Standards
|
||||
|
||||
- Use snakeCase for variable and function names.
|
||||
- Use PascalCase for component names.
|
||||
- Use double quotes for strings.
|
||||
- Use 4 spaces for indentation.
|
||||
|
||||
## Tone
|
||||
|
||||
- If I tell you that you are wrong, think about whether or not you think that's true and respond with facts.
|
||||
- Avoid apologizing or making conciliatory statements.
|
||||
- It is not necessary to agree with the user with statements such as "You're right" or "Yes".
|
||||
- Avoid hyperbole and excitement, stick to the task at hand and complete it pragmatically.
|
||||
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'build.sh'
|
||||
# pull_request:
|
||||
schedule:
|
||||
# Run daily on default branch
|
||||
@@ -19,20 +20,23 @@ jobs:
|
||||
build:
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
# exclude:
|
||||
# 3.x is used to run code coverage
|
||||
python-version: ["3.x", "3.14", "3.13", "3.12", "3.11", "3.10", "3.9"]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest, ubuntu-24.04-arm, macos-15-intel]
|
||||
# exclude:
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: ${{ github.event_name == 'schedule' }}
|
||||
allow-prereleases: false
|
||||
- name: Install zbar shared lib for QReader (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
@@ -52,7 +56,6 @@ jobs:
|
||||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=200 --statistics
|
||||
if: matrix.python-version != '3.7'
|
||||
- name: Type checking with mypy
|
||||
run: |
|
||||
mypy --install-types --non-interactive src/*.py tests/*.py
|
||||
|
||||
230
.github/workflows/ci_docker.yml
vendored
230
.github/workflows/ci_docker.yml
vendored
@@ -14,6 +14,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'build.sh'
|
||||
tags-ignore:
|
||||
- '**'
|
||||
# branches is needed if tags-ignore is used
|
||||
@@ -27,12 +28,22 @@ jobs:
|
||||
build-and-push-docker-debian-image:
|
||||
name: Build Docker Bookworm image and push to repositories
|
||||
# run only when code is compiling and tests are passing
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- DOCKER_ARCH: amd64
|
||||
platform: ubuntu-latest
|
||||
PLATFORM_ARCH: x86_64
|
||||
- DOCKER_ARCH: arm64
|
||||
platform: ubuntu-24.04-arm
|
||||
PLATFORM_ARCH: arm64
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
# steps to perform in job
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# avoid building if there are testing errors
|
||||
- name: Run smoke test
|
||||
@@ -50,11 +61,6 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
# Workaround for failing builds: https://github.com/docker/build-push-action/issues/761#issuecomment-1383822381
|
||||
# TODO remove workaround when fixed
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:v0.10.6
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
@@ -71,11 +77,11 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GHCR_IO_TOKEN }}
|
||||
|
||||
- name: "Build image and push to Docker Hub and GitHub Container Registry"
|
||||
- name: "Build image (Bookworm/Debian 12) and push to Docker Hub and GitHub Container Registry"
|
||||
id: docker_build_qr_reader_latest
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/${{ matrix.DOCKER_ARCH }}
|
||||
# relative path to the place where source code with Dockerfile is located
|
||||
# TODO file:, move to docker/
|
||||
context: .
|
||||
@@ -83,13 +89,15 @@ jobs:
|
||||
# builder: ${{ steps.buildx.outputs.name }}
|
||||
# Note: tags has to be all lower-case
|
||||
build-args: |
|
||||
BASE_IMAGE=python:3.12-slim-bookworm
|
||||
BASE_IMAGE=python:3.14-slim-trixie
|
||||
pull: true
|
||||
tags: |
|
||||
scit0/extract_otp_secrets:latest
|
||||
scit0/extract_otp_secrets:bookworm
|
||||
ghcr.io/scito/extract_otp_secrets:latest
|
||||
ghcr.io/scito/extract_otp_secrets:bookworm
|
||||
docker.io/scit0/extract_otp_secrets:latest-${{ matrix.PLATFORM_ARCH }}
|
||||
docker.io/scit0/extract_otp_secrets:bookworm-${{ matrix.PLATFORM_ARCH }}
|
||||
ghcr.io/scito/extract_otp_secrets:latest-${{ matrix.PLATFORM_ARCH }}
|
||||
ghcr.io/scito/extract_otp_secrets:bookworm-${{ matrix.PLATFORM_ARCH }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
# build on feature branches, push only on master branch
|
||||
push: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
|
||||
@@ -102,18 +110,66 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debian_digests
|
||||
name: digests_bookworm_${{ matrix.PLATFORM_ARCH }}
|
||||
path: digests.txt
|
||||
|
||||
create-multiarch-debian-manifests:
|
||||
name: Create multiarch manifests for Debian image
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-and-push-docker-debian-image
|
||||
steps:
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
if: github.secret_source == 'Actions'
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to Github Packages
|
||||
uses: docker/login-action@v3
|
||||
if: github.secret_source == 'Actions'
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GHCR_IO_TOKEN }}
|
||||
|
||||
- name: Create multiarch manifests
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
shell: bash
|
||||
run: |
|
||||
for tag in \
|
||||
docker.io/scit0/extract_otp_secrets:latest \
|
||||
ghcr.io/scito/extract_otp_secrets:latest \
|
||||
docker.io/scit0/extract_otp_secrets:bookworm \
|
||||
ghcr.io/scito/extract_otp_secrets:bookworm \
|
||||
; do
|
||||
docker buildx imagetools create -t $tag \
|
||||
$tag-x86_64 \
|
||||
$tag-arm64
|
||||
done
|
||||
|
||||
|
||||
build-and-push-docker-alpine-image:
|
||||
name: Build Docker Alpine image and push to repositories
|
||||
# run only when code is compiling and tests are passing
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- DOCKER_ARCH: amd64
|
||||
platform: ubuntu-latest
|
||||
PLATFORM_ARCH: x86_64
|
||||
- DOCKER_ARCH: arm64
|
||||
platform: ubuntu-24.04-arm
|
||||
PLATFORM_ARCH: arm64
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
# steps to perform in job
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# avoid building if there are testing errors
|
||||
- name: Run smoke test
|
||||
@@ -149,20 +205,22 @@ jobs:
|
||||
|
||||
- name: "only_txt: Build image and push to Docker Hub and GitHub Container Registry"
|
||||
id: docker_build_only_txt
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/${{ matrix.DOCKER_ARCH }}
|
||||
# relative path to the place where source code with Dockerfile is located
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
file: docker/Dockerfile_only_txt
|
||||
# builder: ${{ steps.buildx.outputs.name }}
|
||||
# Note: tags has to be all lower-case
|
||||
pull: true
|
||||
tags: |
|
||||
scit0/extract_otp_secrets:only-txt
|
||||
scit0/extract_otp_secrets:alpine
|
||||
ghcr.io/scito/extract_otp_secrets:only-txt
|
||||
ghcr.io/scito/extract_otp_secrets:alpine
|
||||
docker.io/scit0/extract_otp_secrets:only-txt-${{ matrix.PLATFORM_ARCH }}
|
||||
docker.io/scit0/extract_otp_secrets:alpine-${{ matrix.PLATFORM_ARCH }}
|
||||
ghcr.io/scito/extract_otp_secrets:only-txt-${{ matrix.PLATFORM_ARCH }}
|
||||
ghcr.io/scito/extract_otp_secrets:alpine-${{ matrix.PLATFORM_ARCH }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
# build on feature branches, push only on master branch
|
||||
push: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
build-args: |
|
||||
@@ -178,18 +236,68 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: alpine_digests
|
||||
name: digests_alpine_${{ matrix.PLATFORM_ARCH }}
|
||||
path: digests.txt
|
||||
|
||||
create-multiarch-alpine-manifests:
|
||||
name: Create multiarch manifests for Alpine image
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-and-push-docker-alpine-image
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
if: github.secret_source == 'Actions'
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to Github Packages
|
||||
uses: docker/login-action@v3
|
||||
if: github.secret_source == 'Actions'
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GHCR_IO_TOKEN }}
|
||||
|
||||
- name: Create multiarch manifests
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
shell: bash
|
||||
run: |
|
||||
for tag in \
|
||||
docker.io/scit0/extract_otp_secrets:only-txt \
|
||||
docker.io/scit0/extract_otp_secrets:alpine \
|
||||
ghcr.io/scito/extract_otp_secrets:only-txt \
|
||||
ghcr.io/scito/extract_otp_secrets:alpine \
|
||||
; do
|
||||
docker buildx imagetools create -t $tag \
|
||||
$tag-x86_64 \
|
||||
$tag-arm64
|
||||
done
|
||||
|
||||
build-and-push-docker-bullseye-image:
|
||||
name: Build Docker Bullseye image (for PyInstsaller) and push to repositories
|
||||
# run only when code is compiling and tests are passing
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- DOCKER_ARCH: amd64
|
||||
platform: ubuntu-latest
|
||||
PLATFORM_ARCH: x86_64
|
||||
- DOCKER_ARCH: arm64
|
||||
platform: ubuntu-24.04-arm
|
||||
PLATFORM_ARCH: arm64
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
# steps to perform in job
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# avoid building if there are testing errors
|
||||
- name: Run smoke test
|
||||
@@ -207,11 +315,6 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
# Workaround for failing builds: https://github.com/docker/build-push-action/issues/761#issuecomment-1383822381
|
||||
# TODO remove workaround when fixed
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:v0.10.6
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
@@ -228,22 +331,25 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GHCR_IO_TOKEN }}
|
||||
|
||||
- name: "Build image from Bullseye and push to GitHub Container Registry"
|
||||
- name: "Build image from Bullseye (Debian 11) and push to GitHub Container Registry"
|
||||
id: docker_build_bullseye
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/${{ matrix.DOCKER_ARCH }}
|
||||
# relative path to the place where source code with Dockerfile is located
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
# builder: ${{ steps.buildx.outputs.name }}
|
||||
build-args: |
|
||||
BASE_IMAGE=python:3.12-slim-bullseye
|
||||
BASE_IMAGE=python:3.13-slim-bullseye
|
||||
# Note: tags has to be all lower-case
|
||||
pull: true
|
||||
tags: |
|
||||
scit0/extract_otp_secrets:bullseye
|
||||
docker.io/scit0/extract_otp_secrets:bullseye-${{ matrix.PLATFORM_ARCH }}
|
||||
ghcr.io/scito/extract_otp_secrets:bullseye-${{ matrix.PLATFORM_ARCH }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
push: ${{ github.secret_source == 'Actions' }}
|
||||
|
||||
- name: Image digest
|
||||
@@ -255,5 +361,53 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bullseye_digests
|
||||
name: digests_bullseye_${{ matrix.PLATFORM_ARCH }}
|
||||
path: digests.txt
|
||||
|
||||
create-multiarch-bullseye-manifests:
|
||||
name: Create multiarch manifests for Bullseye image
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
needs:
|
||||
- build-and-push-docker-bullseye-image
|
||||
steps:
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
if: github.secret_source == 'Actions'
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to Github Packages
|
||||
uses: docker/login-action@v3
|
||||
if: github.secret_source == 'Actions'
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GHCR_IO_TOKEN }}
|
||||
|
||||
- name:
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.secret_source == 'Actions'}}
|
||||
shell: bash
|
||||
run: |
|
||||
for tag in \
|
||||
docker.io/scit0/extract_otp_secrets:bullseye \
|
||||
ghcr.io/scito/extract_otp_secrets:bullseye \
|
||||
; do
|
||||
docker buildx imagetools create -t $tag \
|
||||
$tag-x86_64 \
|
||||
$tag-arm64
|
||||
done
|
||||
|
||||
container-images-clean-up:
|
||||
name: Cleanup old container images
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Delete Container Packages
|
||||
uses: actions/delete-package-versions@v5
|
||||
if: ${{ github.secret_source == 'Actions'}}
|
||||
with:
|
||||
package-name: 'extract_otp_secrets'
|
||||
package-type: 'container'
|
||||
min-versions-to-keep: 1
|
||||
delete-only-untagged-versions: 'true'
|
||||
|
||||
89
.github/workflows/ci_release.yml
vendored
89
.github/workflows/ci_release.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
tag_message: ${{ steps.meta.outputs.tag_message }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Set meta data
|
||||
id: meta
|
||||
# Writing to env with >> $GITHUB_ENV is an alternative
|
||||
@@ -106,24 +106,27 @@ jobs:
|
||||
path: release_id.txt
|
||||
|
||||
build-linux-executable-in-docker:
|
||||
name: Build ${{ matrix.PLATFORM }} release in docker container
|
||||
name: Build ${{ matrix.platform }} release in docker container
|
||||
# run only when code is compiling and tests are passing
|
||||
runs-on: ubuntu-latest
|
||||
needs: create-release
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- PLATFORM: linux/amd64
|
||||
- DOCKER_PLATFORM: linux/amd64
|
||||
platform: ubuntu-latest
|
||||
EXE: extract_otp_secrets_linux_x86_64
|
||||
ASSET_NAME: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_linux_x86_64
|
||||
- PLATFORM: linux/arm64
|
||||
- DOCKER_PLATFORM: linux/arm64
|
||||
platform: ubuntu-24.04-arm
|
||||
EXE: extract_otp_secrets_linux_arm64
|
||||
ASSET_NAME: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_linux_arm64
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
# steps to perform in job
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# avoid building if there are testing errors
|
||||
- name: Run smoke test
|
||||
@@ -145,7 +148,7 @@ jobs:
|
||||
# TODO remove workaround when fixed
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:v0.10.6
|
||||
image=moby/buildkit:latest
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
@@ -172,11 +175,10 @@ jobs:
|
||||
# https://hub.docker.com/r/multiarch/qemu-user-static/
|
||||
- name: Run Pyinstaller in container for ${{ matrix.EXE }}
|
||||
run: |
|
||||
docker run --pull always --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
docker run --platform ${{ matrix.PLATFORM }} --pull always --entrypoint /bin/bash --rm -v "$(pwd)":/files -w /files scit0/extract_otp_secrets:bullseye -c 'apt-get update && apt-get -y install binutils && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name ${{ matrix.EXE }} --distpath /files/dist/ /files/src/extract_otp_secrets.py'
|
||||
docker run --pull always --entrypoint /bin/bash --rm -v "$(pwd)":/files -w /files docker.io/scit0/extract_otp_secrets:bullseye -c 'apt-get update && apt-get -y install binutils && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name ${{ matrix.EXE }} --distpath /files/dist/ /files/src/extract_otp_secrets.py'
|
||||
|
||||
- name: Smoke tests linux/amd64
|
||||
if: matrix.PLATFORM == 'linux/amd64'
|
||||
if: matrix.DOCKER_PLATFORM == 'linux/amd64'
|
||||
run: |
|
||||
dist/${{ matrix.EXE }} -V
|
||||
dist/${{ matrix.EXE }} -h
|
||||
@@ -189,12 +191,12 @@ jobs:
|
||||
dist/${{ matrix.EXE }} --qr CV2 example_export.png
|
||||
dist/${{ matrix.EXE }} --qr CV2_WECHAT example_export.png
|
||||
- name: Smoke tests linux/arm64
|
||||
if: matrix.PLATFORM == 'linux/arm64'
|
||||
if: matrix.DOCKER_PLATFORM == 'linux/arm64'
|
||||
run: |
|
||||
docker run --platform ${{ matrix.PLATFORM }} --pull always --entrypoint /bin/bash --rm -v "$(pwd)":/files -w /files scit0/extract_otp_secrets -c 'dist/${{ matrix.EXE }} -V && dist/${{ matrix.EXE }} -h && dist/${{ matrix.EXE }} example_export.png && dist/${{ matrix.EXE }} - < example_export.txt && dist/${{ matrix.EXE }} --qr ZBAR example_export.png && dist/${{ matrix.EXE }} --qr QREADER example_export.png && dist/${{ matrix.EXE }} --qr QREADER_DEEP example_export.png && dist/${{ matrix.EXE }} --qr CV2 example_export.png && dist/${{ matrix.EXE }} --qr CV2_WECHAT example_export.png'
|
||||
docker run --pull always --entrypoint /bin/bash --rm -v "$(pwd)":/files -w /files docker.io/scit0/extract_otp_secrets -c 'dist/${{ matrix.EXE }} -V && dist/${{ matrix.EXE }} -h && dist/${{ matrix.EXE }} example_export.png && dist/${{ matrix.EXE }} - < example_export.txt && dist/${{ matrix.EXE }} --qr ZBAR example_export.png && dist/${{ matrix.EXE }} --qr QREADER example_export.png && dist/${{ matrix.EXE }} --qr QREADER_DEEP example_export.png && dist/${{ matrix.EXE }} --qr CV2 example_export.png && dist/${{ matrix.EXE }} --qr CV2_WECHAT example_export.png'
|
||||
- name: Load Release URL File from release job
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: release_url
|
||||
- name: Display structure of files
|
||||
@@ -224,6 +226,7 @@ jobs:
|
||||
needs: create-release
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-github-hosted-runners
|
||||
include:
|
||||
@@ -239,7 +242,23 @@ jobs:
|
||||
UPLOAD: true
|
||||
CMD_BUILD: |
|
||||
pyinstaller -y --add-data "$($Env:pythonLocation)\__yolo_v3_qr_detector:__yolo_v3_qr_detector" --add-binary "$($Env:pythonLocation)\Lib\site-packages\pyzbar\libiconv.dll:pyzbar" --add-binary "$($Env:pythonLocation)\Lib\site-packages\pyzbar\libzbar-64.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\msvcr120.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\msvcp120.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\vcamp120.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\vcomp120.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\vccorlib120.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120u.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120chs.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120cht.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120deu.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120enu.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120esn.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120fra.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120ita.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120jpn.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120kor.dll:pyzbar" --add-binary "$($Env:WinDir)\system32\mfc120rus.dll:pyzbar" --onefile --version-file build\win_file_version_info.txt --name extract_otp_secrets.exe src\extract_otp_secrets.py
|
||||
- os: macos-12
|
||||
- os: ubuntu-latest
|
||||
TARGET: linux
|
||||
EXE: extract_otp_secrets_ubuntu
|
||||
ASSET_NAME: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_linux_x86_64_ubuntu_latest
|
||||
ASSET_MIME: application/x-executable
|
||||
UPLOAD: false
|
||||
CMD_BUILD: |
|
||||
pyinstaller -y --add-data $pythonLocation/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_ubuntu src/extract_otp_secrets.py
|
||||
- os: ubuntu-24.04-arm
|
||||
TARGET: linux
|
||||
EXE: extract_otp_secrets_ubuntu_arm64
|
||||
ASSET_NAME: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_linux_arm64_ubuntu_latest
|
||||
ASSET_MIME: application/x-executable
|
||||
UPLOAD: false
|
||||
CMD_BUILD: |
|
||||
pyinstaller -y --add-data $pythonLocation/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_ubuntu_arm64 src/extract_otp_secrets.py
|
||||
- os: macos-15-intel
|
||||
TARGET: macos
|
||||
# https://pyinstaller.org/en/stable/spec-files.html#spec-file-options-for-a-macos-bundle
|
||||
EXE: extract_otp_secrets
|
||||
@@ -249,17 +268,23 @@ jobs:
|
||||
ASSET_MIME: application/octet-stream
|
||||
UPLOAD: true
|
||||
CMD_BUILD: |
|
||||
VERSION_STR=$(setuptools-git-versioning) COPYRIGHT_YEARS='2020-2023' envsubst < installer/extract_otp_secrets_macos_template.spec > extract_otp_secrets_macos.spec
|
||||
VERSION_STR=$(setuptools-git-versioning) COPYRIGHT_YEARS='2020-2025' envsubst < installer/extract_otp_secrets_macos_template.spec > extract_otp_secrets_macos.spec
|
||||
pyinstaller -y extract_otp_secrets_macos.spec
|
||||
installer/build_dmg.sh
|
||||
- os: ubuntu-latest
|
||||
TARGET: linux
|
||||
EXE: extract_otp_secrets_ubuntu
|
||||
ASSET_NAME: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_linux_x86_64_ubuntu_latest
|
||||
ASSET_MIME: application/x-executable
|
||||
UPLOAD: false
|
||||
CMD_BUILD: |
|
||||
pyinstaller -y --add-data $pythonLocation/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_ubuntu src/extract_otp_secrets.py
|
||||
# Disable WARN: Cannot import pyzbar module. This problem is probably due to the missing zbar shared library.
|
||||
# - os: macos-14
|
||||
# TARGET: macos
|
||||
# # https://pyinstaller.org/en/stable/spec-files.html#spec-file-options-for-a-macos-bundle
|
||||
# EXE: extract_otp_secrets
|
||||
# ASSET_NAME: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_macos_arm64
|
||||
# DMG: extract_otp_secrets.dmg
|
||||
# ASSET_NAME_DMG: extract_otp_secrets${{ needs.create-release.outputs.inline_version }}_macos_arm64.dmg
|
||||
# ASSET_MIME: application/octet-stream
|
||||
# UPLOAD: true
|
||||
# CMD_BUILD: |
|
||||
# VERSION_STR=$(setuptools-git-versioning) COPYRIGHT_YEARS='2020-2025' envsubst < installer/extract_otp_secrets_macos_template.spec > extract_otp_secrets_macos.spec
|
||||
# pyinstaller -y extract_otp_secrets_macos.spec
|
||||
# installer/build_dmg.sh
|
||||
steps:
|
||||
- name: Output path
|
||||
if: runner.os == 'Windows'
|
||||
@@ -267,14 +292,14 @@ jobs:
|
||||
- name: List Windir
|
||||
if: runner.os == 'Windows'
|
||||
run: ls "$($Env:WinDir)\system32"
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set macos macos_python_path
|
||||
# TODO use variable for Python version
|
||||
run: echo "macos_python_path=/Library/Frameworks/Python.framework/Versions/3.12" >> $GITHUB_ENV
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
run: echo "macos_python_path=/Library/Frameworks/Python.framework/Versions/3.14" >> $GITHUB_ENV
|
||||
- name: Set up Python 3.14
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.12
|
||||
python-version: 3.14
|
||||
check-latest: true
|
||||
- name: Install zbar shared lib for QReader (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
@@ -294,7 +319,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p build/
|
||||
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=$(echo $(cut -d '.' -f 3 <<< "$(setuptools-git-versioning)") | sed -E -n "s/^([0-9]+).*/\1/p") VERSION_BUILD=$(echo $(cut -d '.' -f 3 <<< "$(setuptools-git-versioning)") | sed -E -n -e"s/^[0-9]+.+/99/p")$(($(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
|
||||
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=$(echo $(cut -d '.' -f 3 <<< "$(setuptools-git-versioning)") | sed -E -n "s/^([0-9]+).*/\1/p") VERSION_BUILD=$(echo $(cut -d '.' -f 3 <<< "$(setuptools-git-versioning)") | sed -E -n -e"s/^[0-9]+.+/99/p")$(($(git rev-list --count $(git tag | sort -V -r | sed '1!d')..HEAD))) COPYRIGHT_YEARS='2020-2025' envsubst < installer/win_file_version_info_template.txt > build/win_file_version_info.txt
|
||||
- name: Build with pyinstaller for ${{ matrix.TARGET }}
|
||||
env:
|
||||
# Reproducible build: https://pyinstaller.org/en/stable/advanced-topics.html#creating-a-reproducible-build
|
||||
@@ -317,12 +342,12 @@ jobs:
|
||||
dist/${{ matrix.EXE }} - < example_export.txt
|
||||
- name: Load Release URL File from release job
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: release_url
|
||||
- name: Load Release Id File from release job
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: release_id
|
||||
- name: Display structure of files
|
||||
@@ -365,7 +390,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Load Release Id File from release job
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: release_id
|
||||
- name: Set meta data
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -35,3 +35,12 @@ extract_otp_secrets.build/
|
||||
extract_otp_secrets.dist/
|
||||
extract_otp_secrets.onefile-build/
|
||||
extract_otp_secrets.bin
|
||||
# Devenv
|
||||
.devenv*
|
||||
devenv.local.nix
|
||||
|
||||
# direnv
|
||||
.direnv
|
||||
|
||||
# pre-commit
|
||||
.pre-commit-config.yaml
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -2,7 +2,7 @@
|
||||
"python.testing.pytestArgs": [
|
||||
"."
|
||||
],
|
||||
"python.testing.unittestEnabled": true,
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"cSpell.words": [
|
||||
"devbox",
|
||||
|
||||
9
Pipfile
9
Pipfile
@@ -4,14 +4,15 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
colorama = ">=0.4.6"
|
||||
colorama = "0.4.6"
|
||||
opencv-contrib-python = "*"
|
||||
numpy = "2.3.5"
|
||||
# for macOS: opencv-contrib-python = "<=4.7.0"
|
||||
pillow = "*"
|
||||
pyzbar = "*"
|
||||
protobuf = "*"
|
||||
qrcode = "*"
|
||||
qreader = "<2.0.0"
|
||||
qreader = "1.3.2"
|
||||
|
||||
[dev-packages]
|
||||
build = "*"
|
||||
@@ -24,9 +25,7 @@ pylint = "*"
|
||||
pytest = "*"
|
||||
pytest-cov = "*"
|
||||
pytest-mock = "*"
|
||||
setuptools-git-versioning = "*"
|
||||
types-protobuf = "*"
|
||||
wheel = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.11"
|
||||
python_version = "3.14"
|
||||
|
||||
1060
Pipfile.lock
generated
1060
Pipfile.lock
generated
File diff suppressed because it is too large
Load Diff
89
README.md
89
README.md
@@ -2,10 +2,10 @@
|
||||
|
||||
[](https://github.com/scito/extract_otp_secrets/actions/workflows/ci.yml)
|
||||
[](https://github.com/scito/extract_otp_secrets/actions/workflows/ci_docker.yml)
|
||||

|
||||

|
||||
[](https://github.com/scito/extract_otp_secrets/blob/master/LICENSE)
|
||||
[](https://github.com/scito/extract_otp_secrets/releases/latest)
|
||||

|
||||

|
||||
[](https://hub.docker.com/repository/docker/scit0/extract_otp_secrets/general)
|
||||
[](https://github.com/scito/extract_otp_secrets/releases/latest)
|
||||
[](https://github.com/scito/extract_otp_secrets/releases/latest)
|
||||
@@ -14,7 +14,7 @@
|
||||
[](https://stand-with-ukraine.pp.ua)
|
||||
<!-- 
|
||||
[](https://github.com/scito/extract_otp_secrets/blob/master/Pipfile.lock)
|
||||
-->
|
||||
-->
|
||||
|
||||
<!-- [](https://GitHub.com/scito/extract_otp_secrets/releases/) -->
|
||||
|
||||
@@ -36,6 +36,7 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Download and run binary executable (🆕 since v2.1)](#download-and-run-binary-executable--since-v21)
|
||||
- [MacOS](#macos)
|
||||
- [Usage](#usage)
|
||||
@@ -46,7 +47,7 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
||||
- [Installation of optional shared system libraries (recommended)](#installation-of-optional-shared-system-libraries-recommended)
|
||||
- [Program help: arguments and options](#program-help-arguments-and-options)
|
||||
- [Examples](#examples)
|
||||
- [Printing otp secrets from text file](#printing-otp-secrets-form-text-file)
|
||||
- [Printing otp secrets from text file](#printing-otp-secrets-from-text-file)
|
||||
- [Printing otp secrets from image file](#printing-otp-secrets-from-image-file)
|
||||
- [Writing otp secrets to csv file](#writing-otp-secrets-to-csv-file)
|
||||
- [Writing otp secrets to json file](#writing-otp-secrets-to-json-file)
|
||||
@@ -66,7 +67,8 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
||||
- [pipenv](#pipenv)
|
||||
- [Visual Studio Code Remote - Containers / VSCode devcontainer](#visual-studio-code-remote---containers--vscode-devcontainer)
|
||||
- [venv](#venv)
|
||||
- [devbox](#devbox)
|
||||
- [devbox 1](#devbox-1)
|
||||
- [devbox 2](#devbox-2)
|
||||
- [docker](#docker)
|
||||
- [More docker examples](#more-docker-examples)
|
||||
- [Tests](#tests)
|
||||
@@ -85,6 +87,7 @@ The secrets can be exported to JSON or CSV, or printed as QR codes to console or
|
||||
- [Problems and Troubleshooting](#problems-and-troubleshooting)
|
||||
- [Windows error message](#windows-error-message)
|
||||
- [Related projects](#related-projects)
|
||||
- [Third party documentation](#third-party-documentation)
|
||||
</details>
|
||||
|
||||
## Download and run binary executable (🆕 since v2.1)
|
||||
@@ -121,13 +124,21 @@ However, the bare executable can be executed from the command line:
|
||||
3. Change to Downloads folder in Terminal: `cd $HOME/Downloads`
|
||||
4. Remove quarantine bit for the downloaded file: `xattr -r -d com.apple.quarantine extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||
5. Set executable bit for the downloaded file: `chmod +x extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||
6. Start executable from command line: `./extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||
6. Start executable from command line for the first time: `./extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||
7. Wait approximately 30 seconds to 1 minute on the first run. Terminal will display the following error:
|
||||
```
|
||||
OpenCV: not authorized to capture video (status 0), requesting...
|
||||
OpenCV: camera failed to properly initialize!
|
||||
```
|
||||
8. macOS will then prompt to request camera access.
|
||||
9. After allowing camera access, rerun the program.
|
||||
10. On the second run, the GUI prompt shows correctly and is fully operable: `./extract_otp_secrets_X.Y.Z_macos_x86_64`
|
||||
|
||||
:information_source: Replace `X.Y.Z` in above commands with the version number of your downloaded file, e.g. `extract_otp_secrets_2.4.0_macos_x86_64`
|
||||
|
||||
:information_source: If Rosetta2 emulation is installed, these steps work also for M1 and M2 Apple Silicon processors and the program can be executed directly.
|
||||
|
||||
> :warning: It seems the GUI mode is not working in Terminal on macOS. In tests no [GUI window](#usage) was opened. (Remarks and hints about macOS are welcome since I do not know macOS.)
|
||||
Tested with extract_otp_secrets_2.8.1_macos_x86_64 on macOS Sequoia 15.1 beta. Source: [#283](https://github.com/scito/extract_otp_secrets/issues/283)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -205,7 +216,7 @@ For a detailed installation documentation of [pyzbar](https://github.com/Natural
|
||||
|
||||
#### Linux (Debian, Ubuntu, …)
|
||||
|
||||
sudo apt-get install libzbar0
|
||||
sudo apt-get install libgl1 libzbar0
|
||||
|
||||
#### Linux (OpenSUSE)
|
||||
|
||||
@@ -213,7 +224,7 @@ For a detailed installation documentation of [pyzbar](https://github.com/Natural
|
||||
|
||||
#### Linux (Fedora)
|
||||
|
||||
sudo dnf install zbar
|
||||
sudo dnf install mesa-libGL zbar
|
||||
|
||||
#### Linux (Arch Linux)
|
||||
|
||||
@@ -272,7 +283,7 @@ python extract_otp_secrets.py = < example_export.png</pre>
|
||||
|
||||
## Examples
|
||||
|
||||
### Printing otp secrets form text file
|
||||
### Printing otp secrets from text file
|
||||
|
||||
python src/extract_otp_secrets.py example_export.txt
|
||||
|
||||
@@ -355,7 +366,7 @@ python extract_otp_secrets.py = < example_export.png</pre>
|
||||
* 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)
|
||||
* 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 on [Docker Hub](https://hub.docker.com/repository/docker/scit0/extract_otp_secrets) and [GitHub Packages](https://github.com/users/scito/packages/container/package/extract_otp_secrets) (🆕 since v2.0)
|
||||
* Many ways to run the script:
|
||||
* Native Python
|
||||
* pipenv
|
||||
@@ -369,7 +380,7 @@ python extract_otp_secrets.py = < example_export.png</pre>
|
||||
* macOS
|
||||
* Windows
|
||||
* Uses UTF-8 on all platforms
|
||||
* Supports Python >= 3.8
|
||||
* Supports Python >= 3.9
|
||||
* Installation of shared system libraries is optional (🆕 since v2.3)
|
||||
* Provides a debug mode (-d) for analyzing import problems
|
||||
* Written in modern Python using type hints and following best practices
|
||||
@@ -509,7 +520,7 @@ Alternatively, you can use a python virtual env for the dependencies:
|
||||
The requirements\*.txt files contain all the dependencies (also the optional ones).
|
||||
To leave the python virtual env just call `deactivate`.
|
||||
|
||||
### devbox
|
||||
### devbox 1
|
||||
|
||||
Install [devbox](https://github.com/jetpack-io/devbox), which is a wrapper for nix. Then enter the environment with Python and the packages installed with:
|
||||
|
||||
@@ -517,6 +528,14 @@ Install [devbox](https://github.com/jetpack-io/devbox), which is a wrapper for n
|
||||
devbox shell
|
||||
```
|
||||
|
||||
### devbox 2
|
||||
|
||||
Install [devbox](https://devenv.sh), which is a wrapper for nix. Then enter the environment with Python and the packages installed with:
|
||||
|
||||
```
|
||||
devenv shell
|
||||
```
|
||||
|
||||
### docker
|
||||
|
||||
Install [Docker](https://docs.docker.com/get-docker/).
|
||||
@@ -526,35 +545,35 @@ Prebuilt docker images are available for amd64 and arm64 architectures on [Docke
|
||||
Extracting from an QR image file:
|
||||
|
||||
```
|
||||
curl -s https://raw.githubusercontent.com/scito/extract_otp_secrets/master/example_export.png | docker run --pull always -i --rm -v "$(pwd)":/files:ro scit0/extract_otp_secrets =
|
||||
curl -s https://raw.githubusercontent.com/scito/extract_otp_secrets/master/example_export.png | docker run --network none --pull always -i --rm -v "$(pwd)":/files:ro docker.io/scit0/extract_otp_secrets =
|
||||
```
|
||||
|
||||
Capturing from camera in GUI window (X Window system required on host):
|
||||
|
||||
```
|
||||
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
|
||||
docker run --network none --pull always --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro docker.io/scit0/extract_otp_secrets
|
||||
```
|
||||
|
||||
If only text processing is required, there is a small Image based on Alpine Linux:
|
||||
|
||||
```
|
||||
curl -s https://raw.githubusercontent.com/scito/extract_otp_secrets/master/example_export.txt | docker run --pull always -i --rm -v "$(pwd)":/files:ro scit0/extract_otp_secrets:latest-only-txt -
|
||||
curl -s https://raw.githubusercontent.com/scito/extract_otp_secrets/master/example_export.txt | docker run --network none --pull always -i --rm -v "$(pwd)":/files:ro docker.io/scit0/extract_otp_secrets:latest-only-txt -
|
||||
```
|
||||
|
||||
Docker image from GitHub:
|
||||
|
||||
```
|
||||
docker login ghcr.io -u USERNAME
|
||||
curl -s https://raw.githubusercontent.com/scito/extract_otp_secrets/master/example_export.png | docker run --pull always -i --rm -v "$(pwd)":/files:ro ghcr.io/scito/extract_otp_secrets =
|
||||
curl -s https://raw.githubusercontent.com/scito/extract_otp_secrets/master/example_export.png | docker run --network none --pull always -i --rm -v "$(pwd)":/files:ro ghcr.io/scito/extract_otp_secrets =
|
||||
```
|
||||
|
||||
### More docker examples
|
||||
|
||||
docker run --pull always --rm -v "$(pwd)":/files:ro scit0/extract_otp_secrets example_export.png
|
||||
docker run --network none --pull always --rm -v "$(pwd)":/files:ro docker.io/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
|
||||
docker run --network none --pull always --rm -i -v "$(pwd)":/files:ro docker.io/scit0/extract_otp_secrets:latest-only-txt - < example_export.txt
|
||||
|
||||
cat example_export.txt | docker run --pull always --rm -i -v "$(pwd)":/files:ro scit0/extract_otp_secrets:latest_only_txt - -c - > example_out.csv
|
||||
cat example_export.txt | docker run --network none --pull always --rm -i -v "$(pwd)":/files:ro docker.io/scit0/extract_otp_secrets:latest-only-txt - -c - > example_out.csv
|
||||
|
||||
## Tests
|
||||
|
||||
@@ -676,6 +695,18 @@ There is a Bash script for a full local build including linting and type checkin
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
or
|
||||
```bash
|
||||
PYTHON=python3.11 PIP=pip3.11 DOCKER="sudo podman" ./build.sh -d
|
||||
```
|
||||
Linux or WSL2 Linux:
|
||||
```bash
|
||||
DOCKER="sudo podman" ./build.sh -d
|
||||
```
|
||||
Git for Windows:
|
||||
```bash
|
||||
MSYS_NO_PATHCONV=1 NOINHERIT=1 DOCKER="podman" ./build.sh -d
|
||||
```
|
||||
|
||||
The options of the build script:
|
||||
|
||||
@@ -701,6 +732,17 @@ Options:
|
||||
-h, --help Show help and quit
|
||||
```
|
||||
|
||||
#### Additional requirements
|
||||
|
||||
* envsubst
|
||||
* git
|
||||
* perl
|
||||
* pip
|
||||
|
||||
##### Fedora
|
||||
|
||||
sudo dnf install python3-pip perl envsubst
|
||||
|
||||
## Technical background
|
||||
|
||||
The export QR code of "Google Authenticator" contains the URL `otpauth-migration://offline?data=…`.
|
||||
@@ -710,7 +752,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
|
||||
|
||||
The generated protobuf Python code was generated by protoc 27.2 (https://github.com/protocolbuffers/protobuf/releases/tag/v27.2).
|
||||
The generated protobuf Python code was generated by protoc 33.1 (https://github.com/protocolbuffers/protobuf/releases/tag/v33.1).
|
||||
|
||||
For Python type hint generation the [mypy-protobuf](https://github.com/nipunn1313/mypy-protobuf) package is used.
|
||||
|
||||
@@ -761,6 +803,11 @@ FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependenc
|
||||
* [Android OTP Extractor](https://github.com/puddly/android-otp-extractor) can extract your tokens from popular Android OTP apps and export them in a standard format or just display them as QR codes for easy importing. [Requires a _rooted_ Android phone.]
|
||||
* [Google Authenticator secret extractor](https://github.com/krissrex/google-authenticator-exporter) is similar project written in JavaScript. It also extracts otp secrets from Google Authenticator.
|
||||
|
||||
## Third party documentation
|
||||
|
||||
* [TOTP Secret Extraction from QR codes (medium.com)](https://cavalloj.medium.com/totp-secret-extraction-from-qr-codes-ee097b4c687f)
|
||||
* [Google Authenticator: OTP-Secrets auslesen (stadt-bremerhaven.de)](https://stadt-bremerhaven.de/google-authenticator-otp-secrets-auslesen/)
|
||||
|
||||
***
|
||||
|
||||
# #StandWithUkraine 🇺🇦
|
||||
|
||||
128
build.sh
128
build.sh
@@ -73,6 +73,14 @@ askContinueYn() {
|
||||
|
||||
# Reference: https://gist.github.com/steinwaywhw/a4cd19cda655b8249d908261a62687f8
|
||||
|
||||
if [[ "$MSYSTEM" == "MINGW64" || "$MSYSTEM" == "MINGW32" || "$MSYSTEM" == "UCRT64" ]]; then
|
||||
LINUX=false
|
||||
elif [[ "$(uname -s)" == MINGW* ]]; then
|
||||
LINUX=false
|
||||
else
|
||||
LINUX=true
|
||||
fi
|
||||
|
||||
interactive=false
|
||||
ignore_version_check=true
|
||||
clean=false
|
||||
@@ -173,11 +181,19 @@ done
|
||||
BIN="$HOME/bin"
|
||||
DOWNLOADS="$HOME/downloads"
|
||||
|
||||
PYTHON="python3.11"
|
||||
PIP="pip3.11"
|
||||
# Set python und pip if not already set in environment
|
||||
PYTHON="${PYTHON:=python}"
|
||||
PIP="${PIP:=pip}"
|
||||
PIPENV="$PYTHON -m pipenv"
|
||||
FLAKE8="$PYTHON -m flake8"
|
||||
MYPY="$PYTHON -m mypy"
|
||||
DOCKER="${DOCKER:=docker}"
|
||||
|
||||
if $LINUX; then
|
||||
PWD=pwd
|
||||
else
|
||||
PWD="pwd -W"
|
||||
fi
|
||||
|
||||
# sudo ln -s /usr/bin/python3.11 /usr/bin/python
|
||||
|
||||
@@ -186,7 +202,7 @@ MYPY="$PYTHON -m mypy"
|
||||
DEST="protoc"
|
||||
|
||||
if $clean; then
|
||||
cmd="docker image prune -f || echo 'No docker image pruned'"
|
||||
cmd="$DOCKER image prune -f || echo 'No docker image pruned'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -224,7 +240,7 @@ if $clean; then
|
||||
fi
|
||||
|
||||
if $build_local; then
|
||||
cmd="$PIP install --use-pep517 -U -r requirements-dev.txt"
|
||||
cmd="$PIP install -U -r requirements-dev.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -237,7 +253,7 @@ if $build_local; then
|
||||
echo -e "\nProtoc remote version $VERSION\n"
|
||||
echo -e "Protoc local version: $OLDVERSION\n"
|
||||
|
||||
if [ "$OLDVERSION" != "$VERSION" ] || ! $ignore_version_check; then
|
||||
if [ "$OLDVERSION" != "$VERSION" ] && ! $ignore_version_check; then
|
||||
echo "Upgrade protoc from $OLDVERSION to $VERSION"
|
||||
|
||||
NAME="protoc-$VERSION"
|
||||
@@ -298,7 +314,7 @@ if $build_local; then
|
||||
|
||||
$PIP --version
|
||||
|
||||
cmd="$PIP install --use-pep517 -U -r requirements.txt"
|
||||
cmd="$PIP install -U -r requirements.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -381,15 +397,52 @@ if $build_local; then
|
||||
|
||||
$PIPENV --version
|
||||
|
||||
cmd="$PIPENV --rm && $PIPENV update && $PIPENV install"
|
||||
cmd="rm Pipfile.lock || echo 'No Pipfile.lock to remove'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="# $PIPENV --rm || echo 'No virtualenv to remove'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PIPENV install --dev"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PIPENV update --dev"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
$PIPENV run python --version
|
||||
|
||||
# pip -e install
|
||||
|
||||
cmd="$PIPENV run pip install -U -e ."
|
||||
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"
|
||||
|
||||
|
||||
cmd="$PIPENV run extract_otp_secrets example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PIPENV run extract_otp_secrets - < example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Test (needs module)
|
||||
|
||||
cmd="$PIPENV run python src/extract_otp_secrets.py example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="$PIPENV run python src/extract_otp_secrets.py - < example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
fi
|
||||
|
||||
# Build wheel
|
||||
@@ -449,8 +502,7 @@ if $build_local; then
|
||||
fi
|
||||
|
||||
# Generate README.md TOC
|
||||
|
||||
cmd="gfm-toc -s 2 -e 3 -t -o README.md > docs/README_TOC.md"
|
||||
cmd="env -u MSYS_NO_PATHCONV gfm-toc -s 2 -e 3 -t -o README.md > docs/README_TOC.md"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -460,7 +512,7 @@ if $build_local; then
|
||||
eval "$cmd"
|
||||
|
||||
# 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-$(date +%Y)' 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
|
||||
eval "$cmd"
|
||||
fi
|
||||
@@ -470,85 +522,85 @@ if $build_docker; then
|
||||
|
||||
if $build_x86_64; then
|
||||
# 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 docker/Dockerfile_only_txt --pull --build-arg RUN_TESTS=false"
|
||||
cmd="$DOCKER build . --network=host -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
|
||||
eval "$cmd"
|
||||
|
||||
cmd="docker run --rm -v \"$(pwd)\":/files:ro extract_otp_secrets_only_txt example_export.txt"
|
||||
cmd="$DOCKER run --network none --rm -v \"$($PWD):/files:ro\" extract_otp_secrets_only_txt example_export.txt"
|
||||
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_only_txt - < example_export.txt"
|
||||
cmd="$DOCKER run --network none --rm -i -v \"$($PWD):/files:ro\" extract_otp_secrets_only_txt - < example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="docker run --entrypoint /extract/run_pytest.sh --rm -v \"$(pwd)\":/files:ro extract_otp_secrets_only_txt extract_otp_secrets_test.py -k 'not qreader' -vvv --relaxed"
|
||||
cmd="$DOCKER run --network=host --entrypoint '/extract/run_pytest.sh' --rm -v \"$($PWD):/files:ro\" extract_otp_secrets_only_txt extract_otp_secrets_test.py -k 'not qreader' -vvv --relaxed"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Build extract_otp_secrets (Debian Bookworm)
|
||||
cmd="docker build . -t extract_otp_secrets -t extract_otp_secrets:bookworm --pull -f docker/Dockerfile --build-arg RUN_TESTS=false"
|
||||
cmd="$DOCKER build . --network=host -t extract_otp_secrets -t extract_otp_secrets:bookworm --pull -f docker/Dockerfile --build-arg RUN_TESTS=false"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="docker run --rm -v \"$(pwd)\":/files:ro extract_otp_secrets example_export.txt"
|
||||
cmd="$DOCKER run --network none --rm -v \"$($PWD):/files:ro\" extract_otp_secrets example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="cat example_export.txt | docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets - -c - > example_output.csv"
|
||||
cmd="cat example_export.txt | $DOCKER run --network none --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"
|
||||
cmd="$DOCKER run --network none --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"
|
||||
|
||||
cmd="docker run --entrypoint /extract/run_pytest.sh --rm -v \"$(pwd)\":/files:ro extract_otp_secrets"
|
||||
cmd="$DOCKER run --network=host --entrypoint /extract/run_pytest.sh --rm -v \"$($PWD):/files:ro\" extract_otp_secrets"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Build extract_otp_secrets (Debian Bullseye)
|
||||
cmd="docker build . -t extract_otp_secrets:bullseye -t extract_otp_secrets:bullseye-x86_64 --pull -f docker/Dockerfile --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.12-slim-bullseye"
|
||||
cmd="$DOCKER build . --network=host -t extract_otp_secrets:bullseye -t extract_otp_secrets:bullseye-x86_64 --pull -f docker/Dockerfile --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.13-slim-bullseye"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="docker run --rm -v \"$(pwd)\":/files:ro extract_otp_secrets:bullseye example_export.txt"
|
||||
cmd="$DOCKER run --network none --rm -v \"$($PWD):/files:ro\" extract_otp_secrets:bullseye example_export.txt"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="cat example_export.txt | docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets:bullseye - -c - > example_output.csv"
|
||||
cmd="cat example_export.txt | $DOCKER run --network none --rm -i -v \"$($PWD):/files:ro\" extract_otp_secrets:bullseye - -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:bullseye = < example_export.png"
|
||||
cmd="$DOCKER run --network none --rm -i -v \"$($PWD):/files:ro\" extract_otp_secrets:bullseye = < example_export.png"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="docker run --entrypoint /extract/run_pytest.sh --rm -v \"$(pwd)\":/files:ro extract_otp_secrets:bullseye"
|
||||
cmd="$DOCKER run --network=host --entrypoint /extract/run_pytest.sh --rm -v \"$($PWD):/files:ro\" extract_otp_secrets:bullseye"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Build executable from Docker latest
|
||||
# sed "1!d" is workaround for head -n 1 since it head procduces exit code != 0
|
||||
BOOKWORM_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
||||
BOOKWORM_GLIBC_VERSION=$($DOCKER run --network none --entrypoint /bin/bash --rm extract_otp_secrets -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
||||
echo "Bookworm glibc: $BOOKWORM_GLIBC_VERSION"
|
||||
fi
|
||||
|
||||
if $build_arm; then
|
||||
# build linux/arm64
|
||||
cmd="docker run --pull always --rm --privileged multiarch/qemu-user-static --reset -p yes"
|
||||
cmd="$DOCKER run --network none --pull always --rm --privileged multiarch/qemu-user-static --reset -p yes"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
# Build extract_otp_secrets (Debian Bullseye)
|
||||
cmd="docker buildx build --platform=linux/arm64 . -t extract_otp_secrets:bullseye-arm64 --pull -f docker/Dockerfile --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.12-slim-bullseye"
|
||||
cmd="$DOCKER buildx build --platform=linux/arm64 . -t extract_otp_secrets:bullseye-arm64 --pull -f docker/Dockerfile --build-arg RUN_TESTS=false --build-arg BASE_IMAGE=python:3.13-slim-bullseye"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
fi
|
||||
|
||||
if $build_exe; then
|
||||
if $build_x86_64; then
|
||||
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64_bookworm --distpath /files/dist/ /files/src/extract_otp_secrets.py'"
|
||||
cmd="$DOCKER run --platform linux/amd64 --network=host --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64_bookworm --distpath /files/dist/ /files/src/extract_otp_secrets.py'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -561,10 +613,10 @@ if $build_docker; then
|
||||
eval "$cmd"
|
||||
|
||||
# Build executable from Docker bullseye
|
||||
BULLSEYE_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets:bullseye -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
||||
BULLSEYE_GLIBC_VERSION=$($DOCKER run --network none --entrypoint /bin/bash --rm extract_otp_secrets:bullseye -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
||||
echo "Bullseye glibc: $BULLSEYE_GLIBC_VERSION"
|
||||
|
||||
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:bullseye -c 'apt-get update && apt-get -y install binutils && pip install -U pip && pip install -U -r /files/requirements.txt && pip install pyinstaller && PYTHONHASHSEED=31 && pyinstaller -y --specpath installer --add-data /usr/local/__yolo_v3_qr_detector/:__yolo_v3_qr_detector/ --onefile --name extract_otp_secrets_linux_x86_64 --distpath /files/dist/ /files/src/extract_otp_secrets.py'"
|
||||
cmd="$DOCKER run --platform linux/amd64 --network=host --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets:bullseye -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
|
||||
eval "$cmd"
|
||||
|
||||
@@ -579,11 +631,11 @@ if $build_docker; then
|
||||
|
||||
if $build_arm; then
|
||||
# build linux/arm64
|
||||
cmd="docker run --platform linux/arm64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:bullseye-arm64 -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 --network=host --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets:bullseye-arm64 -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
|
||||
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:bullseye-arm64 -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:bullseye-arm64 -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
|
||||
eval "$cmd"
|
||||
fi
|
||||
@@ -591,7 +643,7 @@ if $build_docker; then
|
||||
|
||||
if $build_nuitka_exe; then
|
||||
if $build_x86_64; then
|
||||
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_bookworm_compiled /files/src/extract_otp_secrets.py'"
|
||||
cmd="$DOCKER run --platform linux/amd64 --network=host --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_bookworm_compiled /files/src/extract_otp_secrets.py'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -608,10 +660,10 @@ if $build_docker; then
|
||||
eval "$cmd"
|
||||
|
||||
# Build executable from Docker bullseye
|
||||
BULLSEYE_GLIBC_VERSION=$(docker run --entrypoint /bin/bash --rm extract_otp_secrets:bullseye -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
||||
BULLSEYE_GLIBC_VERSION=$($DOCKER run --network none --entrypoint /bin/bash --rm extract_otp_secrets:bullseye -c 'ldd --version | sed "1!d" | sed -E "s/.* ([[:digit:]]+\.[[:digit:]]+)$/\1/"')
|
||||
echo "Bookworm glibc: $BULLSEYE_GLIBC_VERSION"
|
||||
|
||||
cmd="docker run --platform linux/amd64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:bullseye -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_bullseye_compiled /files/src/extract_otp_secrets.py'"
|
||||
cmd="$DOCKER run --platform linux/amd64 --network=host --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets:bullseye -c 'apt-get update && apt-get -y install binutils build-essential patchelf && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_x86_64_bullseye_compiled /files/src/extract_otp_secrets.py'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
@@ -630,11 +682,11 @@ if $build_docker; then
|
||||
|
||||
if $build_arm; then
|
||||
# build linux/arm64
|
||||
cmd="docker run --platform linux/arm64 --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:bullseye-arm64 -c 'apt-get update && apt-get -y install binutils build-essential patchelf qt5-default && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_arm64_compiled /files/src/extract_otp_secrets.py'"
|
||||
cmd="$DOCKER run --platform linux/arm64 --network=host --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets:bullseye-arm64 -c 'apt-get update && apt-get -y install binutils build-essential patchelf qt5-default && pip install -U pip && pip install -U -r /files/requirements.txt && pip install nuitka pyqt5 && PYTHONHASHSEED=31 && python -m nuitka --enable-plugin=tk-inter --enable-plugin=pyqt5 --include-data-dir=/usr/local/__yolo_v3_qr_detector/=__yolo_v3_qr_detector/ --onefile --output-dir=/files/build/docker/nuitka --output-filename=extract_otp_secrets_linux_arm64_compiled /files/src/extract_otp_secrets.py'"
|
||||
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
|
||||
eval "$cmd"
|
||||
|
||||
cmd="PLATFORM='linux/arm64' && EXE='build/docker/nuitka/extract_otp_secrets_linux_arm64_compiled' && docker run --platform \"\$PLATFORM\" --entrypoint /bin/bash --rm -v \"$(pwd)\":/files -w /files extract_otp_secrets:bullseye-arm64 -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='build/docker/nuitka/extract_otp_secrets_linux_arm64_compiled' && $DOCKER run --platform \"\$PLATFORM\" --entrypoint /bin/bash --rm -v \"$($PWD):/files\" -w /files extract_otp_secrets:bullseye-arm64 -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
|
||||
eval "$cmd"
|
||||
|
||||
@@ -646,7 +698,7 @@ if $build_docker; then
|
||||
|
||||
# Run GUI from Docker
|
||||
if $build_x86_64 && $run_gui; then
|
||||
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 &"
|
||||
cmd="$DOCKER run --network none --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
|
||||
|
||||
122
devenv.lock
Normal file
122
devenv.lock
Normal file
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"nodes": {
|
||||
"devenv": {
|
||||
"locked": {
|
||||
"dir": "src/modules",
|
||||
"lastModified": 1726050924,
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "cf471f691c3765ed431199f61b8bd70530bc4305",
|
||||
"treeHash": "04a5d566820f8fb1955c7c49ccbd3ff95d9129d7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "src/modules",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1716977621,
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
|
||||
"treeHash": "6d9f1f7ca0faf1bc2eeb397c78a49623260d3412",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1725826545,
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f4c846aee8e1e29062aa8514d5e0ab270f4ec2f9",
|
||||
"treeHash": "8fc49deaed3f2728a7147c38163cc468a117570a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1725513492,
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "7570de7b9b504cfe92025dd1be797bf546f66528",
|
||||
"treeHash": "4b46d77870afecd8f642541cb4f4927326343b59",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
24
devenv.nix
Normal file
24
devenv.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
cachix.enable = false;
|
||||
|
||||
languages.python = {
|
||||
enable = true;
|
||||
venv = {
|
||||
enable = true;
|
||||
requirements = ./requirements.txt;
|
||||
};
|
||||
};
|
||||
|
||||
packages = [
|
||||
pkgs.git
|
||||
pkgs.zbar
|
||||
];
|
||||
}
|
||||
14
devenv.yaml
Normal file
14
devenv.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
inputs:
|
||||
nixpkgs:
|
||||
url: github:cachix/devenv-nixpkgs/rolling
|
||||
|
||||
# If you're using non-OSS software, you can set allowUnfree to true.
|
||||
# allowUnfree: true
|
||||
|
||||
# If you're willing to use a package that's vulnerable
|
||||
# permittedInsecurePackages:
|
||||
# - "openssl-1.1.1w"
|
||||
|
||||
# If you have more than one devenv you can merge them
|
||||
#imports:
|
||||
# - ./backend
|
||||
@@ -1,5 +1,5 @@
|
||||
# --build-arg BASE_IMAGE=python:3.11-slim-buster
|
||||
ARG BASE_IMAGE=python:3.12-slim-bookworm
|
||||
ARG BASE_IMAGE=python:3.14-slim-trixie
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# https://docs.docker.com/engine/reference/builder/
|
||||
@@ -16,7 +16,8 @@ COPY requirements*.txt src/ run_pytest.sh pytest.ini tests/ example_*.txt exampl
|
||||
|
||||
ARG RUN_TESTS=true
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
RUN uname -a \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||
libgl1 \
|
||||
libglib2.0-0 \
|
||||
libsm6 \
|
||||
@@ -31,6 +32,6 @@ WORKDIR /files
|
||||
|
||||
ENTRYPOINT ["python", "/extract/extract_otp_secrets.py"]
|
||||
|
||||
LABEL org.opencontainers.image.source https://github.com/scito/extract_otp_secrets
|
||||
LABEL org.opencontainers.image.license GPL-3.0+
|
||||
LABEL org.opencontainers.image.source=https://github.com/scito/extract_otp_secrets
|
||||
LABEL org.opencontainers.image.license=GPL-3.0+
|
||||
LABEL maintainer="Scito https://scito.ch, https://github.com/scito"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG BASE_IMAGE=python:3.12-alpine
|
||||
ARG BASE_IMAGE=python:3.14-alpine
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# https://docs.docker.com/engine/reference/builder/
|
||||
@@ -17,7 +17,8 @@ COPY requirements*.txt src/ run_pytest.sh pytest.ini tests/ example_*.txt exampl
|
||||
|
||||
ARG RUN_TESTS=true
|
||||
|
||||
RUN apk add --no-cache \
|
||||
RUN uname -a \
|
||||
&& apk add --no-cache \
|
||||
jpeg \
|
||||
zlib \
|
||||
&& echo "Arch: $(apk --print-arch)" \
|
||||
@@ -43,6 +44,6 @@ WORKDIR /files
|
||||
|
||||
ENTRYPOINT ["python", "/extract/extract_otp_secrets.py"]
|
||||
|
||||
LABEL org.opencontainers.image.source https://github.com/scito/extract_otp_secrets
|
||||
LABEL org.opencontainers.image.license GPL-3.0+
|
||||
LABEL org.opencontainers.image.source=https://github.com/scito/extract_otp_secrets
|
||||
LABEL org.opencontainers.image.license=GPL-3.0+
|
||||
LABEL maintainer="Scito https://scito.ch, https://github.com/scito"
|
||||
|
||||
@@ -13,7 +13,7 @@ Generate from file: README.md
|
||||
- [Installation of optional shared system libraries (recommended)](#installation-of-optional-shared-system-libraries-recommended)
|
||||
- [Program help: arguments and options](#program-help-arguments-and-options)
|
||||
- [Examples](#examples)
|
||||
- [Printing otp secrets form text file](#printing-otp-secrets-form-text-file)
|
||||
- [Printing otp secrets from text file](#printing-otp-secrets-from-text-file)
|
||||
- [Printing otp secrets from image file](#printing-otp-secrets-from-image-file)
|
||||
- [Writing otp secrets to csv file](#writing-otp-secrets-to-csv-file)
|
||||
- [Writing otp secrets to json file](#writing-otp-secrets-to-json-file)
|
||||
@@ -33,7 +33,8 @@ Generate from file: README.md
|
||||
- [pipenv](#pipenv)
|
||||
- [Visual Studio Code Remote - Containers / VSCode devcontainer](#visual-studio-code-remote---containers--vscode-devcontainer)
|
||||
- [venv](#venv)
|
||||
- [devbox](#devbox)
|
||||
- [devbox 1](#devbox-1)
|
||||
- [devbox 2](#devbox-2)
|
||||
- [docker](#docker)
|
||||
- [More docker examples](#more-docker-examples)
|
||||
- [Tests](#tests)
|
||||
@@ -52,5 +53,6 @@ Generate from file: README.md
|
||||
- [Problems and Troubleshooting](#problems-and-troubleshooting)
|
||||
- [Windows error message](#windows-error-message)
|
||||
- [Related projects](#related-projects)
|
||||
- [Third party documentation](#third-party-documentation)
|
||||
|
||||
Table of contents generated.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Title,User Name,HmacOtp-Secret-Base32,HmacOtp-Counter,Group
|
||||
,hotp demo,7KSQL2JTUDIS5EF65KLMRQIIGY,4,OTP/HOTP
|
||||
Title,User Name,HmacOtp-Secret-Base32,HmacOtp-Counter,Group
|
||||
,hotp demo,7KSQL2JTUDIS5EF65KLMRQIIGY,4,OTP/HOTP
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
Title,User Name,TimeOtp-Secret-Base32,Group
|
||||
raspberrypi,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
raspberrypi,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
,encoding: ¿äÄéÉ? (demo),7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
Title,User Name,TimeOtp-Secret-Base32,Group
|
||||
raspberrypi,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
raspberrypi,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
,encoding: ¿äÄéÉ? (demo),7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
name,secret,issuer,type,counter,url
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
|
||||
hotp demo,7KSQL2JTUDIS5EF65KLMRQIIGY,,hotp,4,otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
|
||||
encoding: ¿äÄéÉ? (demo),7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/encoding%3A%20%C2%BF%C3%A4%C3%84%C3%A9%C3%89%3F%20%28demo%29?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
name,secret,issuer,type,counter,url
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
|
||||
hotp demo,7KSQL2JTUDIS5EF65KLMRQIIGY,,hotp,4,otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
|
||||
encoding: ¿äÄéÉ? (demo),7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/encoding%3A%20%C2%BF%C3%A4%C3%84%C3%A9%C3%89%3F%20%28demo%29?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
|
||||
|
@@ -3,8 +3,7 @@ requires = [
|
||||
"pip",
|
||||
"nuitka",
|
||||
# https://setuptools-git-versioning.readthedocs.io/en/latest/differences.html
|
||||
"setuptools>=64.0.0",
|
||||
"setuptools-git-versioning",
|
||||
"setuptools-git-versioning",
|
||||
"wheel>=0.37.0",
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
@@ -21,11 +20,12 @@ classifiers = [
|
||||
"Topic :: Utilities",
|
||||
"Topic :: Security",
|
||||
"Topic :: Multimedia :: Graphics :: Capture :: Digital Camera",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
"Intended Audience :: End Users/Desktop",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: System Administrators",
|
||||
@@ -41,6 +41,9 @@ classifiers = [
|
||||
dependencies = [
|
||||
"colorama>=0.4.6",
|
||||
"opencv-contrib-python",
|
||||
"numpy>=2.0,<2.1 ; python_version >= '3.9' and python_version < '3.10'",
|
||||
"numpy>=2.2,<2.3 ; python_version >= '3.10' and python_version < '3.11'",
|
||||
"numpy>=2.3,<3.0 ; python_version >= '3.11'",
|
||||
"Pillow",
|
||||
"protobuf",
|
||||
"pyzbar",
|
||||
@@ -54,7 +57,7 @@ license = {text = "GNU General Public License v3 (GPLv3)"}
|
||||
readme = "README.md"
|
||||
authors = [{name = "scito", email = "info@scito.ch"}]
|
||||
maintainers = [{name = "scito", email = "info@scito.ch"}]
|
||||
requires-python = ">=3.8, <4"
|
||||
requires-python = ">=3.9, <4"
|
||||
scripts = {extract_otp_secrets = "extract_otp_secrets:sys_main"}
|
||||
urls = {Project-URL = "https://github.com/scito/extract_otp_secrets", Bug-Reports = "https://github.com/scito/extract_otp_secrets/issues", Source = "https://github.com/scito/extract_otp_secrets"}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
colorama>=0.4.6
|
||||
opencv-contrib-python
|
||||
numpy>=2.0,<2.1 ; python_version >= "3.9" and python_version < "3.10"
|
||||
numpy>=2.2,<2.3 ; python_version >= "3.10" and python_version < "3.11"
|
||||
numpy>=2.3,<3.0 ; python_version >= "3.11"
|
||||
Pillow
|
||||
protobuf
|
||||
pyzbar
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = extract_otp_secrets
|
||||
|
||||
[options]
|
||||
python_requires = >=3.8, <4
|
||||
python_requires = >=3.9, <4
|
||||
py_modules = extract_otp_secrets, protobuf_generated_python.google_auth_pb2
|
||||
package_dir =
|
||||
=src
|
||||
|
||||
@@ -36,6 +36,7 @@ import argparse
|
||||
import base64
|
||||
import csv
|
||||
import fileinput
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
@@ -48,7 +49,7 @@ from typing import (Any, Final, List, Optional, Sequence, TextIO, Tuple,
|
||||
TypedDict, Union)
|
||||
|
||||
import colorama
|
||||
from qrcode import QRCode # type: ignore
|
||||
from qrcode import QRCode
|
||||
|
||||
import protobuf_generated_python.google_auth_pb2 as pb
|
||||
|
||||
@@ -59,8 +60,8 @@ headless: bool = False
|
||||
|
||||
try:
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2.typing
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
import tkinter
|
||||
@@ -367,7 +368,7 @@ def extract_otps_from_camera(args: Args) -> Otps:
|
||||
if QRMode.CV2:
|
||||
otp_url, raw_pts, _ = cv2_qr.detectAndDecode(img)
|
||||
else:
|
||||
otp_url, raw_pts = cv2_qr_wechat.detectAndDecode(img) # type: ignore # use proper cv2 types
|
||||
otp_url, raw_pts = cv2_qr_wechat.detectAndDecode(img)
|
||||
if raw_pts is not None:
|
||||
if otp_url:
|
||||
new_otps_count = extract_otps_from_otp_url(otp_url, otp_urls, otps, args)
|
||||
@@ -379,14 +380,22 @@ def extract_otps_from_camera(args: Args) -> Otps:
|
||||
qr_mode = next_qr_mode(qr_mode)
|
||||
continue
|
||||
|
||||
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 c,j,k,t,u to save as csv/json/keepass/txt/urls file", 2, TextPosition.LEFT, FONT_COLOR, None)
|
||||
try:
|
||||
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 c,j,k,t,u to save as csv/json/keepass/txt/urls 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(otps)} otp{'s'[:len(otps) != 1]} extracted", 1, 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.imshow(WINDOW_NAME, img)
|
||||
cv2.imshow(WINDOW_NAME, img)
|
||||
except cv2.error as e:
|
||||
# Workaround due to Gtk2/3 problem, see #444
|
||||
if e.code == cv2.Error.StsNullPtr:
|
||||
# Window closed
|
||||
break
|
||||
else:
|
||||
raise e
|
||||
|
||||
quit, qr_mode = cv2_handle_pressed_keys(qr_mode, otps)
|
||||
if quit:
|
||||
@@ -448,7 +457,7 @@ def cv2_handle_pressed_keys(qr_mode: QRMode, otps: Otps) -> Tuple[bool, QRMode]:
|
||||
defaultextension='.csv',
|
||||
filetypes=[('CSV', '*.csv'), ('All', '*.*')]
|
||||
)
|
||||
tk_root.update()
|
||||
tk_root.update() # noqa: F821 # workaround flake8 false positive, tk_root is defined globally
|
||||
if len(file_name) > 0:
|
||||
write_csv(file_name, otps)
|
||||
elif (key == ord('j') or key == ord('J')) and is_not_headless():
|
||||
@@ -460,7 +469,7 @@ def cv2_handle_pressed_keys(qr_mode: QRMode, otps: Otps) -> Tuple[bool, QRMode]:
|
||||
defaultextension='.json',
|
||||
filetypes=[('JSON', '*.json'), ('All', '*.*')]
|
||||
)
|
||||
tk_root.update()
|
||||
tk_root.update() # noqa: F821 # workaround flake8 false positive, tk_root is defined globally
|
||||
if len(file_name) > 0:
|
||||
write_json(file_name, otps)
|
||||
elif (key == ord('k') or key == ord('K')) and is_not_headless():
|
||||
@@ -472,7 +481,7 @@ def cv2_handle_pressed_keys(qr_mode: QRMode, otps: Otps) -> Tuple[bool, QRMode]:
|
||||
defaultextension='.csv',
|
||||
filetypes=[('CSV', '*.csv'), ('All', '*.*')]
|
||||
)
|
||||
tk_root.update()
|
||||
tk_root.update() # noqa: F821 # workaround flake8 false positive, tk_root is defined globally
|
||||
if len(file_name) > 0:
|
||||
write_keepass_csv(file_name, otps)
|
||||
elif (key == ord('t') or key == ord('T')) and is_not_headless():
|
||||
@@ -484,7 +493,7 @@ def cv2_handle_pressed_keys(qr_mode: QRMode, otps: Otps) -> Tuple[bool, QRMode]:
|
||||
defaultextension='.txt',
|
||||
filetypes=[('Text', '*.txt'), ('All', '*.*')]
|
||||
)
|
||||
tk_root.update()
|
||||
tk_root.update() # noqa: F821 # workaround flake8 false positive, tk_root is defined globally
|
||||
if len(file_name) > 0:
|
||||
write_txt(file_name, otps, True)
|
||||
elif (key == ord('u') or key == ord('U')) and is_not_headless():
|
||||
@@ -496,15 +505,13 @@ def cv2_handle_pressed_keys(qr_mode: QRMode, otps: Otps) -> Tuple[bool, QRMode]:
|
||||
defaultextension='.txt',
|
||||
filetypes=[('Text', '*.txt'), ('All', '*.*')]
|
||||
)
|
||||
tk_root.update()
|
||||
tk_root.update() # noqa: F821 # workaround flake8 false positive, tk_root is defined globally
|
||||
if len(file_name) > 0:
|
||||
write_urls(file_name, otps)
|
||||
elif key == 32:
|
||||
qr_mode = next_valid_qr_mode(qr_mode, zbar_available)
|
||||
if verbose >= LogLevel.MORE_VERBOSE: print(f"QR reading mode: {qr_mode}")
|
||||
if cv2.getWindowProperty(WINDOW_NAME, cv2.WND_PROP_VISIBLE) < 1:
|
||||
# Window close clicked
|
||||
quit = True
|
||||
# Do not check for invisible window due to Gtk2/3 problem, see #444
|
||||
return quit, qr_mode
|
||||
|
||||
|
||||
@@ -527,14 +534,20 @@ def extract_otps_from_files(args: Args) -> Otps:
|
||||
|
||||
files_count = urls_count = otps_count = 0
|
||||
if verbose: print(f"Input files: {args.infile}")
|
||||
for infile in args.infile:
|
||||
if verbose >= LogLevel.MORE_VERBOSE: log_verbose(f"Processing infile {infile}")
|
||||
files_count += 1
|
||||
for line in get_otp_urls_from_file(infile, args):
|
||||
if verbose >= LogLevel.MORE_VERBOSE: log_verbose(line)
|
||||
if line.startswith('#') or line == '': continue
|
||||
urls_count += 1
|
||||
otps_count += extract_otp_from_otp_url(line, otps, urls_count, infile, args)
|
||||
for infile_raw in args.infile:
|
||||
expanded_infiles = glob.glob(infile_raw)
|
||||
if not expanded_infiles:
|
||||
expanded_infiles = [infile_raw]
|
||||
if verbose >= LogLevel.DEBUG: log_debug(f"Could not expand input files, fallback to infile {infile_raw}")
|
||||
if verbose >= LogLevel.DEBUG: log_debug(f"Expanded input files: {expanded_infiles}")
|
||||
for infile in expanded_infiles:
|
||||
if verbose >= LogLevel.MORE_VERBOSE: log_verbose(f"Processing infile {infile}")
|
||||
files_count += 1
|
||||
for line in get_otp_urls_from_file(infile, args):
|
||||
if verbose >= LogLevel.MORE_VERBOSE: log_verbose(line)
|
||||
if line.startswith('#') or line == '': continue
|
||||
urls_count += 1
|
||||
otps_count += extract_otp_from_otp_url(line, otps, urls_count, infile, args)
|
||||
if verbose: print(f"Extracted {otps_count} otp{'s'[:otps_count != 1]} from {urls_count} otp url{'s'[:urls_count != 1]} by reading {files_count} infile{'s'[:files_count != 1]}")
|
||||
return otps
|
||||
|
||||
@@ -592,7 +605,7 @@ def convert_img_to_otp_urls(filename: str, args: Args) -> OtpUrls:
|
||||
stdin = sys.stdin.buffer.read()
|
||||
except AttributeError:
|
||||
# Workaround for pytest, since pytest cannot monkeypatch sys.stdin.buffer
|
||||
stdin = sys.stdin.read() # type: ignore # Workaround for pytest fixtures
|
||||
stdin = sys.stdin.read()
|
||||
if not stdin:
|
||||
log_warn("stdin is empty")
|
||||
try:
|
||||
@@ -697,7 +710,7 @@ def save_qr_image_file(otp_url: OtpUrl, name: str) -> None:
|
||||
qr.add_data(otp_url)
|
||||
img = qr.make_image(fill_color='black', back_color='white')
|
||||
if verbose: print(f"Saving to {name}")
|
||||
img.save(name)
|
||||
img.save(name) # type: ignore
|
||||
|
||||
|
||||
def print_qr(otp_url: str, out: Optional[TextIO] = None) -> None:
|
||||
@@ -830,7 +843,7 @@ def check_file_exists(filename: str) -> None:
|
||||
def has_no_otps_show_warning(otps: Otps) -> bool:
|
||||
if len(otps) == 0:
|
||||
tkinter.messagebox.showinfo(title="No data", message="There are no otp secrets to write")
|
||||
tk_root.update() # dispose dialog
|
||||
tk_root.update() # dispose dialog # noqa: F821 # workaround flake8 false positive, tk_root is defined globally
|
||||
return len(otps) == 0
|
||||
|
||||
|
||||
@@ -915,10 +928,15 @@ def get_raw_version() -> str:
|
||||
|
||||
# workaround for PYTHON <= 3.9 use: BaseException | None
|
||||
def log_debug(*values: object, sep: Optional[str] = ' ') -> None:
|
||||
if os.name == 'nt':
|
||||
# Workaround "Windows fatal exception: access violation"
|
||||
print(f"\nDEBUG: {str(values[0])}")
|
||||
return
|
||||
|
||||
if colored:
|
||||
print(f"{colorama.Fore.CYAN}\nDEBUG: {str(values[0])}", *values[1:], colorama.Fore.RESET, sep)
|
||||
print(f"{colorama.Fore.CYAN}\nDEBUG: {str(values[0])}", *values[1:], colorama.Fore.RESET, sep=sep)
|
||||
else:
|
||||
print(f"\nDEBUG: {str(values[0])}", *values[1:], sep)
|
||||
print(f"\nDEBUG: {str(values[0])}", *values[1:], sep=sep)
|
||||
|
||||
|
||||
# workaround for PYTHON <= 3.9 use: BaseException | None
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: google_auth.proto
|
||||
# Protobuf Python Version: 5.27.2
|
||||
# Protobuf Python Version: 6.33.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
@@ -11,9 +11,9 @@ from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_runtime_version.ValidateProtobufRuntimeVersion(
|
||||
_runtime_version.Domain.PUBLIC,
|
||||
5,
|
||||
27,
|
||||
2,
|
||||
6,
|
||||
33,
|
||||
0,
|
||||
'',
|
||||
'google_auth.proto'
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
QReader installed: True
|
||||
CV2 version: 4.7.0
|
||||
CV2 version: 4.10.0
|
||||
QR reading mode: ZBAR
|
||||
|
||||
Input files: ['example_export.txt']
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
QReader installed: True
|
||||
CV2 version: 4.7.0
|
||||
CV2 version: 4.10.0
|
||||
QR reading mode: ZBAR
|
||||
|
||||
Input files: ['example_export.txt']
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
QReader installed: True
|
||||
CV2 version: 4.7.0
|
||||
CV2 version: 4.10.0
|
||||
QR reading mode: ZBAR
|
||||
|
||||
Version: extract_otp_secrets 2.0.2.post50+git.158245dd.dirty Linux x86_64 Python 3.11.1 (CPython/called as script)
|
||||
Version: extract_otp_secrets 2.8.4.post4+git.7ce765dd.dirty Linux x86_64 Python 3.11.10 (CPython/called as script)
|
||||
|
||||
Input files: ['example_export.txt']
|
||||
|
||||
DEBUG: Expanded input files: ['example_export.txt']
|
||||
Processing infile example_export.txt
|
||||
Reading lines of example_export.txt
|
||||
# 2FA example from https://www.raspberrypi.org/blog/setting-up-two-factor-authentication-on-your-raspberry-pi/
|
||||
@@ -32,16 +34,17 @@ otpauth-migration://offline?data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8O
|
||||
# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
|
||||
otpauth-migration://offline?data=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK%2B%2F%2F%2F%2F%2F8B
|
||||
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK%2B%2F%2F%2F%2F%2F8B', fragment='')
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK%2B%2F%2F%2F%2F%2F8B', fragment='')
|
||||
|
||||
DEBUG: querystring params={'data': ['CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B']}
|
||||
DEBUG: querystring params={'data': ['CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B']}
|
||||
|
||||
DEBUG: data_base64=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B
|
||||
DEBUG: data_base64=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B
|
||||
|
||||
DEBUG: data_base64_fixed=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B
|
||||
DEBUG: data_base64_fixed=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B
|
||||
|
||||
DEBUG:
|
||||
1. Payload Line otp_parameters {
|
||||
1. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "pi@raspberrypi"
|
||||
issuer: "raspberrypi"
|
||||
@@ -52,12 +55,11 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -1320898453
|
||||
|
||||
|
||||
|
||||
1. Secret
|
||||
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Issuer: raspberrypi
|
||||
@@ -68,16 +70,17 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspber
|
||||
# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
otpauth-migration://offline?data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4%2F%2F%2F%2F%2FwE%3D
|
||||
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4%2F%2F%2F%2F%2FwE%3D', fragment='')
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4%2F%2F%2F%2F%2FwE%3D', fragment='')
|
||||
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=']}
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=']}
|
||||
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=
|
||||
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=
|
||||
|
||||
DEBUG:
|
||||
2. Payload Line otp_parameters {
|
||||
2. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "pi@raspberrypi"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -87,12 +90,11 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -2094403140
|
||||
|
||||
|
||||
|
||||
2. Secret
|
||||
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: totp
|
||||
@@ -103,16 +105,17 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
otpauth-migration://offline?data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B
|
||||
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B', fragment='')
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B', fragment='')
|
||||
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B']}
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B']}
|
||||
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B
|
||||
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B
|
||||
|
||||
DEBUG:
|
||||
3. Payload Line otp_parameters {
|
||||
3. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "pi@raspberrypi"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -130,12 +133,11 @@ otp_parameters {
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -1822886384
|
||||
|
||||
|
||||
|
||||
3. Secret
|
||||
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: totp
|
||||
@@ -144,7 +146,7 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
|
||||
4. Secret
|
||||
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Issuer: raspberrypi
|
||||
@@ -155,16 +157,17 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspber
|
||||
# otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
|
||||
otpauth-migration://offline?data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D
|
||||
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D', fragment='')
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D', fragment='')
|
||||
|
||||
DEBUG: querystring params={'data': ['CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=']}
|
||||
DEBUG: querystring params={'data': ['CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=']}
|
||||
|
||||
DEBUG: data_base64=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=
|
||||
DEBUG: data_base64=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=
|
||||
|
||||
DEBUG: data_base64_fixed=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=
|
||||
DEBUG: data_base64_fixed=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=
|
||||
|
||||
DEBUG:
|
||||
4. Payload Line otp_parameters {
|
||||
4. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "hotp demo"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -175,12 +178,11 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -1558849573
|
||||
|
||||
|
||||
|
||||
5. Secret
|
||||
|
||||
DEBUG: OTP enum type: OTP_HOTP
|
||||
DEBUG: OTP enum type: OTP_HOTP
|
||||
Name: hotp demo
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: hotp
|
||||
@@ -192,16 +194,17 @@ otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
|
||||
# Name: "encoding: ¿äÄéÉ? (demo)"
|
||||
otpauth-migration://offline?data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv%2F%2F%2F%2F%2F%2FAQ%3D%3D
|
||||
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv%2F%2F%2F%2F%2F%2FAQ%3D%3D', fragment='')
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv%2F%2F%2F%2F%2F%2FAQ%3D%3D', fragment='')
|
||||
|
||||
DEBUG: querystring params={'data': ['CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==']}
|
||||
DEBUG: querystring params={'data': ['CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==']}
|
||||
|
||||
DEBUG: data_base64=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==
|
||||
DEBUG: data_base64=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==
|
||||
|
||||
DEBUG: data_base64_fixed=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==
|
||||
DEBUG: data_base64_fixed=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==
|
||||
|
||||
DEBUG:
|
||||
5. Payload Line otp_parameters {
|
||||
5. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "encoding: ¿äÄéÉ? (demo)"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -211,12 +214,11 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -171198419
|
||||
|
||||
|
||||
|
||||
6. Secret
|
||||
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
DEBUG: OTP enum type: OTP_TOTP
|
||||
Name: encoding: ¿äÄéÉ? (demo)
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: totp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
QReader installed: True
|
||||
CV2 version: 4.7.0
|
||||
CV2 version: 4.10.0
|
||||
QR reading mode: ZBAR
|
||||
|
||||
Input files: ['example_export.txt']
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
QReader installed: True
|
||||
CV2 version: 4.7.0
|
||||
CV2 version: 4.10.0
|
||||
QR reading mode: ZBAR
|
||||
|
||||
Input files: ['example_export.txt']
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
QReader installed: True
|
||||
CV2 version: 4.7.0
|
||||
CV2 version: 4.10.0
|
||||
QR reading mode: ZBAR
|
||||
|
||||
Version: extract_otp_secrets 2.0.2.post50+git.158245dd.dirty Linux x86_64 Python 3.11.1 (CPython/called as script)
|
||||
Version: extract_otp_secrets 2.8.4.post4+git.7ce765dd.dirty Linux x86_64 Python 3.11.10 (CPython/called as script)
|
||||
|
||||
Input files: ['example_export.txt']
|
||||
[36m
|
||||
DEBUG: Expanded input files: ['example_export.txt'] [39m
|
||||
[36mProcessing infile example_export.txt[39m
|
||||
Reading lines of example_export.txt
|
||||
[36m# 2FA example from https://www.raspberrypi.org/blog/setting-up-two-factor-authentication-on-your-raspberry-pi/[39m
|
||||
@@ -32,16 +34,17 @@ Reading lines of example_export.txt
|
||||
[36m# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi[39m
|
||||
[36motpauth-migration://offline?data=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK%2B%2F%2F%2F%2F%2F8B[39m
|
||||
[36m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK%2B%2F%2F%2F%2F%2F8B', fragment='') [39m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK%2B%2F%2F%2F%2F%2F8B', fragment='') [39m
|
||||
[36m
|
||||
DEBUG: querystring params={'data': ['CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B']} [39m
|
||||
DEBUG: querystring params={'data': ['CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B']} [39m
|
||||
[36m
|
||||
DEBUG: data_base64=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B [39m
|
||||
DEBUG: data_base64=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B [39m
|
||||
[36m
|
||||
DEBUG: data_base64_fixed=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B [39m
|
||||
DEBUG: data_base64_fixed=CjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACjr4JKK+/////8B [39m
|
||||
[36m
|
||||
DEBUG:
|
||||
1. Payload Line otp_parameters {
|
||||
1. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "pi@raspberrypi"
|
||||
issuer: "raspberrypi"
|
||||
@@ -52,12 +55,12 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -1320898453
|
||||
[39m
|
||||
|
||||
[39m
|
||||
|
||||
1. Secret
|
||||
[36m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Issuer: raspberrypi
|
||||
@@ -68,16 +71,17 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspber
|
||||
[36m# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY[39m
|
||||
[36motpauth-migration://offline?data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4%2F%2F%2F%2F%2FwE%3D[39m
|
||||
[36m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4%2F%2F%2F%2F%2FwE%3D', fragment='') [39m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4%2F%2F%2F%2F%2FwE%3D', fragment='') [39m
|
||||
[36m
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=']} [39m
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE=']} [39m
|
||||
[36m
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE= [39m
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE= [39m
|
||||
[36m
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE= [39m
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACEAEYASAAKLzjp5n4/////wE= [39m
|
||||
[36m
|
||||
DEBUG:
|
||||
2. Payload Line otp_parameters {
|
||||
2. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "pi@raspberrypi"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -87,12 +91,12 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -2094403140
|
||||
[39m
|
||||
|
||||
[39m
|
||||
|
||||
2. Secret
|
||||
[36m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: totp
|
||||
@@ -103,16 +107,17 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
[36m# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY[39m
|
||||
[36motpauth-migration://offline?data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B[39m
|
||||
[36m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B', fragment='') [39m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B', fragment='') [39m
|
||||
[36m
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B']} [39m
|
||||
DEBUG: querystring params={'data': ['CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B']} [39m
|
||||
[36m
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B [39m
|
||||
DEBUG: data_base64=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B [39m
|
||||
[36m
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B [39m
|
||||
DEBUG: data_base64_fixed=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa+f////8B [39m
|
||||
[36m
|
||||
DEBUG:
|
||||
3. Payload Line otp_parameters {
|
||||
3. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "pi@raspberrypi"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -130,12 +135,12 @@ otp_parameters {
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -1822886384
|
||||
[39m
|
||||
|
||||
[39m
|
||||
|
||||
3. Secret
|
||||
[36m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: totp
|
||||
@@ -144,7 +149,7 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
|
||||
4. Secret
|
||||
[36m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
Name: pi@raspberrypi
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Issuer: raspberrypi
|
||||
@@ -155,16 +160,17 @@ otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspber
|
||||
[36m# otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4[39m
|
||||
[36motpauth-migration://offline?data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D[39m
|
||||
[36m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D', fragment='') [39m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D', fragment='') [39m
|
||||
[36m
|
||||
DEBUG: querystring params={'data': ['CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=']} [39m
|
||||
DEBUG: querystring params={'data': ['CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE=']} [39m
|
||||
[36m
|
||||
DEBUG: data_base64=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE= [39m
|
||||
DEBUG: data_base64=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE= [39m
|
||||
[36m
|
||||
DEBUG: data_base64_fixed=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE= [39m
|
||||
DEBUG: data_base64_fixed=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6/////wE= [39m
|
||||
[36m
|
||||
DEBUG:
|
||||
4. Payload Line otp_parameters {
|
||||
4. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "hotp demo"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -175,12 +181,12 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -1558849573
|
||||
[39m
|
||||
|
||||
[39m
|
||||
|
||||
5. Secret
|
||||
[36m
|
||||
DEBUG: OTP enum type: OTP_HOTP [39m
|
||||
DEBUG: OTP enum type: OTP_HOTP [39m
|
||||
Name: hotp demo
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: hotp
|
||||
@@ -192,16 +198,17 @@ otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
|
||||
[36m# Name: "encoding: ¿äÄéÉ? (demo)"[39m
|
||||
[36motpauth-migration://offline?data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv%2F%2F%2F%2F%2F%2FAQ%3D%3D[39m
|
||||
[36m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv%2F%2F%2F%2F%2F%2FAQ%3D%3D', fragment='') [39m
|
||||
DEBUG: parsed_url=ParseResult(scheme='otpauth-migration', netloc='offline', path='', params='', query='data=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv%2F%2F%2F%2F%2F%2FAQ%3D%3D', fragment='') [39m
|
||||
[36m
|
||||
DEBUG: querystring params={'data': ['CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==']} [39m
|
||||
DEBUG: querystring params={'data': ['CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ==']} [39m
|
||||
[36m
|
||||
DEBUG: data_base64=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ== [39m
|
||||
DEBUG: data_base64=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ== [39m
|
||||
[36m
|
||||
DEBUG: data_base64_fixed=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ== [39m
|
||||
DEBUG: data_base64_fixed=CjYKEPqlBekzoNEukL7qlsjBCDYSHGVuY29kaW5nOiDCv8Okw4TDqcOJPyAoZGVtbykgASgBMAIQARgBIAAorfCurv//////AQ== [39m
|
||||
[36m
|
||||
DEBUG:
|
||||
5. Payload Line otp_parameters {
|
||||
5. Payload Line
|
||||
otp_parameters {
|
||||
secret: "\372\245\005\3513\240\321.\220\276\352\226\310\301\0106"
|
||||
name: "encoding: ¿äÄéÉ? (demo)"
|
||||
algorithm: ALGO_SHA1
|
||||
@@ -211,12 +218,12 @@ DEBUG:
|
||||
version: 1
|
||||
batch_size: 1
|
||||
batch_id: -171198419
|
||||
[39m
|
||||
|
||||
[39m
|
||||
|
||||
6. Secret
|
||||
[36m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
DEBUG: OTP enum type: OTP_TOTP [39m
|
||||
Name: encoding: ¿äÄéÉ? (demo)
|
||||
Secret: 7KSQL2JTUDIS5EF65KLMRQIIGY
|
||||
Type: totp
|
||||
|
||||
@@ -559,13 +559,16 @@ def test_normalize_bytes() -> None:
|
||||
# Generate verbose output:
|
||||
# for color in '' '-n'; do for level in '' '-v' '-vv' '-vvv'; do python3.11 src/extract_otp_secrets.py example_export.txt $color $level > tests/data/print_verbose_output$color$level.txt; done; done
|
||||
# workaround for PYTHON <= 3.10
|
||||
@pytest.mark.skipif(sys.version_info < (3, 10), reason="fileinput.input encoding exists since PYTHON 3.10")
|
||||
@pytest.mark.parametrize("verbose_level", ['', '-v', '-vv', '-vvv'])
|
||||
@pytest.mark.skipif(sys.version_info < (3, 10), reason="fileinput.input encoding exists since PYTHON 3.10 OR Windows fatal exception: access violation")
|
||||
@pytest.mark.parametrize("verbose_level", ['', '-v', '-vv', '-vvv' if not sys.platform.startswith("win") else None])
|
||||
@pytest.mark.parametrize("color", ['', '-n'])
|
||||
def test_extract_verbose(verbose_level: str, color: str, capsys: pytest.CaptureFixture[str], relaxed: bool) -> None:
|
||||
args = ['example_export.txt']
|
||||
if verbose_level:
|
||||
args.append(verbose_level)
|
||||
elif verbose_level is None:
|
||||
print('Skip parameterized test\n')
|
||||
return
|
||||
if color:
|
||||
args.append(color)
|
||||
# Act
|
||||
@@ -849,7 +852,14 @@ data=XXXX
|
||||
Exception: unpack requires a buffer of 4 bytes
|
||||
'''
|
||||
|
||||
assert captured.err == first_expected_stderr or captured.err == second_expected_stderr
|
||||
#
|
||||
third_expected_stderr = '''
|
||||
ERROR: Cannot decode otpauth-migration migration payload.
|
||||
data=XXXX
|
||||
Exception: Error parsing message with type 'MigrationPayload'
|
||||
'''
|
||||
|
||||
assert captured.err == first_expected_stderr or captured.err == second_expected_stderr or captured.err == third_expected_stderr
|
||||
assert captured.out == ''
|
||||
assert e.value.code == 1
|
||||
assert e.type == SystemExit
|
||||
@@ -862,19 +872,8 @@ def test_wrong_content(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
expected_stderr = '''
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
input: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
Maybe a wrong file was given
|
||||
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
url: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
'''
|
||||
|
||||
assert captured.out == ''
|
||||
assert captured.err == expected_stderr
|
||||
assert captured.err == EXPECTED_STDERR_OTP_URL_WRONG
|
||||
|
||||
|
||||
def test_one_wrong_file(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
@@ -884,19 +883,8 @@ def test_one_wrong_file(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
expected_stderr = '''
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
input: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
Maybe a wrong file was given
|
||||
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
url: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
'''
|
||||
|
||||
assert captured.out == EXPECTED_STDOUT_FROM_EXAMPLE_EXPORT
|
||||
assert captured.err == expected_stderr
|
||||
assert captured.err == EXPECTED_STDERR_OTP_URL_WRONG
|
||||
|
||||
|
||||
def test_one_wrong_file_colored(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
@@ -906,19 +894,8 @@ def test_one_wrong_file_colored(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
expected_stderr = f'''{colorama.Fore.RED}
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
input: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
Maybe a wrong file was given{colorama.Fore.RESET}
|
||||
{colorama.Fore.RED}
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
url: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.{colorama.Fore.RESET}
|
||||
'''
|
||||
|
||||
assert captured.out == EXPECTED_STDOUT_FROM_EXAMPLE_EXPORT
|
||||
assert captured.err == expected_stderr
|
||||
assert captured.err == EXPECTED_STDERR_COLORED_OTP_URL_WRONG
|
||||
|
||||
|
||||
def test_one_wrong_line(capsys: pytest.CaptureFixture[str], monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@@ -990,6 +967,46 @@ def test_img_qr_reader_from_file_happy_path(capsys: pytest.CaptureFixture[str])
|
||||
assert captured.err == ''
|
||||
|
||||
|
||||
@pytest.mark.qreader
|
||||
def test_img_qr_reader_but_no_otp_from_file(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
# Act
|
||||
extract_otp_secrets.main(['-n', 'tests/data/qr_but_without_otp.png'])
|
||||
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert captured.out == ''
|
||||
assert captured.err == EXPECTED_STDERR_NO_OTP_URL
|
||||
|
||||
|
||||
@pytest.mark.qreader
|
||||
def test_img_qr_reader_from_wildcard(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
# Act
|
||||
extract_otp_secrets.main(['-n', 'tests/data/*.png'])
|
||||
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert captured.out == EXPECTED_STDOUT_FROM_EXAMPLE_EXPORT_PNG
|
||||
assert normalize_testfile_path(captured.err) == EXPECTED_STDERR_NO_OTP_URL
|
||||
|
||||
|
||||
def normalize_testfile_path(text: str) -> str:
|
||||
return text.replace('tests/data\\', 'tests/data/') if sys.platform.startswith("win") else text
|
||||
|
||||
|
||||
@pytest.mark.qreader
|
||||
def test_img_qr_reader_from_multiple_files(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
# Act
|
||||
extract_otp_secrets.main(['-n', 'tests/data/test_googleauth_export.png', 'tests/data/text_masquerading_as_image.jpeg'])
|
||||
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert captured.out == EXPECTED_STDOUT_FROM_EXAMPLE_EXPORT_PNG
|
||||
assert captured.err == EXPECTED_STDERR_BAD_IMAGE
|
||||
|
||||
|
||||
@pytest.mark.qreader
|
||||
def test_img_qr_reader_by_parameter(capsys: pytest.CaptureFixture[str], qr_mode: str) -> None:
|
||||
# Act
|
||||
@@ -1034,24 +1051,7 @@ def test_img_qr_reader_from_stdin(capsys: pytest.CaptureFixture[str], monkeypatc
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
|
||||
expected_stdout = '''Name: Test1:test1@example1.com
|
||||
Secret: JBSWY3DPEHPK3PXP
|
||||
Issuer: Test1
|
||||
Type: totp
|
||||
|
||||
Name: Test2:test2@example2.com
|
||||
Secret: JBSWY3DPEHPK3PXQ
|
||||
Issuer: Test2
|
||||
Type: totp
|
||||
|
||||
Name: Test3:test3@example3.com
|
||||
Secret: JBSWY3DPEHPK3PXR
|
||||
Issuer: Test3
|
||||
Type: totp
|
||||
|
||||
'''
|
||||
|
||||
assert captured.out == expected_stdout
|
||||
assert captured.out == EXPECTED_STDOUT_FROM_EXAMPLE_EXPORT_PNG
|
||||
assert captured.err == ''
|
||||
|
||||
|
||||
@@ -1136,19 +1136,9 @@ def test_non_image_file(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
|
||||
# Assert
|
||||
captured = capsys.readouterr()
|
||||
expected_stderr = '''
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/text_masquerading_as_image.jpeg
|
||||
input: This is just a text file masquerading as an image file.
|
||||
Maybe a wrong file was given
|
||||
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/text_masquerading_as_image.jpeg
|
||||
url: This is just a text file masquerading as an image file.
|
||||
'''
|
||||
|
||||
assert captured.err == expected_stderr
|
||||
assert captured.out == ''
|
||||
assert captured.err == EXPECTED_STDERR_BAD_IMAGE
|
||||
|
||||
|
||||
def test_next_valid_qr_mode() -> None:
|
||||
@@ -1202,3 +1192,47 @@ Issuer: Test3
|
||||
Type: totp
|
||||
|
||||
'''
|
||||
|
||||
EXPECTED_STDERR_OTP_URL_WRONG = '''
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
input: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
Maybe a wrong file was given
|
||||
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
url: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
'''
|
||||
|
||||
EXPECTED_STDERR_COLORED_OTP_URL_WRONG = f'''{colorama.Fore.RED}
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
input: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
Maybe a wrong file was given{colorama.Fore.RESET}
|
||||
{colorama.Fore.RED}
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/test_export_wrong_content.txt
|
||||
url: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.{colorama.Fore.RESET}
|
||||
'''
|
||||
|
||||
EXPECTED_STDERR_NO_OTP_URL = '''
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/qr_but_without_otp.png
|
||||
input: NOT A otpauth-migration:// URL
|
||||
Maybe a wrong file was given
|
||||
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/qr_but_without_otp.png
|
||||
url: NOT A otpauth-migration:// URL
|
||||
'''
|
||||
|
||||
EXPECTED_STDERR_BAD_IMAGE = '''
|
||||
WARN: input is not a otpauth-migration:// url
|
||||
source: tests/data/text_masquerading_as_image.jpeg
|
||||
input: This is just a text file masquerading as an image file.
|
||||
Maybe a wrong file was given
|
||||
|
||||
ERROR: could not parse query parameter in input url
|
||||
source: tests/data/text_masquerading_as_image.jpeg
|
||||
url: This is just a text file masquerading as an image file.
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user