Option to save QR codes as PNG (#2)

* Generate QR code images

Now generates QR images instead of attempting to display the QR code in the console. Places them in a subdirectory of the current directory, entitled "qr"

* Update README.md

* Changes based on suggestions from scito

https://github.com/scito/extract_otp_secret_keys/pull/2#pullrequestreview-555264890

* Update extract_otp_secret_keys.py

Minor formatting changes and clarifications to help text

* Update extract_otp_secret_keys.py

Remove --qr argument, instead opting to respond to --printqr or --saveqr
This commit is contained in:
FrankAbagnaleJr 2020-12-21 12:19:13 -06:00 committed by GitHub
parent 6068eb142c
commit cc26f7b589
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 5 deletions

View file

@ -21,7 +21,7 @@ The protobuf package of Google for proto3 is required for running this script.
For printing QR codes, the qrcode module is required For printing QR codes, the qrcode module is required
pip install qrcode pip install qrcode[pil]
## Technical background ## Technical background

View file

@ -46,17 +46,22 @@ import base64
import fileinput import fileinput
import sys import sys
from urllib.parse import parse_qs, urlencode, urlparse, quote from urllib.parse import parse_qs, urlencode, urlparse, quote
from os import path, mkdir
from re import sub, compile as rcompile
import generated_python.google_auth_pb2 import generated_python.google_auth_pb2
arg_parser = argparse.ArgumentParser() 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('--qr', '-q', help='print QR codes (otpauth://...)', 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('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()
verbose = args.verbose verbose = args.verbose
if args.qr: saveqr = args.saveqr
printqr = args.printqr
if saveqr or printqr:
from qrcode import QRCode from qrcode import QRCode
# https://stackoverflow.com/questions/40226049/find-enums-listed-in-python-descriptor-for-protobuf # https://stackoverflow.com/questions/40226049/find-enums-listed-in-python-descriptor-for-protobuf
@ -68,6 +73,13 @@ def convert_secret_from_bytes_to_base32_str(bytes):
return str(base64.b32encode(otp.secret), 'utf-8').replace('=', '') return str(base64.b32encode(otp.secret), 'utf-8').replace('=', '')
def save_qr(data, name):
qr = QRCode()
qr.add_data(data)
img = qr.make_image(fill_color="black", back_color="white")
if verbose: print("Saving to {}".format(name))
img.save(name)
def print_qr(data): def print_qr(data):
qr = QRCode() qr = QRCode()
qr.add_data(data) qr.add_data(data)
@ -85,7 +97,9 @@ for line in (line.strip() for line in fileinput.input(args.infile)):
if verbose: print(payload) if verbose: print(payload)
# pylint: disable=no-member # pylint: disable=no-member
i = 0
for otp in payload.otp_parameters: for otp in payload.otp_parameters:
i += 1
print('\nName: {}'.format(otp.name)) print('\nName: {}'.format(otp.name))
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))
@ -95,6 +109,14 @@ for line in (line.strip() for line in fileinput.input(args.infile)):
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
otp_url = 'otpauth://{}/{}?'.format('totp' if otp.type == 2 else 'hotp', quote(otp.name)) + urlencode(url_params) otp_url = 'otpauth://{}/{}?'.format('totp' if otp.type == 2 else 'hotp', quote(otp.name)) + urlencode(url_params)
if args.qr: if saveqr:
if verbose: print(otp_url)
if not(path.exists("qr")): mkdir("qr")
pattern = rcompile('[\W_]+')
file_otp_name = pattern.sub('', otp.name)
file_otp_issuer = pattern.sub('', otp.issuer)
if not(file_otp_issuer): print_qr(otp_url, "qr/{}-{}.png".format(i, file_otp_name))
if file_otp_issuer: save_qr(otp_url, "qr/{}-{}-{}.png".format(i,file_otp_name, file_otp_issuer))
if printqr:
if verbose: print(otp_url) if verbose: print(otp_url)
print_qr(otp_url) print_qr(otp_url)