pyauthenticator 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,35 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pyauthenticator
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Similar to the Google authenticator just written in python.
5
- Home-page: https://github.com/jan-janssen/pyauthenticator
6
- Author: Jan Janssen
7
- Author-email: jan.janssen@outlook.com
8
- License: BSD
9
- Description-Content-Type: text/markdown
5
+ Project-URL: Homepage, https://github.com/jan-janssen/pyauthenticator
6
+ Project-URL: Documentation, https://github.com/jan-janssen/pyauthenticator/blob/master/README.md
7
+ Project-URL: Source, https://github.com/jan-janssen/pyauthenticator
8
+ Project-URL: Tracker, https://github.com/jan-janssen/pyauthenticator/issues
9
+ Author-email: Jan Janssen <jan.janssen@outlook.com>
10
+ License: BSD-3-Clause
10
11
  License-File: LICENSE
12
+ Keywords: 2FA,MFA,authenticator
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.7
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Topic :: Security
26
+ Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.7
28
+ Requires-Dist: pillow>=11.3.0
29
+ Requires-Dist: pyotp>=2.9.0
30
+ Requires-Dist: pyzbar>=0.1.9
31
+ Requires-Dist: qrcode>=8.2
32
+ Description-Content-Type: text/markdown
11
33
 
12
34
  # pyauthenticator
