Skip to content

Commit

Permalink
Merge pull request #44 from jan-janssen/pyotp
Browse files Browse the repository at this point in the history
Switch from otpauth to pyotp
  • Loading branch information
jan-janssen authored Jul 4, 2023
2 parents 35bafd9 + 88ab87f commit 5384afc
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 107 deletions.
2 changes: 1 addition & 1 deletion .binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ channels:
dependencies:
- python
- qrcode
- otpauth
- pyotp
- pyzbar
- zbar
- pillow
2 changes: 1 addition & 1 deletion .ci_support/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dependencies:
- python
- coverage
- qrcode=7.4.2
- otpauth=2.0.0
- pyotp=2.6.0
- pyzbar=0.1.9
- zbar=0.10
- pillow=10.0.0
8 changes: 3 additions & 5 deletions pyauthenticator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
"""
Generate two factor authentication codes on the command line
"""
from pyauthenticator.share import (
load_config,
generate_qrcode,
get_two_factor_code as get_two_factor_code_internal,
)
from pyauthenticator.share import generate_qrcode
from pyauthenticator.share import get_two_factor_code as get_two_factor_code_internal
from pyauthenticator.share import load_config


def write_qrcode_to_file(service, file_name=None):
Expand Down
7 changes: 4 additions & 3 deletions pyauthenticator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
"""
import argparse
import sys

from pyauthenticator.share import (
list_services,
load_config,
generate_qrcode,
add_service,
generate_qrcode,
get_two_factor_code,
list_services,
load_config,
)


Expand Down
76 changes: 21 additions & 55 deletions pyauthenticator/share.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""
Shared functionality to generate two factor authentication codes
"""
import base64
import json
import os
import otpauth
from inspect import signature

import pyotp
import qrcode
from PIL import Image
from pyzbar.pyzbar import decode
import qrcode


# default configuration file
config_file = "~/.pyauthenticator"
Expand Down Expand Up @@ -75,28 +75,6 @@ def get_otpauth_dict(otpauth_str):
}


def add_padding(main_str, padding_str, padding_length, inverse_padding=False):
"""
Add padding to a string either in the beginning or at the end
Args:
main_str (str): string to add padding to
padding_str (str): padding character as string
padding_length (int): the length of the final string should be a multiple of the padding length
inverse_padding (bool): add padding in the beginning rather than the end
Returns:
str: resulting string with padding
"""
missing_padding = len(main_str) % padding_length
if missing_padding:
if inverse_padding:
main_str = padding_str * (padding_length - missing_padding) + main_str
else:
main_str += padding_str * (padding_length - missing_padding)
return main_str


def check_if_key_in_config(key, config_dict):
"""
Check if a given key is included in a dictionary, raise an ValueError if it is not.
Expand All @@ -122,37 +100,25 @@ def get_two_factor_code(key, config_dict):
"""
check_if_key_in_config(key=key, config_dict=config_dict)
decode_dict_internal = get_otpauth_dict(otpauth_str=config_dict[key])
funct_sig = signature(pyotp.TOTP)
if "digits" in decode_dict_internal.keys():
digits = int(decode_dict_internal["digits"])
else:
digits = funct_sig.parameters["digits"].default
if "period" in decode_dict_internal.keys():
totp = otpauth.TOTP(
secret=base64.b32decode(
add_padding(
main_str=decode_dict_internal["secret"],
padding_str="=",
padding_length=8,
inverse_padding=False,
),
True,
),
period=int(decode_dict_internal["period"]),
)
interval = int(decode_dict_internal["period"])
else:
interval = funct_sig.parameters["interval"].default
if "issuer" in decode_dict_internal.keys():
issuer = decode_dict_internal["issuer"]
else:
totp = otpauth.TOTP(
secret=base64.b32decode(
add_padding(
main_str=decode_dict_internal["secret"],
padding_str="=",
padding_length=8,
inverse_padding=False,
),
True,
),
)
return add_padding(
main_str=str(totp.string_code(totp.generate())),
padding_str="0",
padding_length=6,
inverse_padding=True,
)
issuer = funct_sig.parameters["issuer"].default
return pyotp.TOTP(
s=decode_dict_internal["secret"],
digits=digits,
issuer=issuer,
interval=interval,
).now()


def add_service(
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
Setuptools based setup module
"""
from setuptools import setup, find_packages
import versioneer
from setuptools import find_packages, setup

import versioneer

setup(
name='pyauthenticator',
Expand All @@ -17,7 +17,7 @@
license='BSD',
packages=find_packages(exclude=["*tests*"]),
install_requires=[
'otpauth==2.0.0',
'pyotp==2.6.0',
'qrcode==7.4.2',
'pyzbar==0.1.9',
'pillow==10.0.0',
Expand Down
7 changes: 4 additions & 3 deletions tests/test_cmd.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import unittest
import json
import os
import subprocess
import json
import unittest
from contextlib import redirect_stdout
from io import StringIO
from pyauthenticator.share import expand_path, write_config, config_file

from pyauthenticator.__main__ import command_line_parser
from pyauthenticator.share import config_file, expand_path, write_config


class CmdSubprocessTest(unittest.TestCase):
Expand Down
11 changes: 9 additions & 2 deletions tests/test_core.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
"""
Test for core functionality
"""
import unittest
from pyauthenticator.share import list_services, load_config, generate_qrcode, add_service, get_two_factor_code
import os
import unittest

from pyauthenticator.share import (
add_service,
generate_qrcode,
get_two_factor_code,
list_services,
load_config
)


class TestCore(unittest.TestCase):
Expand Down
41 changes: 9 additions & 32 deletions tests/test_share.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"""
Test for shared functionality
"""
import unittest
import os
from pyauthenticator.share import \
expand_path, \
load_config, \
write_config, \
get_otpauth_dict, \
add_padding, \
check_if_key_in_config
import unittest

from pyauthenticator.share import (
check_if_key_in_config,
expand_path,
get_otpauth_dict,
load_config,
write_config
)


class ShareTest(unittest.TestCase):
Expand Down Expand Up @@ -52,30 +53,6 @@ def test_get_otpauth_dict(self):
}
self.assertDictEqual(otpauth_dict, otp_test_dict)

def test_add_padding(self):
main_str = "1234"
padding_str = "0"
str_pad_0 = add_padding(
main_str=main_str,
padding_str=padding_str,
padding_length=5
)
str_pad_1 = add_padding(
main_str=main_str,
padding_str=padding_str,
padding_length=6,
inverse_padding=True
)
str_pad_2 = add_padding(
main_str=main_str,
padding_str=padding_str,
padding_length=7,
inverse_padding=False
)
self.assertEqual("12340", str_pad_0)
self.assertEqual("001234", str_pad_1)
self.assertEqual("1234000", str_pad_2)

def test_check_if_key_in_config(self):
test_dict = {"key": "value"}
check_if_key_in_config(
Expand Down
5 changes: 3 additions & 2 deletions tests/test_user_interface.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import unittest
import os
import unittest

from pyauthenticator import get_two_factor_code, write_qrcode_to_file
from pyauthenticator.share import expand_path, write_config, config_file
from pyauthenticator.share import config_file, expand_path, write_config


class TestUserInterface(unittest.TestCase):
Expand Down

0 comments on commit 5384afc

Please sign in to comment.