Add initial structure implementation

This commit is contained in:
Ethan Paul 2023-03-30 23:22:28 -04:00
parent e905ab2374
commit 5abb98af1d
Signed by: enpaul
GPG Key ID: 07F53B438281D181

View File

@ -1,4 +1,12 @@
"""Python library bindings for the Spectre password manager""" """Python library bindings for the Spectre password manager"""
import enum
import shutil
import subprocess
from dataclasses import dataclass
from pathlib import Path
from typing import Optional
from typing import Union
__title__ = "spectrepy" __title__ = "spectrepy"
__summary__ = "Python bindings for the Spectre Password Manager" __summary__ = "Python bindings for the Spectre Password Manager"
@ -6,3 +14,106 @@ __version__ = "0.1.0"
__url__ = "https://github.com/enpaul/spectrepy/" __url__ = "https://github.com/enpaul/spectrepy/"
__license__ = "MIT" __license__ = "MIT"
__authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"] __authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
__all__ = [
"__title__",
"__summary__",
"__version__",
"__url__",
"__license__",
"__authors__",
"SpectrePasswordType",
"SpectreAlgorithmVersion",
"SpectrePassword",
"Spectre",
"generate",
"get_version",
]
class SpectrePasswordType(enum.Enum):
X = "maximum"
L = "long"
M = "medium"
B = "basic"
S = "short"
I = "pin"
N = "name"
P = "phrase"
K = "key"
class SpectreAlgorithmVersion(enum.Enum):
V0 = 0
V1 = 1
V2 = 2
V3 = 3
@dataclass(frozen=True)
class SpectrePassword:
site: str
identicon: str
password_type: SpectrePasswordType
username: str
algorithm_version: SpectreAlgorithmVersion
context: str
def generate(*args, **kwargs) -> SpectrePassword:
return Spectre(*args, **kwargs).generate()
def get_version(*args, **kwargs) -> str:
return Spectre(*args, **kwargs).version
def get_path(*args, **kwargs) -> Path:
return Spectre(*args, **kwargs).path
class Spectre:
def __init__(self, binary: Optional[Union[str, Path]] = None):
self._path: Path
self._version: str
self._path = (
Path(binary).resolve() if binary is not None else self._find_binary()
)
self._version = self._fetch_version()
@property
def version(self) -> str:
return self._version
@property
def program(self) -> str:
return self._program
@property
def path(self) -> Path:
return self._path
@staticmethod
def _find_binary() -> Path:
binary = shutil.which("spectre") or shutil.which("mpw")
if not binary:
raise RuntimeError
return Path(binary)
def generate(self) -> SpectrePassword:
pass
def _call(self, *args, raise_errors: bool = True) -> subprocess.CompletedProcess:
result = subprocess.run([str(self._path)] + [*args], capture_output=True)
if result.returncode != 0 and raise_errors:
raise RuntimeError
return result
def _fetch_version(self) -> str:
out = self._call("-h")
raw = out.stderr.decode().split("\n")[0].strip().split(" ")
version = raw[-1]
return version