More work on ssh bootstrap

This commit is contained in:
Kovid Goyal
2022-02-21 10:50:39 +05:30
parent cf01480ec8
commit 2dd7c3b939
5 changed files with 119 additions and 4 deletions

View File

@@ -1,16 +1,37 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import io
import os import os
import shlex import shlex
import subprocess import subprocess
import sys import sys
import tarfile
from contextlib import suppress from contextlib import suppress
from typing import List, NoReturn, Optional, Set, Tuple from typing import List, NoReturn, Optional, Set, Tuple
from .completion import ssh_options, complete
from kitty.constants import shell_integration_dir, terminfo_dir
from kitty.utils import SSHConnectionData from kitty.utils import SSHConnectionData
from .completion import complete, ssh_options
def make_tarfile() -> bytes:
def filter_files(tarinfo: tarfile.TarInfo) -> Optional[tarfile.TarInfo]:
if tarinfo.name.endswith('ssh/bootstrap.sh'):
return None
tarinfo.uname = tarinfo.gname = 'kitty'
tarinfo.uid = tarinfo.gid = 0
return tarinfo
buf = io.BytesIO()
with tarfile.open(mode='w:bz2', fileobj=buf, encoding='utf-8') as tf:
tf.add(shell_integration_dir, arcname='.local/share/kitty-ssh-kitten/shell-integration', filter=filter_files)
tf.add(terminfo_dir, arcname='.terminfo', filter=filter_files)
return buf.getvalue()
SHELL_SCRIPT = '''\ SHELL_SCRIPT = '''\
#!/bin/sh #!/bin/sh
# macOS ships with an ancient version of tic that cannot read from stdin, so we # macOS ships with an ancient version of tic that cannot read from stdin, so we

View File

@@ -2106,9 +2106,7 @@ screen_handle_print(Screen *self, PyObject *msg) {
void void
screen_handle_echo(Screen *self, PyObject *msg) { screen_handle_echo(Screen *self, PyObject *msg) {
Py_ssize_t sz; CALLBACK("handle_remote_echo", "O", msg);
const char *bytes = PyUnicode_AsUTF8AndSize(msg, &sz);
write_to_child(self, bytes, sz);
} }
void void

View File

@@ -875,6 +875,11 @@ class Window:
def handle_remote_cmd(self, cmd: str) -> None: def handle_remote_cmd(self, cmd: str) -> None:
get_boss().handle_remote_cmd(cmd, self) get_boss().handle_remote_cmd(cmd, self)
def handle_remote_echo(self, msg: bytes) -> None:
from base64 import standard_b64decode
data = standard_b64decode(msg)
self.write_to_child(data)
def handle_remote_print(self, msg: bytes) -> None: def handle_remote_print(self, msg: bytes) -> None:
text = process_remote_print(msg) text = process_remote_print(msg)
print(text, end='', file=sys.stderr) print(text, end='', file=sys.stderr)

View File

@@ -3,6 +3,8 @@
import os import os
import shutil
import tempfile
from kittens.ssh.main import get_connection_data from kittens.ssh.main import get_connection_data
from kitty.utils import SSHConnectionData from kitty.utils import SSHConnectionData
@@ -35,3 +37,13 @@ print(' '.join(map(str, buf)))'''), lines=13, cols=77)
t('ssh un@ip -i ident -p34', host='un@ip', port=34, identity_file='ident') t('ssh un@ip -i ident -p34', host='un@ip', port=34, identity_file='ident')
t('ssh un@ip -iident -p34', host='un@ip', port=34, identity_file='ident') t('ssh un@ip -iident -p34', host='un@ip', port=34, identity_file='ident')
t('ssh -p 33 main', port=33) t('ssh -p 33 main', port=33)
def test_ssh_launcher_script(self):
for sh in ('sh', 'zsh', 'bash', 'dash'):
q = shutil.which(sh)
if q:
with self.subTest(sh=sh), tempfile.TemporaryDirectory() as tdir:
self.run_launcher(sh, tdir)
def run_launcher(self, sh, tdir):
pass

View File

@@ -0,0 +1,79 @@
#!/bin/sh
# Copyright (C) 2022 Kovid Goyal <kovid at kovidgoyal.net>
# Distributed under terms of the GPLv3 license.
# read the transmitted data from STDIN
saved_tty_settings=$(command stty -g)
command stty -echo
encoded_data_file=$(mktemp)
cleanup_on_bootstrap_exit() {
[[ ! -z "$encoded_data_file" ]] && command rm -f "$encoded_data_file"
[[ ! -z "$saved_tty_settings" ]] && command stty "$saved_tty_settings"
}
trap 'cleanup_on_bootstrap_exit' EXIT
data_started="n"
data_complete="n"
pending_data=""
if [[ -z "$HOSTNAME" ]]; then
hostname=$(hostname)
if [[ -z "$hostname" ]]; then hostname="_"; fi
else
hostname=$(HOSTNAME)
fi
# ask for the SSH data
data_password="DATA_PASSWORD"
password_filename="PASSWORD_FILENAME"
printf "\eP@kitty-ssh|$password_filename:$data_password:$hostname\e\\"
while IFS= read -r line; do
case "$line" in
*"KITTY_SSH_DATA_START")
prefix=$(command expr "$line" : "\(.*\)KITTY_SSH_DATA_START")
pending_data="$pending_data$prefix"
data_started="y";
;;
"KITTY_SSH_DATA_END")
data_complete="y";
;;
*)
if [[ "$data_started" == "y" ]]; then
echo -n "$line" >> "$encoded_data_file"
else
pending_data="$pending_data$line\n"
fi
;;
esac
if [[ "$data_complete" == "y" ]]; then break; fi
done
command stty "$saved_tty_settings"
saved_tty_settings=""
if [[ ! -z "$pending_data" ]]; then
printf "\eP@kitty-echo|$(echo -n "$pending_data" | base64)\e\\"
fi
command base64 -d < "$encoded_data_file" | command tar xjf - --no-same-owner
rc=$?
command rm -f "$encoded_data_file"
encoded_data_file=""
if [ "$rc" != "0" ]; then echo "Failed to extract data transmitted by ssh kitten over the TTY device" > /dev/stderr; exit 1; fi
# compile terminfo for this system
if [ -x "$(command -v tic)" ]; then
tname=".terminfo"
if [ -e "/usr/share/misc/terminfo.cdb" ]; then
# NetBSD requires this see https://github.com/kovidgoyal/kitty/issues/4622
tname=".terminfo.cdb"
fi
tic_out=$(command tic -x -o "$HOME/$tname" ".terminfo/kitty.terminfo" 2>&1)
rc=$?
if [ "$rc" != "0" ]; then echo "$tic_out"; exit 1; fi
export TERMINFO="$HOME/$tname"
fi
# If a command was passed to SSH execute it here
EXEC_CMD
# ensure $USER is set
if [ -z "$USER" ]; then export USER=$(whoami); fi