Remote control: Allow matching for self window even over sockets when run inside a kitty window
Have kitty-tool send the value of KITTY_WINDOW_ID if present.
This commit is contained in:
parent
c18bff7821
commit
456af90ad2
@ -15,6 +15,7 @@ Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form:
|
|||||||
"cmd": "command name",
|
"cmd": "command name",
|
||||||
"version": "<kitty version>",
|
"version": "<kitty version>",
|
||||||
"no_response": "<Optional Boolean>",
|
"no_response": "<Optional Boolean>",
|
||||||
|
"kitty_window_id": "<Optional value of the KITTY_WINDOW_ID env var>",
|
||||||
"payload": "<Optional JSON object>"
|
"payload": "<Optional JSON object>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -505,6 +505,18 @@ class Boss:
|
|||||||
return response
|
return response
|
||||||
if not pcmd:
|
if not pcmd:
|
||||||
return response
|
return response
|
||||||
|
self_window: Optional[Window] = None
|
||||||
|
if window is not None:
|
||||||
|
self_window = window
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
swid = int(pcmd.get('kitty_window_id', 0))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if swid > 0:
|
||||||
|
self_window = self.window_id_map.get(swid)
|
||||||
|
|
||||||
extra_data: Dict[str, Any] = {}
|
extra_data: Dict[str, Any] = {}
|
||||||
try:
|
try:
|
||||||
allowed_unconditionally = (
|
allowed_unconditionally = (
|
||||||
@ -513,12 +525,12 @@ class Boss:
|
|||||||
except PermissionError:
|
except PermissionError:
|
||||||
return {'ok': False, 'error': 'Remote control disallowed by window specific password'}
|
return {'ok': False, 'error': 'Remote control disallowed by window specific password'}
|
||||||
if allowed_unconditionally:
|
if allowed_unconditionally:
|
||||||
return self._execute_remote_command(pcmd, window, peer_id)
|
return self._execute_remote_command(pcmd, window, peer_id, self_window)
|
||||||
q = is_cmd_allowed(pcmd, window, peer_id > 0, extra_data)
|
q = is_cmd_allowed(pcmd, window, peer_id > 0, extra_data)
|
||||||
if q is True:
|
if q is True:
|
||||||
return self._execute_remote_command(pcmd, window, peer_id)
|
return self._execute_remote_command(pcmd, window, peer_id, self_window)
|
||||||
if q is None:
|
if q is None:
|
||||||
if self.ask_if_remote_cmd_is_allowed(pcmd, window, peer_id):
|
if self.ask_if_remote_cmd_is_allowed(pcmd, window, peer_id, self_window):
|
||||||
return AsyncResponse()
|
return AsyncResponse()
|
||||||
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'}
|
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'}
|
||||||
if q is False and pcmd.get('password'):
|
if q is False and pcmd.get('password'):
|
||||||
@ -528,7 +540,9 @@ class Boss:
|
|||||||
return None
|
return None
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def ask_if_remote_cmd_is_allowed(self, pcmd: Dict[str, Any], window: Optional[Window] = None, peer_id: int = 0) -> bool:
|
def ask_if_remote_cmd_is_allowed(
|
||||||
|
self, pcmd: Dict[str, Any], window: Optional[Window] = None, peer_id: int = 0, self_window: Optional[Window] = None
|
||||||
|
) -> bool:
|
||||||
from kittens.tui.operations import styled
|
from kittens.tui.operations import styled
|
||||||
in_flight = 0
|
in_flight = 0
|
||||||
for w in self.window_id_map.values():
|
for w in self.window_id_map.values():
|
||||||
@ -547,7 +561,7 @@ class Boss:
|
|||||||
'\x1b[m' + styled(_(
|
'\x1b[m' + styled(_(
|
||||||
'Note that allowing the password will allow all future actions using the same password, in this kitty instance.'
|
'Note that allowing the password will allow all future actions using the same password, in this kitty instance.'
|
||||||
), dim=True, italic=True)),
|
), dim=True, italic=True)),
|
||||||
partial(self.remote_cmd_permission_received, pcmd, wid, peer_id),
|
partial(self.remote_cmd_permission_received, pcmd, wid, peer_id, self_window),
|
||||||
'a;green:Allow request', 'p;yellow:Allow password', 'r;magenta:Deny request', 'd;red:Deny password',
|
'a;green:Allow request', 'p;yellow:Allow password', 'r;magenta:Deny request', 'd;red:Deny password',
|
||||||
window=window, default='a', hidden_text=hidden_text
|
window=window, default='a', hidden_text=hidden_text
|
||||||
)
|
)
|
||||||
@ -556,7 +570,7 @@ class Boss:
|
|||||||
overlay_window.window_custom_type = 'remote_command_permission_dialog'
|
overlay_window.window_custom_type = 'remote_command_permission_dialog'
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def remote_cmd_permission_received(self, pcmd: Dict[str, Any], window_id: int, peer_id: int, choice: str) -> None:
|
def remote_cmd_permission_received(self, pcmd: Dict[str, Any], window_id: int, peer_id: int, self_window: Optional[Window], choice: str) -> None:
|
||||||
from .remote_control import encode_response_for_peer, set_user_password_allowed
|
from .remote_control import encode_response_for_peer, set_user_password_allowed
|
||||||
response: RCResponse = None
|
response: RCResponse = None
|
||||||
window = self.window_id_map.get(window_id)
|
window = self.window_id_map.get(window_id)
|
||||||
@ -570,7 +584,7 @@ class Boss:
|
|||||||
elif choice in ('a', 'p'):
|
elif choice in ('a', 'p'):
|
||||||
if choice == 'p':
|
if choice == 'p':
|
||||||
set_user_password_allowed(pcmd['password'], True)
|
set_user_password_allowed(pcmd['password'], True)
|
||||||
response = self._execute_remote_command(pcmd, window, peer_id)
|
response = self._execute_remote_command(pcmd, window, peer_id, self_window)
|
||||||
if window is not None and response is not None and not isinstance(response, AsyncResponse):
|
if window is not None and response is not None and not isinstance(response, AsyncResponse):
|
||||||
window.send_cmd_response(response)
|
window.send_cmd_response(response)
|
||||||
if peer_id > 0:
|
if peer_id > 0:
|
||||||
@ -579,10 +593,12 @@ class Boss:
|
|||||||
elif not isinstance(response, AsyncResponse):
|
elif not isinstance(response, AsyncResponse):
|
||||||
send_data_to_peer(peer_id, encode_response_for_peer(response))
|
send_data_to_peer(peer_id, encode_response_for_peer(response))
|
||||||
|
|
||||||
def _execute_remote_command(self, pcmd: Dict[str, Any], window: Optional[Window] = None, peer_id: int = 0) -> RCResponse:
|
def _execute_remote_command(
|
||||||
|
self, pcmd: Dict[str, Any], window: Optional[Window] = None, peer_id: int = 0, self_window: Optional[Window] = None
|
||||||
|
) -> RCResponse:
|
||||||
from .remote_control import handle_cmd
|
from .remote_control import handle_cmd
|
||||||
try:
|
try:
|
||||||
response = handle_cmd(self, window, pcmd, peer_id)
|
response = handle_cmd(self, window, pcmd, peer_id, self_window)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
import traceback
|
import traceback
|
||||||
response = {'ok': False, 'error': str(err)}
|
response = {'ok': False, 'error': str(err)}
|
||||||
|
|||||||
@ -169,7 +169,9 @@ def close_active_stream(stream_id: str) -> None:
|
|||||||
active_streams.pop(stream_id, None)
|
active_streams.pop(stream_id, None)
|
||||||
|
|
||||||
|
|
||||||
def handle_cmd(boss: BossType, window: Optional[WindowType], cmd: Dict[str, Any], peer_id: int) -> Union[Dict[str, Any], None, AsyncResponse]:
|
def handle_cmd(
|
||||||
|
boss: BossType, window: Optional[WindowType], cmd: Dict[str, Any], peer_id: int, self_window: Optional[WindowType]
|
||||||
|
) -> Union[Dict[str, Any], None, AsyncResponse]:
|
||||||
v = cmd['version']
|
v = cmd['version']
|
||||||
no_response = cmd.get('no_response', False)
|
no_response = cmd.get('no_response', False)
|
||||||
if tuple(v)[:2] > version[:2]:
|
if tuple(v)[:2] > version[:2]:
|
||||||
@ -194,14 +196,14 @@ def handle_cmd(boss: BossType, window: Optional[WindowType], cmd: Dict[str, Any]
|
|||||||
payload['async_id'] = async_id
|
payload['async_id'] = async_id
|
||||||
if 'cancel_async' in cmd:
|
if 'cancel_async' in cmd:
|
||||||
active_async_requests.pop(async_id, None)
|
active_async_requests.pop(async_id, None)
|
||||||
c.cancel_async_request(boss, window, PayloadGetter(c, payload))
|
c.cancel_async_request(boss, self_window or window, PayloadGetter(c, payload))
|
||||||
return None
|
return None
|
||||||
active_async_requests[async_id] = monotonic()
|
active_async_requests[async_id] = monotonic()
|
||||||
if len(active_async_requests) > 32:
|
if len(active_async_requests) > 32:
|
||||||
oldest = next(iter(active_async_requests))
|
oldest = next(iter(active_async_requests))
|
||||||
del active_async_requests[oldest]
|
del active_async_requests[oldest]
|
||||||
try:
|
try:
|
||||||
ans = c.response_from_kitty(boss, window, PayloadGetter(c, payload))
|
ans = c.response_from_kitty(boss, self_window or window, PayloadGetter(c, payload))
|
||||||
except Exception:
|
except Exception:
|
||||||
if no_response: # don't report errors if --no-response was used
|
if no_response: # don't report errors if --no-response was used
|
||||||
return None
|
return None
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
@ -268,6 +269,10 @@ func send_rc_command(io_data *rc_io_data) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
wid, err := strconv.Atoi(os.Getenv("KITTY_WINDOW_ID"))
|
||||||
|
if err == nil && wid > 0 {
|
||||||
|
io_data.rc.KittyWindowId = uint(wid)
|
||||||
|
}
|
||||||
err = create_serializer(global_options.password, "", io_data)
|
err = create_serializer(global_options.password, "", io_data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -3,16 +3,17 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
type RemoteControlCmd struct {
|
type RemoteControlCmd struct {
|
||||||
Cmd string `json:"cmd"`
|
Cmd string `json:"cmd"`
|
||||||
Version [3]int `json:"version"`
|
Version [3]int `json:"version"`
|
||||||
NoResponse bool `json:"no_response,omitempty"`
|
NoResponse bool `json:"no_response,omitempty"`
|
||||||
Timestamp int64 `json:"timestamp,omitempty"`
|
Timestamp int64 `json:"timestamp,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Async string `json:"async,omitempty"`
|
Async string `json:"async,omitempty"`
|
||||||
CancelAsync bool `json:"cancel_async,omitempty"`
|
CancelAsync bool `json:"cancel_async,omitempty"`
|
||||||
Stream bool `json:"stream,omitempty"`
|
Stream bool `json:"stream,omitempty"`
|
||||||
StreamId string `json:"stream_id,omitempty"`
|
StreamId string `json:"stream_id,omitempty"`
|
||||||
Payload any `json:"payload,omitempty"`
|
KittyWindowId uint `json:"kitty_window_id,omitempty"`
|
||||||
|
Payload any `json:"payload,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EncryptedRemoteControlCmd struct {
|
type EncryptedRemoteControlCmd struct {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user