Document remote_control_password more thoroughly

Also ignore failures in custom auth functions
This commit is contained in:
Kovid Goyal 2022-08-11 05:56:04 +05:30
parent 2e422e5ba8
commit 331f6d4903
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 113 additions and 13 deletions

View File

@ -38,6 +38,8 @@ Detailed list of changes
0.26.0 [future]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- A new option :opt:`remote_control_password` to use fine grained permissions for what can be remote controlled (:disc:`5320`)
- Reduce startup latency by ~30 milliseconds when running kittens and remote control commands inside kitty (:iss:`5159`)
- A new option :opt:`modify_font` to adjust various font metrics like underlines, cell sizes etc. (:pull:`5265`)

View File

@ -107,6 +107,11 @@ Variables that influence kitty behavior
Set this to the directory path of the kitty source code and its Python code
will be loaded from there. Only works with official binary builds.
.. envvar:: KITTY_RC_PASSWORD
Set this to a pass phrase to use the ``kitty @`` remote control command with
:opt:`remote_control_password`.
Variables that kitty sets when running child programs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -17,8 +17,9 @@ Start by running |kitty| as::
kitty -o allow_remote_control=yes -o enabled_layouts=tall
In order for control to work, :opt:`allow_remote_control` must be enabled in
:file:`kitty.conf`. Here we turn it on explicitly at the command line.
In order for control to work, :opt:`allow_remote_control` or
:opt:`remote_control_password` must be enabled in :file:`kitty.conf`. Here we
turn it on explicitly at the command line.
Now, in the new |kitty| window, enter the command::
@ -92,11 +93,23 @@ As you can see, it is very easy to control |kitty| using the ``kitty @``
messaging system. This tutorial touches only the surface of what is possible.
See ``kitty @ --help`` for more details.
Note that in the example's above, ``kitty @`` messaging works only when run
In the example's above, ``kitty @`` messaging works only when run
inside a |kitty| window, not anywhere. But, within a |kitty| window it even
works over SSH. If you want to control |kitty| from programs/scripts not running
inside a |kitty| window, you have to implement a couple of extra steps. First
start |kitty| as::
inside a |kitty| window, see the section on :ref:`using a socket for remote control <rc_via_socket>`
below.
Note that if all you want to do is run a single |kitty| "daemon" and have
subsequent |kitty| invocations appear as new top-level windows, you can use the
simpler :option:`kitty --single-instance` option, see ``kitty --help`` for that.
.. _rc_via_socket:
Remote control via a socket
--------------------------------
First, start |kitty| as::
kitty -o allow_remote_control=yes --listen-on unix:/tmp/mykitty
@ -108,11 +121,6 @@ command line argument to ``kitty @``. For example::
kitty @ --to unix:/tmp/mykitty ls
Note that if all you want to do is run a single |kitty| "daemon" and have
subsequent |kitty| invocations appear as new top-level windows, you can use the
simpler :option:`kitty --single-instance` option, see ``kitty --help`` for that.
The builtin kitty shell
--------------------------
@ -148,6 +156,83 @@ other computers (for example, over SSH) or as other users.
kitty, as if you were running with :opt:`allow_remote_control` turned on.
Fine grained permissions for remote control
----------------------------------------------
The :opt:`allow_remote_control` option discussed so far is a blunt
instrument, granting the ability to any program running on your computer
or even on remote computers via SSH the ability to use remote control.
You can instead define remote control passwords that can be used to grant
different levels of control to different places. You can even write your
own script to decide which remote control requests are allowed. This is
done using the :opt:`remote_control_password` option in :file:`kitty.conf`.
Let's see some examples:
.. code-block:: conf
remote_control_password "control colors" get-colors set-colors
Now, using this password, you can, in scripts run the command::
kitty @ --password="control colors" set-colors background=red
Any script with access to the password can now change colors in kitty using
remote control, but only that and nothing else. You can even supply the
password via the :envvar:`KITTY_RC_PASSWORD` environment variable, or the
file :file:`~/.config/kitty/rc-password` to avoid having to type it repeatedly.
See :option:`kitty @ --password-file` and :option:`kitty @ --password-env`.
The :opt:`remote_control_password` can be specified multiple times to create
different passwords with different capabilities. Run the following to get a
list of all action names::
kitty @ -h
You can even use glob patterns to match action names, for example:
.. code-block:: conf
remote_control_password "control colors" *-colors
If no action names are specified, all actions are allowed.
If ``kitty @`` is run with a password that is not present in
:file:`kitty.conf`, then kitty will interactively prompt the user to allow or
disallow the remote control request. The user can choose to allow or disallow
either just that request or all requests using that password. The user's
decision is remembered for the duration of that kitty instance.
.. _rc_custom_auth:
Customizing authorization with your own program
____________________________________________________________
If the ability to control access by action names is not fine grained enough,
you can define your own Python script to examine every remote control command
and allow/disallow it. To do so create a file in the kitty configuration
directory, :file:`~/.config/kitty/my_rc_auth.py` and add the following
to :file:`kitty.conf`:
.. code-block:: conf
remote_control_password "testing custom auth" my_rc_auth.py
:file:`my_rc_auth.py` should define a :code:`is_cmd_allowed` function
as shown below:
.. code-block:: py
def is_cmd_allowed(pcmd, window, from_socket, extra_data):
cmd_name = pcmd['cmd'] # the name of the command
cmd_payload = pcmd['payload'] # the arguments to the command
# examine the cmd_name and cmd_payload and return True to allow
# the command or False to disallow it. Return None to have no
# effect on the command.
# The command payload will vary from command to command, see
# the rc protocol docs for details.
.. _rc_mapping:
Mapping key presses to remote control commands

View File

@ -55,6 +55,7 @@ def ref_map() -> Dict[str, str]:
'functional': f'{website_url("keyboard-protocol")}#functional-key-definitions',
'ssh_copy_command': f'{website_url("kittens/ssh")}#ssh-copy-command',
'shell_integration': website_url("shell-integration"),
'rc_custom_auth': f'{website_url("remote-control")}#rc-custom-auth',
'clone_shell': f'{website_url("shell-integration")}#clone-shell',
'github_discussions': 'https://github.com/kovidgoyal/kitty/discussions',
}

View File

@ -70,7 +70,7 @@ def parse_cmd(serialized_cmd: str, encryption_key: EllipticCurveKey) -> Dict[str
class CMDChecker:
def __call__(self, pcmd: Dict[str, Any], window: Optional['Window'], from_socket: bool, extra_data: Dict[str, Any]) -> bool:
def __call__(self, pcmd: Dict[str, Any], window: Optional['Window'], from_socket: bool, extra_data: Dict[str, Any]) -> Optional[bool]:
return False
@ -114,8 +114,15 @@ class PasswordAuthorizer:
if x.match(cmd_name) is not None:
return True
for f in self.function_checkers:
if f(pcmd, window, from_socket, extra_data):
return True
try:
ret = f(pcmd, window, from_socket, extra_data)
except Exception as e:
import traceback
traceback.print_exc()
log_error(f'There was an error using a custom RC auth function, blocking the remote command. Error: {e}')
ret = False
if ret is not None:
return ret
return False