More work on the transfer kitten

This commit is contained in:
Kovid Goyal 2021-09-19 10:17:53 +05:30
parent 2a9dff2846
commit 68436c93a7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 31 additions and 30 deletions

View File

@ -30,9 +30,9 @@ receiving computer. In :code:`normal` mode the last argument is assumed to be a
destination path on the receiving computer.
--permissions-password -p
--permissions-bypass -p
The password to use to skip the transfer confirmation popup in kitty. Must match the
password set for the :opt:`file_transfer_password` option in kitty.conf. Note that
password set for the :opt:`file_transfer_confirmation_bypass` option in kitty.conf. Note that
leading and trailing whitespace is removed from the password. A password starting with
., / or ~ characters is assumed to be a file name to read the password from. A value
of - means read the password from STDIN. A password that is purely a number less than 256
@ -71,8 +71,8 @@ def read_password(loc: str) -> str:
def main(args: List[str]) -> None:
cli_opts, items = parse_transfer_args(args)
if cli_opts.permissions_password:
cli_opts.permissions_password = read_password(cli_opts.permissions_password).strip()
if cli_opts.permissions_bypass:
cli_opts.permissions_bypass = read_password(cli_opts.permissions_bypass).strip()
if not items:
raise SystemExit('Usage: kitty +kitten transfer file_or_directory ...')

View File

@ -18,7 +18,7 @@ from kitty.cli_stub import TransferCLIOptions
from kitty.fast_data_types import FILE_TRANSFER_CODE, wcswidth
from kitty.file_transmission import (
Action, Compression, FileTransmissionCommand, FileType, NameReprEnum,
TransmissionType, encode_password
TransmissionType, encode_bypass
)
from kitty.typing import KeyEventType
from kitty.utils import sanitize_control_codes
@ -257,9 +257,9 @@ class ProgressTracker:
class SendManager:
def __init__(self, request_id: str, files: Tuple[File, ...], pw: Optional[str] = None, file_done: Callable[[File], None] = lambda f: None):
def __init__(self, request_id: str, files: Tuple[File, ...], bypass: Optional[str] = None, file_done: Callable[[File], None] = lambda f: None):
self.files = files
self.password = encode_password(request_id, pw) if pw else ''
self.bypass = encode_bypass(request_id, bypass) if bypass else ''
self.fid_map = {f.file_id: f for f in self.files}
self.request_id = request_id
self.state = SendState.waiting_for_permission
@ -306,7 +306,7 @@ class SendManager:
self.all_started = not found_not_started
def start_transfer(self) -> str:
return FileTransmissionCommand(action=Action.send, password=self.password).serialize()
return FileTransmissionCommand(action=Action.send, bypass=self.bypass).serialize()
def next_chunks(self) -> Iterator[str]:
if self.active_file is None:
@ -368,7 +368,7 @@ class Send(Handler):
def __init__(self, cli_opts: TransferCLIOptions, files: Tuple[File, ...]):
Handler.__init__(self)
self.manager = SendManager(random_id(), files, cli_opts.permissions_password, self.on_file_done)
self.manager = SendManager(random_id(), files, cli_opts.permissions_bypass, self.on_file_done)
self.cli_opts = cli_opts
self.transmit_started = False
self.file_metadata_sent = False
@ -504,8 +504,8 @@ class Send(Handler):
def initialize(self) -> None:
self.send_payload(self.manager.start_transfer())
if self.cli_opts.permissions_password:
# dont wait for permission, not needed with a password and
if self.cli_opts.permissions_bypass:
# dont wait for permission, not needed with a bypass and
# avoids a roundtrip
self.send_file_metadata()
self.cmd.set_cursor_visible(False)

View File

