rc_protocol.rst 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. The kitty remote control protocol
  2. ==================================
  3. The kitty remote control protocol is a simple protocol that involves sending
  4. data to kitty in the form of JSON. Any individual command of kitty has the
  5. form::
  6. <ESC>P@kitty-cmd<JSON object><ESC>\
  7. Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form:
  8. .. code-block:: json
  9. {
  10. "cmd": "command name",
  11. "version": "<kitty version>",
  12. "no_response": "<Optional Boolean>",
  13. "kitty_window_id": "<Optional value of the KITTY_WINDOW_ID env var>",
  14. "payload": "<Optional JSON object>"
  15. }
  16. The ``version`` above is an array of the form :code:`[0, 14, 2]`. If you are
  17. developing a standalone client, use the kitty version that you are developing
  18. against. Using a version greater than the version of the kitty instance you are
  19. talking to, will cause a failure.
  20. Set ``no_response`` to ``true`` if you don't want a response from kitty.
  21. The optional payload is a JSON object that is specific to the actual command
  22. being sent. The fields in the object for every command are documented below.
  23. As a quick example showing how easy to use this protocol is, we will implement
  24. the ``@ ls`` command from the shell using only shell tools.
  25. First, run kitty as::
  26. kitty -o allow_remote_control=socket-only --listen-on unix:/tmp/test
  27. Now, in a different terminal, you can get the pretty printed ``@ ls`` output
  28. with the following command line::
  29. echo -en '\eP@kitty-cmd{"cmd":"ls","version":[0,14,2]}\e\\' | socat - unix:/tmp/test | awk '{ print substr($0, 13, length($0) - 14) }' | jq -c '.data | fromjson' | jq .
  30. There is also the statically compiled stand-alone executable ``kitten``
  31. that can be used for this, available from the `kitty releases
  32. <https://github.com/kovidgoyal/kitty/releases>`__ page::
  33. kitten @ --help
  34. .. _rc_crypto:
  35. Encrypted communication
  36. --------------------------
  37. .. versionadded:: 0.26.0
  38. When using the :opt:`remote_control_password` option communication to the
  39. terminal is encrypted to keep the password secure. A public key is used from
  40. the :envvar:`KITTY_PUBLIC_KEY` environment variable. Currently, only one
  41. encryption protocol is supported. The protocol number is present in
  42. :envvar:`KITTY_PUBLIC_KEY` as ``1``. The key data in this environment variable
  43. is :rfc:`Base-85 <1924>` encoded. The algorithm used is `Elliptic Curve Diffie
  44. Helman <https://en.wikipedia.org/wiki/Elliptic-curve_Diffie–Hellman>`__ with
  45. the `X25519 curve <https://en.wikipedia.org/wiki/Curve25519>`__. A time based
  46. nonce is used to minimise replay attacks. The original JSON command has the
  47. fields: ``password`` and ``timestamp`` added. The timestamp is the number of
  48. nanoseconds since the epoch, excluding leap seconds. Commands with a timestamp
  49. more than 5 minutes from the current time are rejected. The command is then
  50. encrypted using AES-256-GCM in authenticated encryption mode, with a symmetric
  51. key that is derived from the ECDH key-pair by running the shared secret through
  52. SHA-256 hashing, once. An IV of at least 96 bits of CSPRNG data is used. The
  53. tag for authenticated encryption **must** be at least 128 bits long. The tag
  54. **must** authenticate only the value of the ``encrypted`` field. A new command
  55. is created and transmitted that contains the fields:
  56. .. code-block:: json
  57. {
  58. "version": "<kitty version>",
  59. "iv": "base85 encoded IV",
  60. "tag": "base85 encoded AEAD tag",
  61. "pubkey": "base85 encoded ECDH public key of sender",
  62. "encrypted": "The original command encrypted and base85 encoded"
  63. }
  64. Async and streaming requests
  65. ---------------------------------
  66. Some remote control commands require asynchronous communication, that is, the
  67. response from the terminal can happen after an arbitrary amount of time. For
  68. example, the :code:`select-window` command requires the user to select a window
  69. before a response can be sent. Such command must set the field :code:`async`
  70. in the JSON block above to a random string that serves as a unique id. The
  71. client can cancel an async request in flight by adding the :code:`cancel_async`
  72. field to the JSON block. A async response remains in flight until the terminal
  73. sends a response to the request. Note that cancellation requests dont need to
  74. be encrypted as users must not be prompted for these and the worst a malicious
  75. cancellation request can do is prevent another sync request from getting a
  76. response.
  77. Similar to async requests are *streaming* requests. In these the client has to
  78. send a large amount of data to the terminal and so the request is split into
  79. chunks. In every chunk the JSON block must contain the field ``stream`` set to
  80. ``true`` and ``stream_id`` set to a random long string, that should be the same for
  81. all chunks in a request. End of data is indicated by sending a chunk with no data.
  82. .. include:: generated/rc.rst