s2k-cli 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/PKG-INFO +1 -1
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/pyproject.toml +1 -1
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/config.py +4 -2
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/mailer.py +9 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/wizard.py +23 -11
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/LICENSE +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/README.md +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/__init__.py +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/__main__.py +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/constants.py +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/doctor.py +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/errors.py +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/main.py +0 -0
- {s2k_cli-0.1.0 → s2k_cli-0.2.0}/src/send_2_kindle/validation.py +0 -0
|
@@ -33,8 +33,10 @@ def config_file_path() -> Path:
|
|
|
33
33
|
override = os.environ.get(CONFIG_FILE_VARIABLE)
|
|
34
34
|
if override:
|
|
35
35
|
return Path(override).expanduser()
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
xdg = os.environ.get("XDG_CONFIG_HOME", "")
|
|
37
|
+
# The XDG spec says relative values must be ignored.
|
|
38
|
+
base = Path(xdg) if xdg and Path(xdg).is_absolute() else Path("~/.config").expanduser()
|
|
39
|
+
return base / "s2k" / "config.env"
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
class Settings(BaseSettings):
|
|
@@ -43,6 +43,14 @@ def _auth_failure_message(settings: Settings) -> str:
|
|
|
43
43
|
return message
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def _security_hint(settings: Settings) -> str:
|
|
47
|
+
if settings.smtp_port == 465 and settings.smtp_security == "starttls":
|
|
48
|
+
return " (port 465 normally needs S2K_SMTP_SECURITY=ssl)"
|
|
49
|
+
if settings.smtp_port == 587 and settings.smtp_security == "ssl":
|
|
50
|
+
return " (port 587 normally needs S2K_SMTP_SECURITY=starttls)"
|
|
51
|
+
return ""
|
|
52
|
+
|
|
53
|
+
|
|
46
54
|
def _close_quietly(smtp: smtplib.SMTP | None) -> None:
|
|
47
55
|
if smtp is not None:
|
|
48
56
|
smtp.close()
|
|
@@ -112,6 +120,7 @@ class KindleMailer:
|
|
|
112
120
|
_close_quietly(smtp)
|
|
113
121
|
raise SmtpConnectionError(
|
|
114
122
|
f"could not connect to {settings.smtp_host}:{settings.smtp_port}: {error}"
|
|
123
|
+
f"{_security_hint(settings)}"
|
|
115
124
|
) from error
|
|
116
125
|
self._smtp = smtp
|
|
117
126
|
return self
|
|
@@ -46,7 +46,11 @@ def _quote(value: str) -> str:
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
def write_config(path: Path, values: dict[str, str]) -> None:
|
|
49
|
-
"""Atomically write ``values`` as KEY="value" lines to ``path`` (mode 600, new dirs 700).
|
|
49
|
+
"""Atomically write ``values`` as KEY="value" lines to ``path`` (mode 600, new dirs 700).
|
|
50
|
+
|
|
51
|
+
A symlinked config file (e.g. managed by a dotfiles repo) is kept: its target is rewritten.
|
|
52
|
+
"""
|
|
53
|
+
path = path.resolve() if path.is_symlink() else path
|
|
50
54
|
path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
|
51
55
|
content = HEADER + "".join(f"{key}={_quote(value)}\n" for key, value in values.items())
|
|
52
56
|
fd, temp_name = tempfile.mkstemp(dir=path.parent, prefix=".config.env.")
|
|
@@ -79,16 +83,24 @@ def _ask(text: str, adapter: TypeAdapter[Any], default: str | None) -> str:
|
|
|
79
83
|
|
|
80
84
|
|
|
81
85
|
def _ask_password(has_current: bool) -> str | None:
|
|
82
|
-
"""Return the new password, or None to keep the current one."""
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
"""Return the new password (typed twice), or None to keep the current one."""
|
|
87
|
+
while True:
|
|
88
|
+
if has_current:
|
|
89
|
+
answer = str(
|
|
90
|
+
typer.prompt(
|
|
91
|
+
"SMTP password (empty keeps the current one)",
|
|
92
|
+
default="",
|
|
93
|
+
hide_input=True,
|
|
94
|
+
show_default=False,
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
if not answer:
|
|
98
|
+
return None
|
|
99
|
+
else:
|
|
100
|
+
answer = str(typer.prompt("SMTP password", hide_input=True))
|
|
101
|
+
if str(typer.prompt("Repeat the SMTP password", hide_input=True)) == answer:
|
|
102
|
+
return answer
|
|
103
|
+
typer.secho(" The passwords do not match; try again.", fg=typer.colors.YELLOW)
|
|
92
104
|
|
|
93
105
|
|
|
94
106
|
def _collect(current: dict[str, str]) -> dict[str, str]:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|