13
35
  [![Python package](https://github.com/jan-janssen/pyauthenticator/actions/workflows/unittest.yml/badge.svg?branch=main)](https://github.com/jan-janssen/pyauthenticator/actions/workflows/unittest.yml)
@@ -101,4 +123,4 @@ the config file contains:
101
123
  With the Google username `<username>` and the corresponding secret `<secret>` being contained in the QR code.
102
124
 
103
125
  ## License
104
- The `pyauthenticator` package is licensed under the [BSD-3-Clause license](https://github.com/jan-janssen/pyauthenticator/blob/main/LICENSE).
126
+ The `pyauthenticator` package is licensed under the [BSD-3-Clause license](https://github.com/jan-janssen/pyauthenticator/blob/main/LICENSE).
@@ -1,10 +1,14 @@
1
1
  """
2
2
  Generate two factor authentication codes on the command line
3
3
  """
4
+
5
+ from . import _version
4
6
  from pyauthenticator.share import generate_qrcode
5
7
  from pyauthenticator.share import get_two_factor_code as get_two_factor_code_internal
6
8
  from pyauthenticator.share import load_config
7
9
 
10
+ __version__ = _version.__version__
11
+
8
12
 
9
13
  def write_qrcode_to_file(service, file_name=None):
10
14
  """
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Generate two factor authentication codes on the command line
3
3
  """
4
+
4
5
  import argparse
5
6
  import sys
6
7
 
@@ -0,0 +1,21 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
6
+ TYPE_CHECKING = False
7
+ if TYPE_CHECKING:
8
+ from typing import Tuple
9
+ from typing import Union
10
+
11
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
12
+ else:
13
+ VERSION_TUPLE = object
14
+
15
+ version: str
16
+ __version__: str
17
+ __version_tuple__: VERSION_TUPLE
18
+ version_tuple: VERSION_TUPLE
19
+
20
+ __version__ = version = '0.2.1'
21
+ __version_tuple__ = version_tuple = (0, 2, 1)
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Shared functionality to generate two factor authentication codes
3
3
  """
4
+
4
5
  import json
5
6
  import os
6
7
  from inspect import signature
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = [
3
+ "hatchling>=1.27.0",
4
+ "hatch-vcs>=0.5.0",
5
+ "pyotp>=2.9.0",
6
+ "qrcode>=8.2",
7
+ "pyzbar>=0.1.9",
8
+ "pillow>=11.3.0",
9
+ ]
10
+ build-backend = "hatchling.build"
11
+
12
+ [project]
13
+ name = "pyauthenticator"
14
+ dynamic = ["version"]
15
+ description = "Similar to the Google authenticator just written in python."
16
+ readme = "README.md"
17
+ requires-python = ">=3.7"
18
+ license = { text = "BSD-3-Clause" }
19
+ authors = [
20
+ { name = "Jan Janssen", email = "jan.janssen@outlook.com" },
21
+ ]
22
+ keywords = ["authenticator", "2FA", "MFA"]
23
+ classifiers = [
24
+ "Development Status :: 5 - Production/Stable",
25
+ "Intended Audience :: Developers",
26
+ "License :: OSI Approved :: BSD License",
27
+ "Operating System :: OS Independent",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.7",
30
+ "Programming Language :: Python :: 3.8",
31
+ "Programming Language :: Python :: 3.9",
32
+ "Programming Language :: Python :: 3.10",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Topic :: Security",
37
+ "Topic :: Utilities",
38
+ ]
39
+ dependencies = [
40
+ "pyotp>=2.9.0",
41
+ "qrcode>=8.2",
42
+ "pyzbar>=0.1.9",
43
+ "pillow>=11.3.0",
44
+ ]
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/jan-janssen/pyauthenticator"
48
+ Documentation = "https://github.com/jan-janssen/pyauthenticator/blob/master/README.md"
49
+ Source = "https://github.com/jan-janssen/pyauthenticator"
50
+ Tracker = "https://github.com/jan-janssen/pyauthenticator/issues"
51
+
52
+ [project.scripts]
53
+ pyauthenticator = "pyauthenticator.__main__:command_line_parser"
54
+
55
+ [tool.hatch.build]
56
+ include = [
57
+ "pyauthenticator"
58
+ ]
59
+
60
+ [tool.hatch.build.hooks.vcs]
61
+ version-file = "pyauthenticator/_version.py"
62
+
63
+ [tool.hatch.build.targets.sdist]
64
+ include = [
65
+ "pyauthenticator"
66
+ ]
67
+
68
+ [tool.hatch.build.targets.wheel]
69
+ packages = [
70
+ "pyauthenticator"
71
+ ]
72
+
73
+ [tool.hatch.version]
74
+ source = "vcs"
75
+ path = "pyauthenticator/_version.py"
@@ -1,3 +0,0 @@
1
- include LICENSE
2
- include versioneer.py
3
- include pyauthenticator/_version.py
@@ -1,104 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: pyauthenticator
3
- Version: 0.2.0
4
- Summary: Similar to the Google authenticator just written in python.
5
- Home-page: https://github.com/jan-janssen/pyauthenticator
6
- Author: Jan Janssen
7
- Author-email: jan.janssen@outlook.com
8
- License: BSD
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
-
12
- # pyauthenticator
13
- [![Python package](https://github.com/jan-janssen/pyauthenticator/actions/workflows/unittest.yml/badge.svg?branch=main)](https://github.com/jan-janssen/pyauthenticator/actions/workflows/unittest.yml)
14
- [![Coverage Status](https://coveralls.io/repos/github/jan-janssen/pyauthenticator/badge.svg?branch=main)](https://coveralls.io/github/jan-janssen/pyauthenticator?branch=main)
15
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
16
-
17
- Similar to the Google authenticator just written in Python. With more and more services requiring two factor
18
- authentication without supporting application specific passwords or other forms of token based authenication
19
- suitable for automation this python packages allows to generate two factor authentication codes on the commandline
20
- or in python.
21
-
22
- ![Preview of pyauthenticator](https://raw.githubusercontent.com/jan-janssen/pyauthenticator/main/pyauthenticator.gif)
23
-
24
- # For Users
25
- ## Installation
26
- Install `pyauthenticator` via conda:
27
- ```
28
- >>> conda install -c conda-forge pyauthenticator
29
- ```
30
-
31
- Alternatively, `pyauthenticator` can also be installed via pip:
32
- ```
33
- >>> pip install pyauthenticator
34
- ```
35
-
36
- ## Command Line
37
- Get help how to use `pyauthenticator` using the `--help/-h` option:
38
- ```
39
- >>> pyauthenticator --help
40
-
41
- usage: pyauthenticator [-h] [-qr] [-a ADD] service
42
-
43
- positional arguments:
44
- service Service to generate optauth code for. Currently no
45
- service is defined in the ~/.pyauthenticator config file.
46
-
47
- options:
48
- -h, --help show this help message and exit
49
- -qr, --qrcode Generate qrcode as <service.png> file.
50
- -a ADD, --add ADD Add service by providing the <qrcode.png> file as
51
- additional argument.
52
- ```
53
-
54
- Add `google` as new service after saving the qrcode to `Screenshot 2023-07-02 at 12.45.09.png` to your desktop:
55
- ```
56
- >>> pyauthenticator google --add ~/Desktop/Screenshot\ 2023-07-02\ at\ 12.45.09.png
57
-
58
- The service 'google' was added, from file </Users/jan/Desktop/Screenshot 2023-07-02 at 12.45.09.png>
59
- ```
60
-
61
- Afterwards, new authentication codes can be generated for the service `google` using:
62
- ```
63
- >>> pyauthenticator google
64
-
65
- 087078
66
- ```
67
- Beyond google, `pyauthenticator` works for any service which implements the two factor authentication.
68
-
69
- If you mistype the name of the service, then `pyauthenticator` suggests alternative options:
70
- ```
71
- >>> pyauthenticator googel
72
-
73
- The service "googel" does not exist.
74
-
75
- The config file ~/.pyauthenticator contains the following services:
76
- * google
77
-
78
- Choose one of these or add a new service using:
79
- pyauthenticator --add <qr-code.png> <servicename>
80
- ```
81
-
82
- ## Support
83
- For any support requests feel free to open an [issue on Github](https://github.com/jan-janssen/pyauthenticator/issues).
84
-
85
- # For Developers
86
- ## Python Interface
87
- The same functionality which is available on the command line is also available via the python interface:
88
- ```
89
- from pyauthenticator import get_two_factor_code
90
- get_two_factor_code(service)
91
- ```
92
- So `pyauthenticator` can be integrated in existing python packages which need access to resources protected by two
93
- factor authentication.
94
-
95
- ## Configuration
96
- The configuration is stored in `~/.pyauthenticator` it is written in the JSON format. For a given service like `github`
97
- the config file contains:
98
- ```
99
- {"google": "otpauth://totp/Google:<username>?secret=<secret>&issuer=Google"}
100
- ```
101
- With the Google username `<username>` and the corresponding secret `<secret>` being contained in the QR code.
102
-
103
- ## License
104
- The `pyauthenticator` package is licensed under the [BSD-3-Clause license](https://github.com/jan-janssen/pyauthenticator/blob/main/LICENSE).
@@ -1,21 +0,0 @@
1
-
2
- # This file was generated by 'versioneer.py' (0.18) from
3
- # revision-control system data, or from the parent directory name of an
4
- # unpacked source archive. Distribution tarballs contain a pre-generated copy
5
- # of this file.
6
-
7
- import json
8
-
9
- version_json = '''
10
- {
11
- "date": "2023-07-04T11:40:53-0600",
12
- "dirty": true,
13
- "error": null,
14
- "full-revisionid": "5384afcb4644572f4d8fd4e2f0900fb6c625aa20",
15
- "version": "0.2.0"
16
- }
17
- ''' # END VERSION_JSON
18
-
19
-
20
- def get_versions():
21
- return json.loads(version_json)
@@ -1,20 +0,0 @@
1
- LICENSE
2
- MANIFEST.in
3
- README.md
4
- setup.cfg
5
- setup.py
6
- versioneer.py
7
- pyauthenticator/__init__.py
8
- pyauthenticator/__main__.py
9
- pyauthenticator/_version.py
10
- pyauthenticator/share.py
11
- pyauthenticator.egg-info/PKG-INFO
12
- pyauthenticator.egg-info/SOURCES.txt
13
- pyauthenticator.egg-info/dependency_links.txt
14
- pyauthenticator.egg-info/entry_points.txt
15
- pyauthenticator.egg-info/requires.txt
16
- pyauthenticator.egg-info/top_level.txt
17
- tests/test_cmd.py
18
- tests/test_core.py
19
- tests/test_share.py
20
- tests/test_user_interface.py
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- pyauthenticator = pyauthenticator.__main__:command_line_parser
@@ -1,4 +0,0 @@
1
- pyotp>=2.6.0
2
- qrcode>=7.4.2
3
- pyzbar>=0.1.9
4
- pillow>=10.0.0
@@ -1 +0,0 @@
1
- pyauthenticator
@@ -1,11 +0,0 @@
1
- [versioneer]
2
- VCS = git
3
- style = pep440-pre
4
- versionfile_source = pyauthenticator/_version.py
5
- tag_prefix = pyauthenticator-
6
- parentdir_prefix = pyauthenticator
7
-
8
- [egg_info]
9
- tag_build =
10
- tag_date = 0
11
-
@@ -1,31 +0,0 @@
1
- """
2
- Setuptools based setup module
3
- """
4
- from setuptools import find_packages, setup
5
-
6
- import versioneer
7
-
8
- setup(
9
- name='pyauthenticator',
10
- version=versioneer.get_version(),
11
- description='Similar to the Google authenticator just written in python.',
12
- long_description=open('README.md').read(),
13
- long_description_content_type="text/markdown",
14
- url='https://github.com/jan-janssen/pyauthenticator',
15
- author='Jan Janssen',
16
- author_email='jan.janssen@outlook.com',
17
- license='BSD',
18
- packages=find_packages(exclude=["*tests*"]),
19
- install_requires=[
20
- 'pyotp>=2.6.0',
21
- 'qrcode>=7.4.2',
22
- 'pyzbar>=0.1.9',
23
- 'pillow>=10.0.0',
24
- ],
25
- cmdclass=versioneer.get_cmdclass(),
26
- entry_points={
27
- "console_scripts": [
28
- 'pyauthenticator=pyauthenticator.__main__:command_line_parser'
29
- ]
30
- }
31
- )
@@ -1,89 +0,0 @@
1
- import json
2
- import os
3
- import subprocess
4
- import unittest
5
- from contextlib import redirect_stdout
6
- from io import StringIO
7
-
8
- from pyauthenticator.__main__ import command_line_parser
9
- from pyauthenticator.share import config_file, expand_path, write_config
10
-
11
-
12
- class CmdSubprocessTest(unittest.TestCase):
13
- @classmethod
14
- def setUpClass(cls):
15
- cls.config_dict = {
16
- "test": "otpauth://totp/Test%3A%20root%40github.com?secret=6IQXETC4ADOSMMUN&issuer=Test"
17
- }
18
- cls.config_path = expand_path(config_file)
19
- if not os.path.exists(cls.config_path):
20
- write_config(
21
- config_dict=cls.config_dict
22
- )
23
-
24
- def test_main_generate_two_factor(self):
25
- code = subprocess.check_output(
26
- ["coverage", "run", "-a", "pyauthenticator", "test"],
27
- universal_newlines=True
28
- )
29
- self.assertEqual(len(code.replace("\n", "")), 6)
30
-
31
- def test_main_generate_qr_code(self):
32
- subprocess.check_output(
33
- ["coverage", "run", "-a", "pyauthenticator", "-qr", "test"],
34
- universal_newlines=True
35
- )
36
- self.assertTrue(os.path.exists("test.png"))
37
- subprocess.check_output(
38
- ["coverage", "run", "-a", "pyauthenticator", "-a", "test.png", "test2"],
39
- universal_newlines=True
40
- )
41
- with open(self.config_path, "r") as f:
42
- config_dict = json.load(f)
43
- self.assertTrue("test2" in config_dict.keys())
44
-
45
-
46
- class CmdParserTest(unittest.TestCase):
47
- @classmethod
48
- def setUpClass(cls):
49
- cls.config_dict = {
50
- "test": "otpauth://totp/Test%3A%20root%40github.com?secret=6IQXETC4ADOSMMUN&issuer=Test"
51
- }
52
- cls.config_path = expand_path(config_file)
53
- if not os.path.exists(cls.config_path):
54
- write_config(
55
- config_dict=cls.config_dict
56
- )
57
-
58
- def test_main_generate_two_factor(self):
59
- with redirect_stdout(StringIO()) as sout:
60
- command_line_parser(cmd_args=["test"])
61
- self.assertEqual(len(sout.getvalue().rstrip('\n')), 6)
62
- with redirect_stdout(StringIO()) as sout:
63
- command_line_parser(cmd_args=["test3"])
64
- self.assertEqual(
65
- sout.getvalue().split("\n")[0],
66
- "The service \"test3\" does not exist."
67
- )
68
-
69
- def test_main_generate_qr_code(self):
70
- with redirect_stdout(StringIO()) as sout:
71
- command_line_parser(cmd_args=["-qr", "test"])
72
- self.assertEqual(
73
- sout.getvalue(),
74
- "The qrcode file <test.png> was generated.\n"
75
- )
76
- self.assertTrue(os.path.exists("test.png"))
77
- with redirect_stdout(StringIO()) as sout:
78
- command_line_parser(cmd_args=["-a", "test.png", "test4"])
79
- self.assertEqual(
80
- sout.getvalue(),
81
- "The service 'test4' was added, from file <test.png>.\n"
82
- )
83
- with open(self.config_path, "r") as f:
84
- config_dict = json.load(f)
85
- self.assertTrue("test4" in config_dict.keys())
86
-
87
-
88
- if __name__ == '__main__':
89
- unittest.main()
@@ -1,55 +0,0 @@
1
- """
2
- Test for core functionality
3
- """
4
- import os
5
- import unittest
6
-
7
- from pyauthenticator.share import (
8
- add_service,
9
- generate_qrcode,
10
- get_two_factor_code,
11
- list_services,
12
- load_config
13
- )
14
-
15
-
16
- class TestCore(unittest.TestCase):
17
- @classmethod
18
- def setUpClass(cls):
19
- cls.qr_code_png = "test.png"
20
- cls.config_dict = {
21
- "test": "otpauth://totp/Test%3A%20root%40github.com?secret=6IQXETC4ADOSMMUN&issuer=Test&period=60"
22
- }
23
- generate_qrcode(
24
- key="test",
25
- config_dict=cls.config_dict,
26
- file_name=None
27
- )
28
-
29
- @classmethod
30
- def tearDownClass(cls):
31
- os.remove(cls.qr_code_png)
32
-
33
- def test_list_services(self):
34
- service_lst = list_services(config_dict=self.config_dict)
35
- self.assertEqual(["test"], service_lst)
36
-
37
- def test_add_service(self):
38
- config_file = "test_config.json"
39
- add_service(
40
- key="test",
41
- qrcode_png_file_name=self.qr_code_png,
42
- config_dict={},
43
- config_file_to_write=config_file
44
- )
45
- config_reload = load_config(config_file_to_load=config_file)
46
- self.assertDictEqual(config_reload, self.config_dict)
47
- os.remove(config_file)
48
-
49
- def test_get_two_factor_code(self):
50
- code = get_two_factor_code(key="test", config_dict=self.config_dict)
51
- self.assertEqual(len(code), 6)
52
-
53
-
54
- if __name__ == '__main__':
55
- unittest.main()
@@ -1,70 +0,0 @@
1
- """
2
- Test for shared functionality
3
- """
4
- import os
5
- import unittest
6
-
7
- from pyauthenticator.share import (
8
- check_if_key_in_config,
9
- expand_path,
10
- get_otpauth_dict,
11
- load_config,
12
- write_config
13
- )
14
-
15
-
16
- class ShareTest(unittest.TestCase):
17
- def test_expand_path(self):
18
- test_path = "~/.pyauthenticator"
19
- self.assertEqual(
20
- expand_path(path=test_path),
21
- os.path.abspath(
22
- os.path.expanduser(
23
- test_path
24
- )
25
- )
26
- )
27
-
28
- def test_config(self):
29
- test_file_name = "test.json"
30
- test_dict = {"key": "value"}
31
- write_config(
32
- config_dict=test_dict,
33
- config_file_to_write=test_file_name
34
- )
35
- test_dict_reload = load_config(
36
- config_file_to_load=test_file_name
37
- )
38
- self.assertDictEqual(test_dict, test_dict_reload)
39
- test_no_dict = load_config(
40
- config_file_to_load="no.json"
41
- )
42
- self.assertDictEqual(test_no_dict, {})
43
- os.remove(test_file_name)
44
-
45
- def test_get_otpauth_dict(self):
46
- otpauth_str = "otpauth://totp/Test%3A%20root%40github.com?secret=MAGICSECRET&issuer=Test"
47
- otpauth_dict = get_otpauth_dict(
48
- otpauth_str=otpauth_str
49
- )
50
- otp_test_dict = {
51
- 'secret': 'MAGICSECRET',
52
- 'issuer': 'Test'
53
- }
54
- self.assertDictEqual(otpauth_dict, otp_test_dict)
55
-
56
- def test_check_if_key_in_config(self):
57
- test_dict = {"key": "value"}
58
- check_if_key_in_config(
59
- key="key",
60
- config_dict=test_dict
61
- )
62
- with self.assertRaises(ValueError):
63
- check_if_key_in_config(
64
- key="secret",
65
- config_dict=test_dict
66
- )
67
-
68
-
69
- if __name__ == '__main__':
70
- unittest.main()
@@ -1,30 +0,0 @@
1
- import os
2
- import unittest
3
-
4
- from pyauthenticator import get_two_factor_code, write_qrcode_to_file
5
- from pyauthenticator.share import config_file, expand_path, write_config
6
-
7
-
8
- class TestUserInterface(unittest.TestCase):
9
- @classmethod
10
- def setUpClass(cls):
11
- cls.config_dict = {
12
- "test": "otpauth://totp/Test%3A%20root%40github.com?secret=6IQXETC4ADOSMMUN&issuer=Test"
13
- }
14
- cls.config_path = expand_path(config_file)
15
- if not os.path.exists(cls.config_path):
16
- write_config(
17
- config_dict=cls.config_dict
18
- )
19
-
20
- def test_get_two_factor_code(self):
21
- code = get_two_factor_code(service="test")
22
- self.assertEqual(len(code), 6)
23
-
24
- def test_write_qrcode_to_file(self):
25
- write_qrcode_to_file(service="test")
26
- self.assertTrue(os.path.exists("test.png"))
27
-
28
-
29
- if __name__ == '__main__':
30
- unittest.main()