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. 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 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 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 ., / 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 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: def main(args: List[str]) -> None:
cli_opts, items = parse_transfer_args(args) cli_opts, items = parse_transfer_args(args)
if cli_opts.permissions_password: if cli_opts.permissions_bypass:
cli_opts.permissions_password = read_password(cli_opts.permissions_password).strip() cli_opts.permissions_bypass = read_password(cli_opts.permissions_bypass).strip()
if not items: if not items:
raise SystemExit('Usage: kitty +kitten transfer file_or_directory ...') 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.fast_data_types import FILE_TRANSFER_CODE, wcswidth
from kitty.file_transmission import ( from kitty.file_transmission import (
Action, Compression, FileTransmissionCommand, FileType, NameReprEnum, Action, Compression, FileTransmissionCommand, FileType, NameReprEnum,
TransmissionType, encode_password TransmissionType, encode_bypass
) )
from kitty.typing import KeyEventType from kitty.typing import KeyEventType
from kitty.utils import sanitize_control_codes from kitty.utils import sanitize_control_codes
@ -257,9 +257,9 @@ class ProgressTracker:
class SendManager: 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.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.fid_map = {f.file_id: f for f in self.files}
self.request_id = request_id self.request_id = request_id
self.state = SendState.waiting_for_permission self.state = SendState.waiting_for_permission
@ -306,7 +306,7 @@ class SendManager:
self.all_started = not found_not_started self.all_started = not found_not_started
def start_transfer(self) -> str: 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]: def next_chunks(self) -> Iterator[str]:
if self.active_file is None: if self.active_file is None:
@ -368,7 +368,7 @@ class Send(Handler):
def __init__(self, cli_opts: TransferCLIOptions, files: Tuple[File, ...]): def __init__(self, cli_opts: TransferCLIOptions, files: Tuple[File, ...]):
Handler.__init__(self) 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.cli_opts = cli_opts
self.transmit_started = False self.transmit_started = False
self.file_metadata_sent = False self.file_metadata_sent = False
@ -504,8 +504,8 @@ class Send(Handler):
def initialize(self) -> None: def initialize(self) -> None:
self.send_payload(self.manager.start_transfer()) self.send_payload(self.manager.start_transfer())
if self.cli_opts.permissions_password: if self.cli_opts.permissions_bypass:
# dont wait for permission, not needed with a password and # dont wait for permission, not needed with a bypass and
# avoids a roundtrip # avoids a roundtrip
self.send_file_metadata() self.send_file_metadata()
self.cmd.set_cursor_visible(False) self.cmd.set_cursor_visible(False)

View File

@ -26,7 +26,7 @@ EXPIRE_TIME = 10 # minutes
MAX_ACTIVE_RECEIVES = 10 MAX_ACTIVE_RECEIVES = 10
def encode_password(request_id: str, pw: str) -> str: def encode_bypass(request_id: str, pw: str) -> str:
import hashlib import hashlib
q = request_id + ';' + pw q = request_id + ';' + pw
return 'sha256:' + hashlib.sha256(q.encode('utf-8', 'replace')).hexdigest() return 'sha256:' + hashlib.sha256(q.encode('utf-8', 'replace')).hexdigest()
@ -114,7 +114,7 @@ class FileTransmissionCommand:
ttype: TransmissionType = TransmissionType.simple ttype: TransmissionType = TransmissionType.simple
id: str = '' id: str = ''
file_id: str = '' file_id: str = ''
password: str = field(default='', metadata={'base64': True}) bypass: str = field(default='', metadata={'base64': True})
quiet: int = 0 quiet: int = 0
mtime: int = -1 mtime: int = -1
permissions: int = -1 permissions: int = -1
@ -341,12 +341,12 @@ class ActiveReceive:
files: Dict[str, DestFile] files: Dict[str, DestFile]
accepted: bool = False 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.id = request_id
self.password_ok: Optional[bool] = None self.bypass_ok: Optional[bool] = None
pw = get_options().file_transfer_password byp = get_options().file_transfer_confirmation_bypass
if pw and password: if byp and bypass:
self.password_ok = encode_password(request_id, pw) == password self.bypass_ok = encode_bypass(request_id, byp) == byp
self.files = {} self.files = {}
self.last_activity_at = monotonic() self.last_activity_at = monotonic()
self.send_acknowledgements = quiet < 1 self.send_acknowledgements = quiet < 1
@ -477,7 +477,7 @@ class FileTransmission:
if len(self.active_receives) >= MAX_ACTIVE_RECEIVES: if len(self.active_receives) >= MAX_ACTIVE_RECEIVES:
log_error('New File transmission send with too many active receives, ignoring') log_error('New File transmission send with too many active receives, ignoring')
return 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) self.start_receive(ar.id)
return return
@ -568,8 +568,8 @@ class FileTransmission:
def start_receive(self, ar_id: str) -> None: def start_receive(self, ar_id: str) -> None:
ar = self.active_receives[ar_id] ar = self.active_receives[ar_id]
if ar.password_ok is not None: if ar.bypass_ok is not None:
self.handle_send_confirmation(ar_id, {'response': 'y' if ar.password_ok else 'n'}) self.handle_send_confirmation(ar_id, {'response': 'y' if ar.bypass_ok else 'n'})
return return
boss = get_boss() boss = get_boss()
window = boss.window_id_map.get(self.window_id) 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. A value of zero means no size limit is applied.
''') ''')
opt('file_transfer_password', '', long_text=''' opt('file_transfer_confirmation_bypass', '', long_text='''
A password, that can be supplied to the file transfer kitten to skip A password, that can be supplied to the file transfer kitten to skip the
the transfer confirmation dialog. This should only be used transfer confirmation prompt. This should only be used when initiating
when initiating transfers from trusted computers, over trusted networks transfers from trusted computers, over trusted networks or encrypted
or encrypted transports. transports, as it allows programs running on the remote machine to read/write
to the local filesystem, without permission.
''') ''')
opt('allow_hyperlinks', 'yes', opt('allow_hyperlinks', 'yes',

View File

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

View File

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