summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimeon Simeonov2026-04-16 17:14:23 +0200
committerSimeon Simeonov2026-04-16 17:14:23 +0200
commit3e4185913b584f5cc9a54f16f3c223861e11ec18 (patch)
tree33877fd0f3e34e13d911d98641227eb5d03fbb9d /src
parentbba82a86b137c73832ad7b6a397d3db24fcc625f (diff)
Introduce a new marco - %e and migrate the project from GitHub to Codeberg2.2.0
Diffstat (limited to 'src')
-rw-r--r--src/etoolkit/__init__.py6
-rw-r--r--src/etoolkit/__main__.py18
-rw-r--r--src/etoolkit/etoolkit.py19
3 files changed, 23 insertions, 20 deletions
diff --git a/src/etoolkit/__init__.py b/src/etoolkit/__init__.py
index 4cf5d6e..fc32b61 100644
--- a/src/etoolkit/__init__.py
+++ b/src/etoolkit/__init__.py
@@ -1,5 +1,5 @@
1# etoolkit 1# etoolkit
2# Copyright (C) 2021-2024 Simeon Simeonov 2# Copyright (C) 2021-2026 Simeon Simeonov
3 3
4# This program is free software: you can redistribute it and/or modify 4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -18,11 +18,11 @@
18from .etoolkit import EtoolkitInstance, EtoolkitInstanceError 18from .etoolkit import EtoolkitInstance, EtoolkitInstanceError
19 19
20__author__ = 'Simeon Simeonov' 20__author__ = 'Simeon Simeonov'
21__version__ = '2.1.0' 21__version__ = '2.2.0'
22__license__ = 'GPL3' 22__license__ = 'GPL3'
23 23
24 24
25def int_or_str(value): 25def int_or_str(value: int | str) -> int | str:
26 """Returns int value of value when possible""" 26 """Returns int value of value when possible"""
27 try: 27 try:
28 return int(value) 28 return int(value)
diff --git a/src/etoolkit/__main__.py b/src/etoolkit/__main__.py
index a2f2f20..cef3d42 100644
--- a/src/etoolkit/__main__.py
+++ b/src/etoolkit/__main__.py
@@ -1,5 +1,5 @@
1# etoolkit 1# etoolkit
2# Copyright (C) 2021-2024 Simeon Simeonov 2# Copyright (C) 2021-2026 Simeon Simeonov
3 3
4# This program is free software: you can redistribute it and/or modify 4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ class EtoolkitCLIHandler:
50 a part of the etoolkit API 50 a part of the etoolkit API
51 """ 51 """
52 52
53 def __init__(self, args: argparse.Namespace, config_dict: dict): 53 def __init__(self, args: argparse.Namespace, config_dict: dict) -> None:
54 """ 54 """
55 :param args: The parsed argparse arguments sent by the caller 55 :param args: The parsed argparse arguments sent by the caller
56 :type args: argparse.Namespace 56 :type args: argparse.Namespace
@@ -69,7 +69,7 @@ class EtoolkitCLIHandler:
69 69
70 self._password_from_env = os.environ.get('ETOOLKIT_MASTER_PASSWORD') 70 self._password_from_env = os.environ.get('ETOOLKIT_MASTER_PASSWORD')
71 71
72 def decrypt_value(self): 72 def decrypt_value(self) -> None:
73 """ 73 """
74 Interactive method for decrypting value(s) 74 Interactive method for decrypting value(s)
75 75
@@ -110,7 +110,7 @@ class EtoolkitCLIHandler:
110 break 110 break
111 return 111 return
112 112
113 def encrypt_value(self): 113 def encrypt_value(self) -> None:
114 """ 114 """
115 Interactive method for encrypting value(s) 115 Interactive method for encrypting value(s)
116 116
@@ -155,7 +155,7 @@ class EtoolkitCLIHandler:
155 break 155 break
156 return 156 return
157 157
158 def generate_master_password_hash(self): 158 def generate_master_password_hash(self) -> None:
159 """ 159 """
160 Interactive method for generating password hash 160 Interactive method for generating password hash
161 161
@@ -168,7 +168,7 @@ class EtoolkitCLIHandler:
168 ) 168 )
169 print(f'Master password hash: {phash}') 169 print(f'Master password hash: {phash}')
170 170
171 def list(self): 171 def list(self) -> None:
172 """Lists all instances defined in the config file""" 172 """Lists all instances defined in the config file"""
173 173
174 for instance_name in sorted( 174 for instance_name in sorted(
@@ -179,7 +179,7 @@ class EtoolkitCLIHandler:
179 ): 179 ):
180 print(instance_name) 180 print(instance_name)
181 181
182 def load_instance(self): 182 def load_instance(self) -> None:
183 """Loads a single specified instance from the config file""" 183 """Loads a single specified instance from the config file"""
184 184
185 inst = etoolkit.EtoolkitInstance( 185 inst = etoolkit.EtoolkitInstance(
@@ -208,7 +208,7 @@ class EtoolkitCLIHandler:
208 os.environ.get('SHELL', 'bash').split(), check=False 208 os.environ.get('SHELL', 'bash').split(), check=False
209 ) 209 )
210 210
211 def reencrypt(self): 211 def reencrypt(self) -> None:
212 """ 212 """
213 Interactive method that prints new configuration data (JSON) to stdout 213 Interactive method that prints new configuration data (JSON) to stdout
214 214
@@ -277,7 +277,7 @@ class EtoolkitCLIHandler:
277 ) 277 )
278 278
279 279
280def main(inargs=None): 280def main(inargs: list = None) -> None:
281 """main entry point""" 281 """main entry point"""
282 282
283 parser = argparse.ArgumentParser( 283 parser = argparse.ArgumentParser(
diff --git a/src/etoolkit/etoolkit.py b/src/etoolkit/etoolkit.py
index a933a01..f5ce2a6 100644
--- a/src/etoolkit/etoolkit.py
+++ b/src/etoolkit/etoolkit.py
@@ -1,5 +1,5 @@
1# etoolkit 1# etoolkit
2# Copyright (C) 2021-2024 Simeon Simeonov 2# Copyright (C) 2021-2026 Simeon Simeonov
3 3
4# This program is free software: you can redistribute it and/or modify 4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@ import base64
19import getpass 19import getpass
20import hashlib 20import hashlib
21import os 21import os
22from collections.abc import Callable
22 23
23from cryptography.exceptions import InvalidTag 24from cryptography.exceptions import InvalidTag
24from cryptography.hazmat.primitives.ciphers.aead import AESGCM 25from cryptography.hazmat.primitives.ciphers.aead import AESGCM
@@ -33,7 +34,7 @@ class EtoolkitInstanceError(Exception):
33class EtoolkitInstance: 34class EtoolkitInstance:
34 """A basic class representing a single instance""" 35 """A basic class representing a single instance"""
35 36
36 def __init__(self, name: str, data: dict): 37 def __init__(self, name: str, data: dict) -> None:
37 """ 38 """
38 :param name: Instance name 39 :param name: Instance name
39 :type name: str 40 :type name: str
@@ -76,14 +77,14 @@ class EtoolkitInstance:
76 ] 77 ]
77 78
78 @property 79 @property
79 def master_password(self) -> str: 80 def master_password(self) -> str | None:
80 """master_password-property""" 81 """master_password-property"""
81 if self._master_password is not None: 82 if self._master_password is not None:
82 return self._master_password 83 return self._master_password
83 return None if self._parent is None else self._parent.master_password 84 return None if self._parent is None else self._parent.master_password
84 85
85 @master_password.setter 86 @master_password.setter
86 def master_password(self, value): 87 def master_password(self, value: str) -> None:
87 """master_password-property setter""" 88 """master_password-property setter"""
88 self._master_password = value 89 self._master_password = value
89 if self._parent is not None and self._parent.master_password is None: 90 if self._parent is not None and self._parent.master_password is None:
@@ -95,7 +96,7 @@ class EtoolkitInstance:
95 return self._master_password_hash 96 return self._master_password_hash
96 97
97 @master_password_hash.setter 98 @master_password_hash.setter
98 def master_password_hash(self, value): 99 def master_password_hash(self, value: str) -> None:
99 """master_password_hash-property setter""" 100 """master_password_hash-property setter"""
100 self._master_password_hash = value 101 self._master_password_hash = value
101 102
@@ -105,12 +106,12 @@ class EtoolkitInstance:
105 return self._name 106 return self._name
106 107
107 @property 108 @property
108 def prompt_func(self): 109 def prompt_func(self) -> Callable[[str, bool], str]:
109 """prompt_func-property""" 110 """prompt_func-property"""
110 return self._prompt_func 111 return self._prompt_func
111 112
112 @prompt_func.setter 113 @prompt_func.setter
113 def prompt_func(self, value): 114 def prompt_func(self, value: Callable[[str, bool], str]) -> None:
114 """prompt_func-property setter""" 115 """prompt_func-property setter"""
115 self._prompt_func = value 116 self._prompt_func = value
116 if self._parent is not None and self._parent.prompt_func is None: 117 if self._parent is not None and self._parent.prompt_func is None:
@@ -294,7 +295,7 @@ class EtoolkitInstance:
294 ) 295 )
295 296
296 @staticmethod 297 @staticmethod
297 def parse_value(value, macros: dict): 298 def parse_value(value: object, macros: dict) -> object:
298 """ 299 """
299 Returns the value with all macros replaced by their values 300 Returns the value with all macros replaced by their values
300 301
@@ -412,6 +413,8 @@ class EtoolkitInstance:
412 if not value: 413 if not value:
413 # perhaps unset instead of skipping? 414 # perhaps unset instead of skipping?
414 continue 415 continue
416 if isinstance(value, str) and '%e' in value:
417 macros['%e'] = os.environ.get(key, '')
415 if isinstance(value, str) and '%p' in value: 418 if isinstance(value, str) and '%p' in value:
416 macros['%p'] = ( 419 macros['%p'] = (
417 self._parent.get_environ().get(key, '') 420 self._parent.get_environ().get(key, '')