From af80b5340276cccc51f733b5a18aa1582fd099f9 Mon Sep 17 00:00:00 2001 From: Fredrik Wahlberg Date: Sat, 14 Jul 2018 12:16:33 +0200 Subject: [PATCH] =?UTF-8?q?Raderar=20ursprungliga=20totp.py=20och=20d?= =?UTF-8?q?=C3=B6per=20om=20alla.py=20till=20totp.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- alla.py | 159 -------------------------------------------------------- totp.py | 128 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 109 insertions(+), 178 deletions(-) delete mode 100755 alla.py mode change 100644 => 100755 totp.py diff --git a/alla.py b/alla.py deleted file mode 100755 index d84858c..0000000 --- a/alla.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import print_function -import argparse -import base64 -import ConfigParser -import hashlib -import hmac -import json -import os -import struct -import time - - - -def die(reason): - # Terminate with an error message - print("Ecountered an error, terminating") - print("Error message -", reason) - exit(1) - - -def get_arguments(): - # Get input from the command line - parser = argparse.ArgumentParser() - parser.add_argument("site", nargs="*") - default_cfg_path = os.environ['HOME'] + '/.totprc' - parser.add_argument("-c", "--config", default=default_cfg_path, help='Path to config-file. Defaults to ~/.totprc') - - args = parser.parse_args() - return args - - -def menu(data): - # Print a pretty menu to choose from - keynum = 1 - print(" ---------------- Available keys ----------------") - print(" |") - for p in data: - print(" | %2d - %s" % (keynum, p["label"])) - keynum = keynum + 1 - - print(" |") - print(" ------------------------------------------------") - print(" | Please select which key to generate [1 - %d] |" % keynum) - print(" ------------------------------------------------") - print() - return keynum - - -def print_OTP(secret): - # Generate the key and pretty print it - value = TOTP(secret).generate() - # Format response like XXX XXX - print(value[:3], value[3:]) - - -def read_config(args): - # Read from the config file - config = ConfigParser.ConfigParser() - - try: - config.read(args.config) - except: - # Error in config file - die("Could not read %s" % args.config) - - # Verify that the config is correct - try: - config.get('totp', 'andOTPfile') - except: - die("Could not find path to 'andOTPfile' in %s" % args.config) - - if not os.path.isfile(config.get('totp', 'andOTPfile')): - die("The file %s does not exist" % config.get('totp', 'andOTPfile')) - - return config - - -def read_file(config): - # Open and parse the data file - try: - with open(config.get('totp', 'andOTPfile')) as filen: - data = json.load(filen) - except: - die("Error parsing JSON, corrupt andOTP-file?") - - return data - - -class TOTP(): - class TOTPException(Exception): - def __init__(self, msg): - self.msg = msg - - def __str__(self): - return repr(self.msg) - - - def __init__(self, secret): - if not secret: - raise TOTP.TOTPException('Invalid secret') - self.secret = secret - - def generate(self): - try: - key = base64.b32decode(self.secret) - num = int(time.time()) // 30 - msg = struct.pack('>Q', num) - - # Take a SHA1 HMAC of key and binary-packed time value - digest = hmac.new(key, msg, hashlib.sha1).digest() - - # Last 4 bits of the digest tells which 4 bytes to use - offset = ord(digest[19]) & 15 - token_base = digest[offset : offset+4] - - # Unpack that into an integer and strip it down - token_val = struct.unpack('>I', token_base)[0] & 0x7fffffff - token_num = token_val % 1000000 - - # Pad with leading zeroes - token = '{0:06d}'.format(token_num) - - return token - except: - raise TOTP.TOTPException('Invalid secret') - - - -if __name__ == '__main__': - args = get_arguments() # Get args from cmdline - cfg = read_config(args) # Read from the cfg file - data = read_file(cfg) # Open the data file - - if not args.site: # Show a menu if no input - while True: - menu(data) - site = raw_input("Key #: ") - try: - site = int(site) - except: - print("Enter a number, not text.") - - if site > len(data): - raw_input("Incorrect menu choice, press Enter to try again") - else: - print_OTP(data[site-1]["secret"]) # -1 since index start with 0 and the menu with 1 - exit(0) - - for p in data: # Try to find a matching site - if p["label"].strip().lower() == args.site[0].lower(): - print_OTP(p["secret"]) - exit(0) - - - die("Could not find '%s' in the andOTP file" % args.site[0]) - - diff --git a/totp.py b/totp.py old mode 100644 new mode 100755 index be07e3d..d84858c --- a/totp.py +++ b/totp.py @@ -1,14 +1,93 @@ #!/usr/bin/env python - +# -*- coding: utf-8 -*- from __future__ import print_function +import argparse import base64 +import ConfigParser import hashlib import hmac +import json +import os import struct -import sys import time + +def die(reason): + # Terminate with an error message + print("Ecountered an error, terminating") + print("Error message -", reason) + exit(1) + + +def get_arguments(): + # Get input from the command line + parser = argparse.ArgumentParser() + parser.add_argument("site", nargs="*") + default_cfg_path = os.environ['HOME'] + '/.totprc' + parser.add_argument("-c", "--config", default=default_cfg_path, help='Path to config-file. Defaults to ~/.totprc') + + args = parser.parse_args() + return args + + +def menu(data): + # Print a pretty menu to choose from + keynum = 1 + print(" ---------------- Available keys ----------------") + print(" |") + for p in data: + print(" | %2d - %s" % (keynum, p["label"])) + keynum = keynum + 1 + + print(" |") + print(" ------------------------------------------------") + print(" | Please select which key to generate [1 - %d] |" % keynum) + print(" ------------------------------------------------") + print() + return keynum + + +def print_OTP(secret): + # Generate the key and pretty print it + value = TOTP(secret).generate() + # Format response like XXX XXX + print(value[:3], value[3:]) + + +def read_config(args): + # Read from the config file + config = ConfigParser.ConfigParser() + + try: + config.read(args.config) + except: + # Error in config file + die("Could not read %s" % args.config) + + # Verify that the config is correct + try: + config.get('totp', 'andOTPfile') + except: + die("Could not find path to 'andOTPfile' in %s" % args.config) + + if not os.path.isfile(config.get('totp', 'andOTPfile')): + die("The file %s does not exist" % config.get('totp', 'andOTPfile')) + + return config + + +def read_file(config): + # Open and parse the data file + try: + with open(config.get('totp', 'andOTPfile')) as filen: + data = json.load(filen) + except: + die("Error parsing JSON, corrupt andOTP-file?") + + return data + + class TOTP(): class TOTPException(Exception): def __init__(self, msg): @@ -48,22 +127,33 @@ class TOTP(): raise TOTP.TOTPException('Invalid secret') -def main(args): - if len(args): - token = sys.stdin.readline().strip() if args[0] == '-' else args[0] - elif not sys.stdin.isatty(): - token = sys.stdin.readline().strip() - else: - return 'Usage: totp ' - - try: - print(TOTP(token).generate()) - except TOTP.TOTPException as e: - return 'Error: ' + e.msg - if __name__ == '__main__': - try: - sys.exit(main(sys.argv[1:])) - except KeyboardInterrupt: - sys.exit(1) + args = get_arguments() # Get args from cmdline + cfg = read_config(args) # Read from the cfg file + data = read_file(cfg) # Open the data file + + if not args.site: # Show a menu if no input + while True: + menu(data) + site = raw_input("Key #: ") + try: + site = int(site) + except: + print("Enter a number, not text.") + + if site > len(data): + raw_input("Incorrect menu choice, press Enter to try again") + else: + print_OTP(data[site-1]["secret"]) # -1 since index start with 0 and the menu with 1 + exit(0) + + for p in data: # Try to find a matching site + if p["label"].strip().lower() == args.site[0].lower(): + print_OTP(p["secret"]) + exit(0) + + + die("Could not find '%s' in the andOTP file" % args.site[0]) + +