Add a permission password to the transfer kitten
This commit is contained in:
parent
0d89eb2c40
commit
24255be0bd
@ -81,6 +81,15 @@ receiving computer. In :code:`normal` mode the last argument is assumed to be a
|
||||
destination path on the receiving computer.
|
||||
|
||||
|
||||
--permissions-password -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
|
||||
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
|
||||
is assumed to be the number of a file descriptor from which to read the actual password.
|
||||
|
||||
|
||||
--confirm-paths
|
||||
type=bool-set
|
||||
Before actually transferring files, show a mapping of local file names to remote file names
|
||||
@ -288,8 +297,9 @@ class SendState(NameReprEnum):
|
||||
|
||||
class SendManager:
|
||||
|
||||
def __init__(self, request_id: str, files: Tuple[File, ...]):
|
||||
def __init__(self, request_id: str, files: Tuple[File, ...], pw: Optional[str] = None):
|
||||
self.files = files
|
||||
self.password = pw or ''
|
||||
self.fid_map = {f.file_id: f for f in self.files}
|
||||
self.request_id = request_id
|
||||
self.state = SendState.waiting_for_permission
|
||||
@ -323,7 +333,7 @@ class SendManager:
|
||||
self.all_started = not found_not_started
|
||||
|
||||
def start_transfer(self) -> str:
|
||||
return FileTransmissionCommand(action=Action.send).serialize()
|
||||
return FileTransmissionCommand(action=Action.send, password=self.password).serialize()
|
||||
|
||||
def next_chunk(self) -> str:
|
||||
if self.active_file is None:
|
||||
@ -389,10 +399,12 @@ class Send(Handler):
|
||||
if before == SendState.waiting_for_permission:
|
||||
if self.manager.state == SendState.permission_denied:
|
||||
self.cmd.styled('Permission denied for this transfer', fg='red')
|
||||
self.print()
|
||||
self.quit_loop(1)
|
||||
return
|
||||
if self.manager.state == SendState.permission_granted:
|
||||
self.cmd.styled('Permission granted for this transfer', fg='green')
|
||||
self.print()
|
||||
self.loop_tick()
|
||||
|
||||
def check_for_transmit_ok(self) -> None:
|
||||
@ -435,6 +447,7 @@ class Send(Handler):
|
||||
|
||||
def on_interrupt(self) -> None:
|
||||
self.cmd.styled('Interrupt requested, cancelling transfer, transferred files are in undefined state', fg='red')
|
||||
self.print()
|
||||
self.abort_transfer()
|
||||
|
||||
def abort_transfer(self) -> None:
|
||||
@ -447,7 +460,7 @@ def send_main(cli_opts: TransferCLIOptions, args: List[str]) -> None:
|
||||
files = files_for_send(cli_opts, args)
|
||||
print(f'Found {len(files)} files and directories, requesting transfer permission…')
|
||||
loop = Loop()
|
||||
handler = Send(cli_opts, SendManager(random_id(), files))
|
||||
handler = Send(cli_opts, SendManager(random_id(), files, cli_opts.permissions_password))
|
||||
loop.loop(handler)
|
||||
raise SystemExit(loop.return_code)
|
||||
|
||||
@ -459,8 +472,27 @@ def parse_transfer_args(args: List[str]) -> Tuple[TransferCLIOptions, List[str]]
|
||||
)
|
||||
|
||||
|
||||
def read_password(loc: str) -> str:
|
||||
if not loc:
|
||||
return ''
|
||||
if loc.isdigit() and int(loc) >= 0 and int(loc) < 256:
|
||||
with open(int(loc), 'rb') as f:
|
||||
return f.read().decode('utf-8')
|
||||
if loc[0] in ('.', '~', '/'):
|
||||
if loc[0] == '~':
|
||||
loc = os.path.expanduser(loc)
|
||||
with open(loc, 'rb') as f:
|
||||
return f.read().decode('utf-8')
|
||||
if loc == '-':
|
||||
return sys.stdin.read()
|
||||
return loc
|
||||
|
||||
|
||||
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 not items:
|
||||
raise SystemExit('Usage: kitty +kitten transfer file_or_directory ...')
|
||||
if cli_opts.direction == 'send':
|
||||
|
||||
@ -16,7 +16,9 @@ from gettext import gettext as _
|
||||
from time import monotonic
|
||||
from typing import IO, Any, Callable, Deque, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from kitty.fast_data_types import FILE_TRANSFER_CODE, OSC, add_timer, get_boss
|
||||
from kitty.fast_data_types import (
|
||||
FILE_TRANSFER_CODE, OSC, add_timer, get_boss, get_options
|
||||
)
|
||||
|
||||
from .utils import log_error, sanitize_control_codes
|
||||
|
||||
@ -97,7 +99,7 @@ class FileTransmissionCommand:
|
||||
ttype: TransmissionType = TransmissionType.simple
|
||||
id: str = ''
|
||||
file_id: str = ''
|
||||
secret: str = ''
|
||||
password: str = field(default='', metadata={'base64': True})
|
||||
quiet: int = 0
|
||||
mtime: int = -1
|
||||
permissions: int = -1
|
||||
@ -313,8 +315,9 @@ class ActiveReceive:
|
||||
files: Dict[str, DestFile]
|
||||
accepted: bool = False
|
||||
|
||||
def __init__(self, id: str, quiet: int) -> None:
|
||||
def __init__(self, id: str, quiet: int, password: str) -> None:
|
||||
self.id = id
|
||||
self.password = password
|
||||
self.files = {}
|
||||
self.last_activity_at = monotonic()
|
||||
self.send_acknowledgements = quiet < 1
|
||||
@ -432,7 +435,7 @@ class FileTransmission:
|
||||
if cmd.action is not Action.send:
|
||||
log_error(f'File transmission command received for unknown or rejected id: {cmd.id}, ignoring')
|
||||
return
|
||||
ar = self.active_receives[cmd.id] = ActiveReceive(cmd.id, cmd.quiet)
|
||||
ar = self.active_receives[cmd.id] = ActiveReceive(cmd.id, cmd.quiet, cmd.password)
|
||||
self.start_receive(ar.id)
|
||||
return
|
||||
|
||||
@ -518,6 +521,10 @@ class FileTransmission:
|
||||
return False
|
||||
|
||||
def start_receive(self, ar_id: str) -> None:
|
||||
ar = self.active_receives[ar_id]
|
||||
if ar.password:
|
||||
self.handle_send_confirmation(ar_id, {'response': 'y' if ar.password == get_options().file_transfer_password else 'n'})
|
||||
return
|
||||
boss = get_boss()
|
||||
window = boss.window_id_map.get(self.window_id)
|
||||
if window is not None:
|
||||
|
||||
@ -2458,7 +2458,7 @@ opt('editor', '.',
|
||||
The terminal editor (such as ``vim`` or ``nano``) to use when editing the kitty
|
||||
config file or similar tasks.
|
||||
|
||||
The default value of . means to use the environment variables :envvar:`VISUAL`
|
||||
The default value of :code:`.` means to use the environment variables :envvar:`VISUAL`
|
||||
and :envvar:`EDITOR` in that order. If these variables aren't set, kitty will
|
||||
run your :opt:`shell` (``$SHELL -l -i -c env``) to see if your shell config
|
||||
files set :envvar:`VISUAL` or :envvar:`EDITOR`. If that doesn't work, kitty
|
||||
@ -2563,6 +2563,13 @@ 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('allow_hyperlinks', 'yes',
|
||||
option_type='allow_hyperlinks', ctype='bool',
|
||||
long_text='''
|
||||
|
||||
3
kitty/options/parse.py
generated
3
kitty/options/parse.py
generated
@ -942,6 +942,9 @@ 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 focus_follows_mouse(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['focus_follows_mouse'] = to_bool(val)
|
||||
|
||||
|
||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@ -345,6 +345,7 @@ option_names = ( # {{{
|
||||
'enable_audio_bell',
|
||||
'enabled_layouts',
|
||||
'env',
|
||||
'file_transfer_password',
|
||||
'focus_follows_mouse',
|
||||
'font_family',
|
||||
'font_features',
|
||||
@ -484,6 +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 = ''
|
||||
focus_follows_mouse: bool = False
|
||||
font_family: str = 'monospace'
|
||||
font_size: float = 11.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user