@ -26,7 +26,7 @@ EXPIRE_TIME = 10 # minutes
MAX_ACTIVE_RECEIVES = 10
def encode_password(request_id: str, pw: str) -> str:
def encode_bypass(request_id: str, pw: str) -> str:
import hashlib
q = request_id + ';' + pw
return 'sha256:' + hashlib.sha256(q.encode('utf-8', 'replace')).hexdigest()
@ -114,7 +114,7 @@ class FileTransmissionCommand:
ttype: TransmissionType = TransmissionType.simple
id: str = ''
file_id: str = ''
password: str = field(default='', metadata={'base64': True})
bypass: str = field(default='', metadata={'base64': True})
quiet: int = 0
mtime: int = -1
permissions: int = -1
@ -341,12 +341,12 @@ class ActiveReceive:
files: Dict[str, DestFile]
accepted: bool = False
def __init__(self, request_id: str, quiet: int, password: str) -> None:
def __init__(self, request_id: str, quiet: int, bypass: str) -> None:
self.id = request_id
self.password_ok: Optional[bool] = None
pw = get_options().file_transfer_password
if pw and password:
self.password_ok = encode_password(request_id, pw) == password
self.bypass_ok: Optional[bool] = None
byp = get_options().file_transfer_confirmation_bypass
if byp and bypass:
self.bypass_ok = encode_bypass(request_id, byp) == byp
self.files = {}
self.last_activity_at = monotonic()
self.send_acknowledgements = quiet < 1
@ -477,7 +477,7 @@ class FileTransmission:
if len(self.active_receives) >= MAX_ACTIVE_RECEIVES:
log_error('New File transmission send with too many active receives, ignoring')
return
ar = self.active_receives[cmd.id] = ActiveReceive(cmd.id, cmd.quiet, cmd.password)
ar = self.active_receives[cmd.id] = ActiveReceive(cmd.id, cmd.quiet, cmd.bypass)
self.start_receive(ar.id)
return
@ -568,8 +568,8 @@ class FileTransmission:
def start_receive(self, ar_id: str) -> None:
ar = self.active_receives[ar_id]
if ar.password_ok is not None:
self.handle_send_confirmation(ar_id, {'response': 'y' if ar.password_ok else 'n'})
if ar.bypass_ok is not None:
self.handle_send_confirmation(ar_id, {'response': 'y' if ar.bypass_ok else 'n'})
return
boss = get_boss()
window = boss.window_id_map.get(self.window_id)

View File

@ -2566,11 +2566,12 @@ stored for writing to the system clipboard. See also :opt:`clipboard_control`.
A value of zero means no size limit is applied.
''')
opt('file_transfer_password', '', long_text='''
A password, that can be supplied to the file transfer kitten to skip
the transfer confirmation dialog. This should only be used
when initiating transfers from trusted computers, over trusted networks
or encrypted transports.
opt('file_transfer_confirmation_bypass', '', long_text='''
A password, that can be supplied to the file transfer kitten to skip the
transfer confirmation prompt. This should only be used when initiating
transfers from trusted computers, over trusted networks or encrypted
transports, as it allows programs running on the remote machine to read/write
to the local filesystem, without permission.
''')
opt('allow_hyperlinks', 'yes',

View File

@ -942,8 +942,8 @@ class Parser:
for k, v in env(val, ans["env"]):
ans["env"][k] = v
def file_transfer_password(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['file_transfer_password'] = str(val)
def file_transfer_confirmation_bypass(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['file_transfer_confirmation_bypass'] = str(val)
def focus_follows_mouse(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['focus_follows_mouse'] = to_bool(val)

View File

@ -345,7 +345,7 @@ option_names = ( # {{{
'enable_audio_bell',
'enabled_layouts',
'env',
'file_transfer_password',
'file_transfer_confirmation_bypass',
'focus_follows_mouse',
'font_family',
'font_features',
@ -485,7 +485,7 @@ class Options:
editor: str = '.'
enable_audio_bell: bool = True
enabled_layouts: typing.List[str] = ['fat', 'grid', 'horizontal', 'splits', 'stack', 'tall', 'vertical']
file_transfer_password: str = ''
file_transfer_confirmation_bypass: str = ''
focus_follows_mouse: bool = False
font_family: str = 'monospace'
font_size: float = 11.0