Merge pull request 'pass_context' (#10) from pass_context into develop
Reviewed-on: https://hattori.ztsh.eu/paas/karl/pulls/10
This commit is contained in:
commit
8cf4f719b5
10 changed files with 24 additions and 26 deletions
|
|
@ -10,6 +10,7 @@ class Request:
|
||||||
started: str
|
started: str
|
||||||
files: List[str]
|
files: List[str]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Response:
|
class Response:
|
||||||
status: int
|
status: int
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
# TODO: unnecessary?
|
# TODO: unnecessary?
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -8,6 +9,7 @@ class PathItem:
|
||||||
name: str
|
name: str
|
||||||
t: Type
|
t: Type
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Path:
|
class Path:
|
||||||
path: list[PathItem] = field(default_factory=list)
|
path: list[PathItem] = field(default_factory=list)
|
||||||
|
|
@ -43,6 +45,7 @@ class Password:
|
||||||
def path(self):
|
def path(self):
|
||||||
return self.group.path.append(self.name, type(self))
|
return self.group.path.append(self.name, type(self))
|
||||||
|
|
||||||
|
|
||||||
class UnencryptedPassword(Password):
|
class UnencryptedPassword(Password):
|
||||||
def __init__(self, name: str, value: str, group: Group):
|
def __init__(self, name: str, value: str, group: Group):
|
||||||
super().__init__(name, group)
|
super().__init__(name, group)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WoodpeckerEvent:
|
class WoodpeckerEvent:
|
||||||
_id: str
|
_id: str
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,3 @@ class DockerService:
|
||||||
def reload(self, compose_path: Path):
|
def reload(self, compose_path: Path):
|
||||||
cmd = ["sudo", "docker", "compose", "-f", str(compose_path), "up", "-d"]
|
cmd = ["sudo", "docker", "compose", "-f", str(compose_path), "up", "-d"]
|
||||||
# TODO: subprocess
|
# TODO: subprocess
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class SimpleValueTemplate(Template):
|
||||||
|
|
||||||
|
|
||||||
class ComplexValueTemplate(SimpleValueTemplate):
|
class ComplexValueTemplate(SimpleValueTemplate):
|
||||||
delimiter = '@'
|
delimiter = '%'
|
||||||
|
|
||||||
|
|
||||||
@injectable
|
@injectable
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
from contextlib import contextmanager
|
||||||
|
from typing import Any, Generator
|
||||||
|
|
||||||
|
import keyring
|
||||||
from injectable import injectable
|
from injectable import injectable
|
||||||
from pykeepass import PyKeePass, create_database
|
from pykeepass import PyKeePass, create_database
|
||||||
|
|
||||||
|
|
@ -12,22 +14,16 @@ class Passwords:
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
|
|
||||||
with open(settings.kp.secret, "r") as fh:
|
with open(settings.kp.secret, "r") as fh:
|
||||||
secret = fh.read().splitlines()[0]
|
keyring.set_password("karl", "kp", fh.read().splitlines()[0])
|
||||||
self._path = settings.kp.file
|
self._path = settings.kp.file
|
||||||
self._kp_org = self._open_or_create(self._path, secret)
|
|
||||||
self._kp = self._open_lock(self._path, secret)
|
|
||||||
|
|
||||||
@staticmethod
|
@contextmanager
|
||||||
def _open_or_create(path, password) -> PyKeePass:
|
def open(self, mode: str = "r") -> Generator[PyKeePass | Any, Any, None]:
|
||||||
if os.path.exists(path):
|
kp = PyKeePass(self._path, password=keyring.get_password("karl", "kp")) \
|
||||||
return PyKeePass(path, password=password)
|
if os.path.exists(self._path) else create_database(self._path, password=keyring.get_password("karl", "kp"))
|
||||||
return create_database(path, password)
|
yield kp
|
||||||
|
if mode == "rw":
|
||||||
@staticmethod
|
kp.save()
|
||||||
def _open_lock(path, password) -> PyKeePass:
|
|
||||||
lock_path = path + ".lock"
|
|
||||||
shutil.copyfile(path, lock_path)
|
|
||||||
return Passwords._open_or_create(lock_path, password)
|
|
||||||
|
|
||||||
def get_values(self, keys: list[str]) -> dict[str, str]:
|
def get_values(self, keys: list[str]) -> dict[str, str]:
|
||||||
output = {}
|
output = {}
|
||||||
|
|
@ -36,7 +32,8 @@ class Passwords:
|
||||||
path = key_parts[:-1] if len(key_parts) > 2 else None
|
path = key_parts[:-1] if len(key_parts) > 2 else None
|
||||||
entry_name = key_parts[-2]
|
entry_name = key_parts[-2]
|
||||||
field_name = key_parts[-1]
|
field_name = key_parts[-1]
|
||||||
kp_entry = self._kp_org.find_entries(path=path, first=True, title=entry_name)
|
with self.open() as kp:
|
||||||
|
kp_entry = kp.find_entries(path=path, first=True, title=entry_name)
|
||||||
output[k] = self._get_field_value(kp_entry, field_name)
|
output[k] = self._get_field_value(kp_entry, field_name)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
@ -53,8 +50,3 @@ class Passwords:
|
||||||
return kp_entry.url
|
return kp_entry.url
|
||||||
case _:
|
case _:
|
||||||
return kp_entry.get_custom_property(field_name)
|
return kp_entry.get_custom_property(field_name)
|
||||||
|
|
||||||
def save(self):
|
|
||||||
# nadpisz plik źródłowy zmianami z lock
|
|
||||||
self._kp.save()
|
|
||||||
shutil.copyfile(self._path + ".lock", self._path)
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ dependencies = [
|
||||||
"injectable==4.0.1",
|
"injectable==4.0.1",
|
||||||
"py-automapper>=2.2.0",
|
"py-automapper>=2.2.0",
|
||||||
"fastapi-utils>=0.8.0",
|
"fastapi-utils>=0.8.0",
|
||||||
|
"keyring>=25.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
value: ${sample}
|
value: ${sample}
|
||||||
nested: ${some.nested.value}
|
nested: ${some.nested.value}
|
||||||
custom: @{custom.field}
|
custom: %{custom.field}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class TestMo(TestCase):
|
||||||
with open(target_path, 'r') as f:
|
with open(target_path, 'r') as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
self.assertFalse(content.__contains__('${'))
|
self.assertFalse(content.__contains__('${'))
|
||||||
|
self.assertFalse(content.__contains__('%{'))
|
||||||
parsed = yaml.load(content, Loader=yaml.FullLoader)
|
parsed = yaml.load(content, Loader=yaml.FullLoader)
|
||||||
self.assertEqual('some_pass', parsed['value'])
|
self.assertEqual('some_pass', parsed['value'])
|
||||||
self.assertEqual('nested_pass', parsed['nested'])
|
self.assertEqual('nested_pass', parsed['nested'])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue