Skip to content

Commit c388e71

Browse files
feat: Add function to process the passcmd for API key retrieval.
1 parent 929e71e commit c388e71

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

zulip/zulip/__init__.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import os
66
import platform
77
import random
8+
import shlex
9+
import subprocess
810
import sys
911
import time
1012
import traceback
@@ -366,12 +368,15 @@ class MissingURLError(ZulipError):
366368
class UnrecoverableNetworkError(ZulipError):
367369
pass
368370

371+
class APIKeyRetrievalError(ZulipError):
372+
pass
369373

370374
class Client:
371375
def __init__(
372376
self,
373377
email: Optional[str] = None,
374378
api_key: Optional[str] = None,
379+
passcmd: Optional[str] = None,
375380
config_file: Optional[str] = None,
376381
verbose: bool = False,
377382
retry_on_errors: bool = True,
@@ -424,8 +429,29 @@ def __init__(
424429
config = ConfigParser()
425430
with open(config_file) as f:
426431
config.read_file(f, config_file)
427-
if api_key is None:
432+
if api_key is None and config.has_option("api", "key"):
428433
api_key = config.get("api", "key")
434+
if passcmd is None and config.has_option("api", "passcmd"):
435+
passcmd = config.get("api", "passcmd")
436+
malicious_chars = {";", "|", "&", ">", "<", "`", "$", "\\", "\n", "\r"}
437+
if any(char in passcmd for char in malicious_chars):
438+
raise APIKeyRetrievalError(
439+
f"Invalid characters detected in passcmd: {passcmd!r}"
440+
)
441+
try:
442+
cmd_parts = shlex.split(passcmd)
443+
except ValueError as err:
444+
raise APIKeyRetrievalError(
445+
f"Failed to parse passcmd '{passcmd}': {err!s}"
446+
) from err
447+
try:
448+
result = subprocess.run(cmd_parts, capture_output=True, check=True)
449+
api_key = result.stdout.decode().strip()
450+
except subprocess.CalledProcessError as err:
451+
raise APIKeyRetrievalError(
452+
f'Failed to retrieve API key using passcmd "{passcmd}".'
453+
f"Command exited with return code {err.returncode}."
454+
) from err
429455
if email is None:
430456
email = config.get("api", "email")
431457
if site is None and config.has_option("api", "site"):

0 commit comments

Comments
 (0)