Merge pull request #83 from paul-nameless/quote

Shell-escape file path passed to commands
This commit is contained in:
Nameless 2020-06-21 10:32:18 +08:00 committed by GitHub
commit 53c2e9354f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 16 deletions

View file

@ -54,7 +54,7 @@ docker run -it --rm tg
- `terminal-notifier` or other program for notifications (see configuration) - `terminal-notifier` or other program for notifications (see configuration)
- `ffmpeg` to record voice msgs and upload videos correctly - `ffmpeg` to record voice msgs and upload videos correctly
- [tdlib](https://tdlib.github.io/td/build.html?language=Python) - in case of incompatibility with built in package - [tdlib](https://tdlib.github.io/td/build.html?language=Python) - in case of incompatibility with built in package.
For example, macOS: For example, macOS:
```sh ```sh
brew install tdlib brew install tdlib
@ -99,16 +99,16 @@ LOG_PATH = "~/.local/share/tg/"
# use your own, for example: # use your own, for example:
TDLIB_PATH = "/usr/local/Cellar/tdlib/1.6.0/lib/libtdjson.dylib" TDLIB_PATH = "/usr/local/Cellar/tdlib/1.6.0/lib/libtdjson.dylib"
# you can use any other notification cmd, it is simple python file which # you can use any other notification cmd, it is simple python string which
# can format title, msg, subtitle and icon_path paramters # can format title, msg, subtitle and icon_path paramters
# In these exapmle, kitty terminal is used and when notification is pressed # In these exapmle, kitty terminal is used and when notification is pressed
# it will focus on the tab of running tg # it will focus on the tab of running tg
NOTIFY_CMD = '/usr/local/bin/terminal-notifier -title "{title}" -subtitle "{subtitle}" -message "{msg}" -appIcon "{icon_path}" -sound default -execute \'/Applications/kitty.app/Contents/MacOS/kitty @ --to unix:/tmp/kitty focus-tab --no-response -m title:tg\'' NOTIFY_CMD = "/usr/local/bin/terminal-notifier -title {title} -subtitle {subtitle} -message {msg} -appIcon {icon_path} -sound default -execute '/Applications/kitty.app/Contents/MacOS/kitty @ --to unix:/tmp/kitty focus-tab --no-response -m title:tg'"
# You can use your own voice recording cmd but it's better to use default one. # You can use your own voice recording cmd but it's better to use default one.
# The voice note must be encoded with the Opus codec, and stored inside an OGG # The voice note must be encoded with the Opus codec, and stored inside an OGG
# container. Voice notes can have only a single audio channel. # container. Voice notes can have only a single audio channel.
VOICE_RECORD_CMD = "ffmpeg -f avfoundation -i ':0' -c:a libopus -b:a 32k '{file_path}'" VOICE_RECORD_CMD = "ffmpeg -f avfoundation -i ':0' -c:a libopus -b:a 32k {file_path}"
# You can customize chat and msg flags however you want. # You can customize chat and msg flags however you want.
# By default words will be used for readability, but you can make # By default words will be used for readability, but you can make

View file

@ -31,17 +31,17 @@ TDLIB_VERBOSITY = 0
MAX_DOWNLOAD_SIZE = "10MB" MAX_DOWNLOAD_SIZE = "10MB"
# TODO: check platform # TODO: check platform
NOTIFY_CMD = "/usr/local/bin/terminal-notifier -title '{title}' -subtitle '{subtitle}' -message '{msg}' -appIcon '{icon_path}'" NOTIFY_CMD = "/usr/local/bin/terminal-notifier -title {title} -subtitle {subtitle} -message {msg} -appIcon {icon_path}"
HELP_CMD = "less" HELP_CMD = "less"
if _os_name == _linux: if _os_name == _linux:
VOICE_RECORD_CMD = ( VOICE_RECORD_CMD = (
"ffmpeg -f alsa -i default -c:a libopus -b:a 32k '{file_path}'" "ffmpeg -f alsa -i default -c:a libopus -b:a 32k {file_path}"
) )
else: else:
VOICE_RECORD_CMD = ( VOICE_RECORD_CMD = (
"ffmpeg -f avfoundation -i ':0' -c:a libopus -b:a 32k '{file_path}'" "ffmpeg -f avfoundation -i ':0' -c:a libopus -b:a 32k {file_path}"
) )
# TODO: use mailcap instead of editor # TODO: use mailcap instead of editor
@ -49,9 +49,9 @@ LONG_MSG_CMD = "vim + -c 'startinsert' {file_path}"
EDITOR = os.environ.get("EDITOR", "vi") EDITOR = os.environ.get("EDITOR", "vi")
if _os_name == _linux: if _os_name == _linux:
DEFAULT_OPEN = "xdg-open '{file_path}'" DEFAULT_OPEN = "xdg-open {file_path}"
else: else:
DEFAULT_OPEN = "open '{file_path}'" DEFAULT_OPEN = "open {file_path}"
if _os_name == _linux: if _os_name == _linux:
COPY_CMD = "xclip -selection c" COPY_CMD = "xclip -selection c"

View file

@ -1,6 +1,7 @@
import curses import curses
import logging import logging
import os import os
import shlex
import threading import threading
from datetime import datetime from datetime import datetime
from functools import partial, wraps from functools import partial, wraps
@ -91,7 +92,7 @@ class Controller:
return return
if len(urls) == 1: if len(urls) == 1:
with suspend(self.view) as s: with suspend(self.view) as s:
s.call(config.DEFAULT_OPEN.format(file_path=url)) s.call(config.DEFAULT_OPEN.format(file_path=shlex.quote(url)))
return return
with suspend(self.view) as s: with suspend(self.view) as s:
s.run_with_input(config.URL_VIEW, "\n".join(urls)) s.run_with_input(config.URL_VIEW, "\n".join(urls))
@ -224,7 +225,7 @@ class Controller:
) as s: ) as s:
f.write(insert_replied_msg(msg)) f.write(insert_replied_msg(msg))
f.seek(0) f.seek(0)
s.call(config.LONG_MSG_CMD.format(file_path=f.name)) s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
with open(f.name) as f: with open(f.name) as f:
if msg := strip_replied_msg(f.read().strip()): if msg := strip_replied_msg(f.read().strip()):
self.tg.reply_message(chat_id, reply_to_msg, msg) self.tg.reply_message(chat_id, reply_to_msg, msg)
@ -251,7 +252,7 @@ class Controller:
with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( with NamedTemporaryFile("r+", suffix=".txt") as f, suspend(
self.view self.view
) as s: ) as s:
s.call(config.LONG_MSG_CMD.format(file_path=f.name)) s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
with open(f.name) as f: with open(f.name) as f:
if msg := f.read().strip(): if msg := f.read().strip():
self.model.send_message(text=msg) self.model.send_message(text=msg)
@ -301,7 +302,11 @@ class Controller:
def record_voice(self): def record_voice(self):
file_path = f"/tmp/voice-{datetime.now()}.oga" file_path = f"/tmp/voice-{datetime.now()}.oga"
with suspend(self.view) as s: with suspend(self.view) as s:
s.call(config.VOICE_RECORD_CMD.format(file_path=file_path)) s.call(
config.VOICE_RECORD_CMD.format(
file_path=shlex.quote(file_path)
)
)
resp = self.view.status.get_input( resp = self.view.status.get_input(
f"Do you want to send recording: {file_path}? [Y/n]" f"Do you want to send recording: {file_path}? [Y/n]"
) )

View file

@ -74,7 +74,7 @@ def get_file_handler(file_path, default=None):
caps = mailcap.getcaps() caps = mailcap.getcaps()
handler, view = mailcap.findmatch(caps, mtype, filename=file_path) handler, view = mailcap.findmatch(caps, mtype, filename=file_path)
if not handler: if not handler:
return config.DEFAULT_OPEN.format(file_path=file_path) return config.DEFAULT_OPEN.format(file_path=shlex.quote(file_path))
return handler return handler
@ -148,9 +148,11 @@ def notify(
if not cmd: if not cmd:
return return
notify_cmd = cmd.format( notify_cmd = cmd.format(
icon_path=config.ICON_PATH, title=title, subtitle=subtitle, msg=msg icon_path=shlex.quote(config.ICON_PATH),
title=shlex.quote(title),
subtitle=shlex.quote(subtitle),
msg=shlex.quote(msg),
) )
log.info("notify-cmd: %s", notify_cmd)
os.system(notify_cmd) os.system(notify_cmd)