Skip to content

Commit 4ee390f

Browse files
refactor: Refactored _write_zuliprc to create zulip_key.
1 parent 23a773c commit 4ee390f

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

zulipterminal/cli/run.py

+40-15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import argparse
66
import configparser
7+
import contextlib
78
import logging
89
import os
910
import stat
@@ -311,36 +312,60 @@ def fetch_zuliprc(zuliprc_path: str) -> None:
311312
print(in_color("red", "\nIncorrect Email(or Username) or Password!\n"))
312313
login_data = get_api_key(realm_url)
313314

315+
zulip_key_path = os.path.join(
316+
os.path.dirname(os.path.abspath(zuliprc_path)), "zulip_key"
317+
)
318+
314319
preferred_realm_url, login_id, api_key = login_data
315320
save_zuliprc_failure = _write_zuliprc(
316-
zuliprc_path,
317-
login_id=login_id,
321+
to_path=zuliprc_path,
322+
key_path=zulip_key_path,
318323
api_key=api_key,
324+
login_id=login_id,
319325
server_url=preferred_realm_url,
320326
)
321327
if not save_zuliprc_failure:
322-
print(f"Generated API key saved at {zuliprc_path}")
328+
print(f"Generated config file saved at {zuliprc_path}")
323329
else:
324330
exit_with_error(save_zuliprc_failure)
325331

326332

327333
def _write_zuliprc(
328-
to_path: str, *, login_id: str, api_key: str, server_url: str
334+
to_path: str, *, key_path: str, login_id: str, api_key: str, server_url: str
329335
) -> str:
330336
"""
331-
Writes a zuliprc file, returning a non-empty error string on failure
332-
Only creates new private files; errors if file already exists
337+
Writes both zuliprc and zulip_key files securely.
338+
Ensures atomicity: if one file fails to write, cleans up the other.
339+
Returns an empty string on success, or a descriptive error message on failure.
333340
"""
341+
zuliprc_created = False
342+
334343
try:
344+
# Write zuliprc
335345
with open(
336346
os.open(to_path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0o600), "w"
337347
) as f:
338-
f.write(f"[api]\nemail={login_id}\nkey={api_key}\nsite={server_url}")
348+
f.write(
349+
f"[api]\nemail={login_id}\npasscmd=cat zulip_key\nsite={server_url}"
350+
)
351+
zuliprc_created = True
352+
# Write zulip_key
353+
with open(
354+
os.open(key_path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0o600), "w"
355+
) as f:
356+
f.write(api_key)
357+
339358
return ""
359+
340360
except FileExistsError:
341-
return f"zuliprc already exists at {to_path}"
361+
filename = to_path if not zuliprc_created else key_path
362+
return f"FileExistsError: {filename} already exists"
342363
except OSError as ex:
343-
return f"{ex.__class__.__name__}: zuliprc could not be created at {to_path}"
364+
if zuliprc_created:
365+
with contextlib.suppress(Exception):
366+
os.remove(to_path)
367+
filename = key_path if zuliprc_created else to_path
368+
return f"{ex.__class__.__name__}: could not create {filename} ({ex})"
344369

345370

346371
def parse_zuliprc(zuliprc_str: str) -> Dict[str, SettingData]:
@@ -366,12 +391,12 @@ def parse_zuliprc(zuliprc_str: str) -> Dict[str, SettingData]:
366391
in_color(
367392
"red",
368393
"ERROR: Please ensure your zuliprc is NOT publicly accessible:\n"
369-
" {0}\n"
370-
"(it currently has permissions '{1}')\n"
394+
f" {zuliprc_path}\n"
395+
f"(it currently has permissions '{stat.filemode(mode)}')\n"
371396
"This can often be achieved with a command such as:\n"
372-
" chmod og-rwx {0}\n"
397+
f" chmod og-rwx {zuliprc_path}\n"
373398
"Consider regenerating the [api] part of your zuliprc to ensure "
374-
"your account is secure.".format(zuliprc_path, stat.filemode(mode)),
399+
"your account is secure.",
375400
)
376401
)
377402
sys.exit(1)
@@ -687,8 +712,8 @@ def print_setting(setting: str, data: SettingData, suffix: str = "") -> None:
687712
# Dump stats only after temporary file is closed (for Win NT+ case)
688713
prof.dump_stats(profile_path)
689714
print(
690-
"Profile data saved to {0}.\n"
691-
"You can visualize it using e.g. `snakeviz {0}`".format(profile_path)
715+
f"Profile data saved to {profile_path}.\n"
716+
f"You can visualize it using e.g. `snakeviz {profile_path}`"
692717
)
693718

694719
sys.exit(1)

zulipterminal/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -745,4 +745,4 @@ def main(self) -> None:
745745

746746
finally:
747747
self.restore_stdout()
748-
self.loop.screen.tty_signal_keys(*old_signal_list)
748+
self.loop.screen.tty_signal_keys(*old_signal_list)

0 commit comments

Comments
 (0)