- commit
- 07ef4b1db7f2d4b5c8204babbf8e59d27ac3642f
- parent
- 25cfb6114c00dbe07be55fc144d6513d6470f5b6
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2024-05-10 10:51
only load secrets into memory on requests
Diffstat
| M | xikeyring/keyring.py | 50 | +++++++++++++++++++++++++++----------------------- |
1 files changed, 27 insertions, 23 deletions
diff --git a/xikeyring/keyring.py b/xikeyring/keyring.py
@@ -79,8 +79,6 @@ class Crypt: 79 79 80 80 81 81 class Keyring:82 -1 items: dict[int, Item]83 -184 82 def __init__(self, path: str): 85 83 self.path = path 86 84 self.prompt = Prompt() @@ -94,9 +92,8 @@ class Keyring: 94 92 except InvalidToken: 95 93 pass 96 94 else:97 -1 self.items = {}98 95 self.crypt = self._get_crypt()99 -1 self._write()-1 96 self._write({}) 100 97 os.chmod(self.path, 0o600) 101 98 102 99 def _get_crypt(self): @@ -108,17 +105,17 @@ class Keyring: 108 105 raise AccessDeniedError 109 106 return Crypt(password) 110 107111 -1 def _read(self):-1 108 def _read(self) -> dict[int, Item]: 112 109 with open(self.path, 'rb') as fh: 113 110 encrypted = fh.read() 114 111 decrypted = self.crypt.decrypt(encrypted) 115 112 raw = json.loads(decrypted)116 -1 self.items = {-1 113 return { 117 114 id: Item(base64.urlsafe_b64decode(secret), attributes, exe) 118 115 for id, secret, attributes, exe in raw 119 116 } 120 117121 -1 def _write(self):-1 118 def _write(self, items: dict[int, Item]): 122 119 raw = [ 123 120 ( 124 121 id, @@ -126,7 +123,7 @@ class Keyring: 126 123 item.attributes, 127 124 item.exe, 128 125 )129 -1 for id, item in self.items.items()-1 126 for id, item in items.items() 130 127 ] 131 128 decrypted = json.dumps(raw).encode('utf-8') 132 129 encrypted = self.crypt.encrypt(decrypted) @@ -144,9 +141,9 @@ class Keyring: 144 141 def has_access(self, exe: str, item: Item) -> bool: 145 142 return item.exe == exe or exe in TRUSTED_MANAGERS 146 143147 -1 def get(self, exe: str, id: int) -> Item:-1 144 def get(self, items: dict[int, Item], exe: str, id: int) -> Item: 148 145 try:149 -1 item = self.items[id]-1 146 item = items[id] 150 147 except KeyError as e: 151 148 raise NotFoundError from e 152 149 if not self.has_access(exe, item): @@ -154,44 +151,51 @@ class Keyring: 154 151 return item 155 152 156 153 def search_items(self, exe: str, query: dict[str, str] = {}) -> list[int]: -1 154 items = self._read() 157 155 return [158 -1 id for id, item in self.items.items()-1 156 id for id, item in items.items() 159 157 if self.has_access(exe, item) and all( 160 158 item.attributes.get(key) == value for key, value in query.items() 161 159 ) 162 160 ] 163 161 164 162 def get_attributes(self, exe: str, id: int) -> dict[str, str]:165 -1 return self.get(exe, id).attributes-1 163 items = self._read() -1 164 return self.get(items, exe, id).attributes 166 165 167 166 def get_secret(self, exe: str, id: int) -> bytes:168 -1 item = self.get(exe, id)-1 167 items = self._read() -1 168 item = self.get(items, exe, id) 169 169 self.confirm_access(exe) 170 170 return item.secret 171 171 172 172 def create_item(self, exe: str, attributes: dict[str, str], secret: bytes) -> int:173 -1 id = max(self.items.keys(), default=0) + 1174 -1 self.items[id] = Item(secret, attributes, exe)175 -1 self._write()-1 173 items = self._read() -1 174 id = max(items.keys(), default=0) + 1 -1 175 items[id] = Item(secret, attributes, exe) -1 176 self._write(items) 176 177 return id 177 178 178 179 def update_attributes(self, exe: str, id: int, attributes: dict[str, str]) -> None:179 -1 item = self.get(exe, id)-1 180 items = self._read() -1 181 item = self.get(items, exe, id) 180 182 self.confirm_change(exe) 181 183 item.attributes = attributes182 -1 self._write()-1 184 self._write(items) 183 185 184 186 def update_secret(self, exe: str, id: int, secret: bytes) -> None:185 -1 item = self.get(exe, id)-1 187 items = self._read() -1 188 item = self.get(items, exe, id) 186 189 self.confirm_change(exe) 187 190 item.secret = secret188 -1 self._write()-1 191 self._write(items) 189 192 190 193 def delete_item(self, exe: str, id: int) -> None:191 -1 self.get(exe, id) # trigger appropriate exceptions-1 194 items = self._read() -1 195 self.get(items, exe, id) # trigger appropriate exceptions 192 196 self.confirm_change(exe)193 -1 del self.items[id]194 -1 self._write()-1 197 del items[id] -1 198 self._write(items) 195 199 196 200 197 201 class KeyringProxy: