mirror of
https://github.com/scito/extract_otp_secrets.git
synced 2025-12-15 11:21:43 +01:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a8ba31947 | ||
|
|
bf96148461 | ||
|
|
5dc155f556 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1 +1,6 @@
|
|||||||
|
generated_python/__pycache__/
|
||||||
qr/
|
qr/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
*.csv
|
||||||
|
*.json
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -28,6 +28,18 @@ For printing QR codes, the qrcode module is required
|
|||||||
|
|
||||||
pip install qrcode[pil]
|
pip install qrcode[pil]
|
||||||
|
|
||||||
|
### Alternative installation method
|
||||||
|
|
||||||
|
Alternatively, you can use a python virtual env for the dependencies:
|
||||||
|
|
||||||
|
python -m venv venv
|
||||||
|
. venv/bin/activate
|
||||||
|
pip install -r requirements-buildenv.txt
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
The requirements\*.txt files contain all the dependencies (also the optional ones).
|
||||||
|
To leave the python virtual env just call `deactivate`.
|
||||||
|
|
||||||
## Technical background
|
## Technical background
|
||||||
|
|
||||||
The export QR code of "Google Authenticator" contains the URL `otpauth-migration://offline?data=...`.
|
The export QR code of "Google Authenticator" contains the URL `otpauth-migration://offline?data=...`.
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ import argparse
|
|||||||
import base64
|
import base64
|
||||||
import fileinput
|
import fileinput
|
||||||
import sys
|
import sys
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
from urllib.parse import parse_qs, urlencode, urlparse, quote
|
from urllib.parse import parse_qs, urlencode, urlparse, quote
|
||||||
from os import path, mkdir
|
from os import path, mkdir
|
||||||
from re import sub, compile as rcompile
|
from re import sub, compile as rcompile
|
||||||
@@ -54,6 +56,8 @@ arg_parser = argparse.ArgumentParser()
|
|||||||
arg_parser.add_argument('--verbose', '-v', help='verbose output', action='store_true')
|
arg_parser.add_argument('--verbose', '-v', help='verbose output', action='store_true')
|
||||||
arg_parser.add_argument('--saveqr', '-s', help='save QR code(s) as images to the "qr" subfolder', action='store_true')
|
arg_parser.add_argument('--saveqr', '-s', help='save QR code(s) as images to the "qr" subfolder', action='store_true')
|
||||||
arg_parser.add_argument('--printqr', '-p', help='print QR code(s) as text to the terminal', action='store_true')
|
arg_parser.add_argument('--printqr', '-p', help='print QR code(s) as text to the terminal', action='store_true')
|
||||||
|
arg_parser.add_argument('--json', '-j', help='export to json file')
|
||||||
|
arg_parser.add_argument('--csv', '-c', help='export to csv file')
|
||||||
arg_parser.add_argument('infile', help='file or - for stdin (default: -) with "otpauth-migration://..." URLs separated by newlines, lines starting with # are ignored')
|
arg_parser.add_argument('infile', help='file or - for stdin (default: -) with "otpauth-migration://..." URLs separated by newlines, lines starting with # are ignored')
|
||||||
args = arg_parser.parse_args()
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
@@ -78,7 +82,9 @@ def save_qr(data, name):
|
|||||||
def print_qr(data):
|
def print_qr(data):
|
||||||
qr = QRCode()
|
qr = QRCode()
|
||||||
qr.add_data(data)
|
qr.add_data(data)
|
||||||
qr.print_tty()
|
qr.print_ascii()
|
||||||
|
|
||||||
|
otps = []
|
||||||
|
|
||||||
i = j = 0
|
i = j = 0
|
||||||
for line in (line.strip() for line in fileinput.input(args.infile)):
|
for line in (line.strip() for line in fileinput.input(args.infile)):
|
||||||
@@ -106,7 +112,8 @@ for line in (line.strip() for line in fileinput.input(args.infile)):
|
|||||||
secret = convert_secret_from_bytes_to_base32_str(otp.secret)
|
secret = convert_secret_from_bytes_to_base32_str(otp.secret)
|
||||||
print('Secret: {}'.format(secret))
|
print('Secret: {}'.format(secret))
|
||||||
if otp.issuer: print('Issuer: {}'.format(otp.issuer))
|
if otp.issuer: print('Issuer: {}'.format(otp.issuer))
|
||||||
print('Type: {}'.format(get_enum_name_by_number(otp, 'type')))
|
otp_type = get_enum_name_by_number(otp, 'type')
|
||||||
|
print('Type: {}'.format(otp_type))
|
||||||
url_params = { 'secret': secret }
|
url_params = { 'secret': secret }
|
||||||
if otp.type == 1: url_params['counter'] = otp.counter
|
if otp.type == 1: url_params['counter'] = otp.counter
|
||||||
if otp.issuer: url_params['issuer'] = otp.issuer
|
if otp.issuer: url_params['issuer'] = otp.issuer
|
||||||
@@ -120,3 +127,23 @@ for line in (line.strip() for line in fileinput.input(args.infile)):
|
|||||||
file_otp_name = pattern.sub('', otp.name)
|
file_otp_name = pattern.sub('', otp.name)
|
||||||
file_otp_issuer = pattern.sub('', otp.issuer)
|
file_otp_issuer = pattern.sub('', otp.issuer)
|
||||||
save_qr(otp_url, 'qr/{}-{}{}.png'.format(j, file_otp_name, '-' + file_otp_issuer if file_otp_issuer else ''))
|
save_qr(otp_url, 'qr/{}-{}{}.png'.format(j, file_otp_name, '-' + file_otp_issuer if file_otp_issuer else ''))
|
||||||
|
|
||||||
|
otps.append({
|
||||||
|
"name": otp.name,
|
||||||
|
"secret": secret,
|
||||||
|
"issuer": otp.issuer,
|
||||||
|
"type": otp_type,
|
||||||
|
"url": otp_url
|
||||||
|
})
|
||||||
|
|
||||||
|
if args.csv and len(otps) > 0:
|
||||||
|
with open(args.csv, "w") as outfile:
|
||||||
|
writer = csv.DictWriter(outfile, otps[0].keys())
|
||||||
|
writer.writeheader()
|
||||||
|
writer.writerows(otps)
|
||||||
|
print("Exported {} otps to csv".format(len(otps)))
|
||||||
|
|
||||||
|
if args.json:
|
||||||
|
with open(args.json, "w") as outfile:
|
||||||
|
json.dump(otps, outfile, indent = 4)
|
||||||
|
print("Exported {} otp entries to json".format(len(otps)))
|
||||||
|
|||||||
1
requirements-buildenv.txt
Normal file
1
requirements-buildenv.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
wheel
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
protobuf
|
||||||
|
qrcode
|
||||||
|
Pillow
|
||||||
Reference in New Issue
Block a user