Releases: DeveloperrEva/conchshell
Release list
Conchshell 2.10.1
Download the .dmg for macOS (pick aarch64 for Apple Silicon,
x64 for Intel), the .msi or .exe for Windows, or the
.AppImage / .deb / .rpm for Linux.
Auto-updater artifacts (latest.json, *.sig) are included.
What changed: see CHANGES.md.
Conchshell 2.10.0
Download the .dmg for macOS (pick aarch64 for Apple Silicon,
x64 for Intel), the .msi or .exe for Windows, or the
.AppImage / .deb / .rpm for Linux.
Auto-updater artifacts (latest.json, *.sig) are included.
What changed: see CHANGES.md.
Conchshell 2.9.1 (macOS + Linux)
Conchshell для macOS (Apple Silicon) и Linux.
Скачивайте .dmg (macOS) либо .AppImage / .deb (Linux). Артефакты автообновления (latest.json, *.sig) приложены.
Главное: пароли больше не лежат открытым текстом
До этой версии сохранённые пароли, ключевые фразы и учётные данные прокси и jump-хостов хранились в localStorage — обычным текстом, в файле внутри каталога приложения. Их читал любой процесс от вашего имени, они уезжали в любой бэкап и находились обычным grep.
Теперь при первом запуске появляется мастер, который переносит их в зашифрованное хранилище: XChaCha20-Poly1305, ключ через Argon2id, отдельные независимые слоты ключей. Перенос идёт по схеме «записать → прочитать обратно с диска → сверить → только потом стереть открытую копию», поэтому сбой на любом шаге не может уничтожить единственный экземпляр пароля.
Команды чтения секрета не существует. Фронтенд может положить пароль в хранилище и удалить его, но получить обратно — нет. Учётные данные читает только Rust, в момент подключения. Скомпрометированное окно приложения не может выгрузить хранилище через IPC.
Мастер-пароль не нужен. Хранилище открывается ключом из keychain macOS, без запросов при запуске. Если хотите более строгий режим — «Настройки → Безопасность → Спрашивать мастер-пароль при запуске»; тогда хранилище остаётся запертым, пока вы не введёте пароль, и это защищает его и от всего, что работает на машине до первой разблокировки. Оба способа — независимые обёртки одного ключа, так что переключение туда-обратно ничего не перешифровывает и не обесценивает уже записанный пароль.
Честно о границах: ключ в обычном keychain читается любым процессом, работающим от вашего имени. То есть хранилище защищено настолько же, насколько ваша учётная запись macOS. Бэкап одного файла хранилища бесполезен — ключа в нём нет; бэкап вместе с login.keychain-db отдаёт ключ тому, у кого есть ваш пароль входа. Подробности — docs/vault-format.md, раздел 2.5.1.
Закрытые уязвимости
Три отдельных прохода аудита, каждая находка проверялась независимым агентом с задачей её опровергнуть.
Враждебный SSH-сервер мог записать файл в любое место диска. Вкладка «Files» получала листинг, разбирая вывод ls -la, и отбрасывала только строки . и ... Имя вида ../../../../.zshrc проходило и склеивалось с папкой, выбранной для загрузки, — содержимое тоже выбирал сервер. Дальше ~/.zshrc или ~/.ssh/authorized_keys и выполнение кода при следующем входе. Закрыто с трёх сторон, включая проверку в самой команде скачивания.
Терминал отвечал на запрос чтения буфера обмена. Последовательность OSC 52 ; c ; ? заставляла приложение прочитать системный буфер и отправить его обратно в stdin того же сервера. Для SSH-клиента со встроенным хранилищем это прямой способ увести пароль или ключ; ответ уходил как ввод, поэтому в raw-режиме на экране не появлялось ничего. Чтение теперь запрещено безусловно, настройки для него нет. Запись оставлена и включена по умолчанию — она нужна, например, чтобы копировать из vim через SSH.
Одно окно могло управлять сессиями другого. Аутентификация канала не мешала одному сокету писать в чужой терминал, менять его размер и получать его вывод. Теперь сообщение к живой сессии принимается только от сокета, который её создал.
Импорт known_hosts терял отзыв ключа. Строка @revoked * <ключ> — стандартный способ отозвать ключ везде — не разбиралась, и отозванный отпечаток мог попасть в доверенные, после чего соединение проходило вообще без вопросов.
Отключение соединений не работало. Двенадцать вызовов передавали аргументы в неверном регистре, команда их не находила и отклоняла — молча, потому что ошибку никто не показывал. Так не работали отключение SSH/SFTP/FTP и кнопка отмены подключения.
FTPS теперь закрепляет ключ сервера через тот же механизм, что SSH и RDP: первое подключение спрашивает доверие, изменившийся ключ — отказ. Заодно вернулась поддержка самоподписанных сертификатов, которых для FTPS большинство.
Новое
- Выбор программы для открытия файлов. В редакторе появилось меню: открыть в системной программе по умолчанию, выбрать конкретную и запомнить её, забыть выбранную. Встроенный редактор остаётся значением по умолчанию для всего, что умеет показать.
- Управление хранилищем в настройках — состояние, кнопка «Запереть», переключатель мастер-пароля.
Исправления
- Мигрированное соединение нельзя было открыть из диалога: он требовал пароль в поле, которое миграция намеренно опустошила.
- Правка пароля стирала сохранённые пароли прокси и jump-хоста.
- Восстановление сессии стартовало при запертом хранилище, из-за чего все соединения падали при запуске.
- Пароль прокси для RDP не доставался из хранилища.
- Вкладка «Безопасность» состояла из трёх переключателей, не подключённых ни к чему. Опаснее прочих был «Host Key Verification»: он выглядел выключаемым, тогда как проверка ключа безусловна. Заменено на честный статус.
- Импорт конфигурации по умолчанию заменял все соединения без предупреждения. Теперь по умолчанию объединение, а замена требует подтверждения с числом удаляемых записей.
- Русские формы множественного числа существовали только для 1 и «многих», поэтому любое число от 2 до 20 показывалось по-английски. Добавлены недостающие формы, проверка покрытия переписана по категориям
Intl.PluralRules. - Поправлена вёрстка в настройках: заголовок строки и надпись на кнопке использовали одну и ту же длинную строку.
Важно при обновлении
Это переходная версия смены ключа подписи обновлений. Сборки несут новый публичный ключ, но подписаны старым, потому что установленный клиент проверяет подпись тем ключом, который вкомпилирован в него самого. Обновление с 2.9.0 пройдёт штатно.
Ключ подписи в CI нельзя переключать на новый, пока эта версия не разойдётся, — иначе обновления оборвутся у всех, кто ещё на 2.9.0.
Что осталось открытым
Чтобы не создавать ложного впечатления. Команды Tauri не разграничены по правам: любое окно может вызвать любую команду по чужому идентификатору соединения, а решение о доверии к ключу сервера принимает сторона окна. Не проверялись аудитом: слой VNC, разбор протоколов SFTP/FTP и механизм самообновления целиком. Сборки под Windows не выпускаются и этот путь не проверялся.
Полный список изменений — CHANGES.md.
Conchshell 2.9.0 — релиз безопасности (обновитесь как можно скорее)
🔐 2.9.0 — обновитесь как можно скорее
Это релиз безопасности. Проведён аудит всего приложения по семи поверхностям атаки; найденное исправлено. Одна из находок — критическая.
🔴 Критично: удалённое выполнение кода
r-shell слушал локальный порт (9001) для связи терминала с бэкендом и принимал любое соединение — без пароля, без проверки, кто подключается. А команда «запусти локальный терминал» не требовала никаких условий: она сразу запускала вашу оболочку.
Из-за того, что WebSocket не подчиняется обычным правилам изоляции сайтов, подключиться мог не только другой процесс на вашем компьютере, но и любая веб-страница, которую вы открыли в браузере. То есть простое посещение сайта могло дать чужому коду полноценную командную строку от вашего имени — а дальше: пароли серверов (они пока хранятся открыто), ключи из ~/.ssh, подмена доверенных ключей серверов.
Исправлено: канал теперь требует секретный токен, который создаётся при каждом запуске и передаётся только самому приложению. Веб-страница получить его не может.
Остальное исправленное
- Внедрение команд. Шесть операций с файлами и логами подставляли пути в команды без экранирования. Для одной из них путь приходит от самого сервера — достаточно было создать на нём файл с апострофом в имени, чтобы выполнить произвольную команду.
- Выход за пределы папки при скачивании. Вредоносный SFTP/FTP-сервер мог подсунуть в списке файлов имя вида
../../../.zshrcи при скачивании папки записать файл куда угодно на вашем диске. - FTPS принимал любой сертификат. Соединение шифровалось, но не проверялось — то есть любой, кто может вклиниться в сеть, читал ваш пароль FTP. Теперь сертификат проверяется. Если ваш FTPS-сервер с самоподписанным сертификатом — подключение будет отклонено с понятным объяснением; это сделано намеренно.
- Нажатия клавиш попадали в лог. При включённом отладочном логировании в файл писалось всё, что вы набирали, — включая пароль, введённый в
sudo. - Пароль FTP в логах — закрыто.
- Временные файлы редактора (при «Открыть в VS Code») создавались доступными для чтения всем локальным пользователям. Теперь только для вас.
Что стоит сделать
Если вы пользуетесь r-shell на компьютере, к которому имеют доступ другие люди, или часто открываете браузер параллельно с работой — смените пароли серверов после обновления. Уязвимость существовала во всех предыдущих версиях, и следов её эксплуатации приложение не сохраняет.
🔒 Зашифрованное хранилище паролей — готово ядро
Пароли пока по-прежнему хранятся открыто, но в этой версии готова вся основа для их шифрования: формат хранилища, шифрование, атомарная запись, парольная фраза, миграция и резолв паролей на стороне Rust. Ключевое решение: команды «выдай пароль» не существует вовсе — даже скомпрометированный интерфейс не сможет их выгрузить. Включение по умолчанию — в следующем релизе.
📦 Установка
macOS (Apple Silicon): скачайте .dmg. Если Gatekeeper ругается:
xattr -dr com.apple.quarantine /Applications/r-shell.app
Linux (x86_64): .AppImage, .deb или .rpm.
Установленная версия обновится сама.
Conchshell 2.8.2 — экспорт настроек больше не выносит пароли открытым текстом
🔒 Что нового в 2.8.2 — исправление утечки при экспорте настроек
Экспорт конфигурации больше не записывает пароли в открытый файл.
Раньше «Экспорт настроек» складывал в обычный JSON-файл все учётные данные как есть: пароли подключений, парольные фразы ключей, пароли VNC, прокси и jump-хостов, а из профилей — даже само тело приватного ключа. Такой файл обычно попадает в облачную синхронизацию, Time Machine или общую папку — то есть пароли реально утекали в открытом виде.
Теперь при экспорте все учётные данные вырезаются, а после сохранения приложение честно сообщает, что секреты исключены и их нужно ввести заново после импорта. Импорт не изменился: файл, экспортированный старой версией, по-прежнему импортируется.
⚠️ Что стоит сделать вам
Если вы раньше пользовались экспортом настроек — старые файлы r-shell-config-*.json содержат пароли открытым текстом. Найдите и удалите их (проверьте облако и резервные копии). Помните: удаление файла не стирает его из снапшотов и бэкапов, поэтому самое надёжное — сменить пароли, которые могли попасть в такой экспорт.
Честно о границах
Это исправление закрывает утечку через файл экспорта. Сами пароли в приложении пока по-прежнему хранятся в открытом виде в локальном хранилище — это следующая большая задача. В этом релизе появился документ docs/vault-format.md — готовая к реализации спецификация зашифрованного хранилища учётных данных (один ключ данных, отдельные слоты для прозрачной разблокировки через системную связку ключей и для переносимой парольной фразы Argon2id, атомарный формат файла, защита синхронизации от отката, миграция и честная модель угроз).
📦 Установка
macOS (Apple Silicon): скачай .dmg, перетащи r-shell в Applications. Если Gatekeeper ругается:
xattr -dr com.apple.quarantine /Applications/r-shell.app
Linux (x86_64): .AppImage (сделать исполняемым и запустить), либо .deb / .rpm.
Уже установленная версия подтянет обновление сама через встроенный автоапдейтер.
Conchshell 2.8.1 (macOS + Linux)
Исправление к 2.8.0 — все возможности той версии плюс починенный запрос доверия к серверу. Ставить стоит именно эту.
Запрос доверия открывался частью за экраном
В 2.8.0 окно с отпечатком сервера появлялось смещённым вверх: заголовок, адрес и порт оказывались срезаны, а при высоком содержимом прокрутка до них не добиралась. Причин было две, и обе устранены.
Окно центрировалось сдвигом на половину собственной высоты. Пока содержимое ниже экрана, это выглядит как центр; как только выше — верхняя половина уходит за край, и прокрутить к ней нельзя, потому что переполняется не окно, а экран. Теперь центрирование идёт по рамке окна и не зависит от объёма содержимого.
Вторая причина тоньше. Фокус при открытии намеренно ставится на кнопку отказа, чтобы случайное нажатие Enter не подтвердило доверие к незнакомому серверу. Но кнопка находится внизу, и браузер прокручивал к ней содержимое — заголовок с адресом уезжал раньше, чем его можно было прочитать. Теперь фокус ставится без прокрутки.
Обе особенности закреплены тестами: невидимое или прокрученное окно — ровно тот случай, который не заметит ни одна другая проверка.
Conchshell 2.8.0 (macOS + Linux)
Проксирование работает по-настоящему
Вкладка «Proxy» в диалоге подключения — с выбором HTTP/SOCKS4/SOCKS5, полями хоста, порта и учётных данных, переведённая на три языка — до сих пор была декорацией: введённые значения никогда не покидали интерфейс, не сохранялись и не доходили до сети. Слово «proxy» не встречалось ни в одной исполняемой строке серверной части.
Теперь поддерживаются SOCKS5, SOCKS4, SOCKS4a и HTTP CONNECT — для SSH, SFTP и RDP одинаково. Это стало возможно потому, что все соединения приложения теперь открываются через один общий транспорт; заодно исчезла третья копия кода подключения, из-за расхождения которых раньше ломалась авторизация SFTP по ключу.
Прямого подключения в обход прокси не бывает. Если прокси настроен, но недоступен — соединение не состоится, и в сообщении будет сказано, что молчит именно прокси, а не сервер. Это принципиально: тихий откат на прямое соединение означал бы, что вы считаете трафик проксированным, когда он идёт напрямую. Протоколы, которые маршрут не поддерживают (FTP, VNC), отказываются, а не игнорируют настройку.
Ошибки называют участок пути: не дозвонились до прокси, прокси отверг учётные данные (и это именно его учётные данные, а не сервера), прокси отказался соединять с целью.
Промежуточный хост для SSH
Появился jump host: вход на промежуточный сервер и оттуда — на целевой. Промежуточный хост проверяется тем же хранилищем отпечатков и под собственным ключом, то есть на одно подключение приходится два независимых решения о доверии. Проверяется он до того, как к целевому серверу уйдут любые учётные данные.
Если заданы и прокси, и промежуточный хост, прокси используется для связи с промежуточным.
Что нашли при проверке
Проверка велась через настоящие прокси-серверы, а не через собственные заглушки, и нашла две вещи, каждая из которых обесценила бы функцию:
- Библиотека SSH записывает буфер аутентификации в лог до шифрования, поэтому при включённом отладочном логировании пароль и пароль промежуточного хоста попадали в журнал открытым текстом.
- Неизвестный тип прокси считался отсутствием прокси — то есть подключением напрямую. Сработать это могло от опечатки в импортированном конфиге или от
socks4a, который серверная часть умеет, а список интерфейса ещё нет. Теперь это отказ с объяснением.
Тесты: Rust 569, интерфейс 1019.
Conchshell 2.7.0 (macOS + Linux)
RDP в отдельном окне
Сессия открывается собственным окном системы, а не только вкладкой. Вкладка остаётся «ручкой» сессии — через неё работают восстановление, статус в дереве подключений и ⌘W. Закрытие окна закрывает сессию; захват клавиатуры следует за окном и не отбирает сочетания у главного.
Перенос файлов по SFTP наконец работает
Три из четырёх способов начать копирование молча ничего не делали:
- Правый клик по файлу → «Загрузить на сервер» срабатывал только если строку до этого выделили левым кликом: меню читало выделение, а правый клик его не создаёт.
- Выбор папки и кнопка «→» отваливались до показа уведомления — папки отфильтровывались, и функция выходила молча.
- Перетаскивание между панелями не работало в принципе: Tauri перехватывает событие раньше страницы. При этом панель подсвечивалась «перетащите сюда», обещая приём. Теперь переписано на pointer-события — тем же способом, каким в приложении уже перетаскиваются вкладки.
Добавлены уведомления об успехе и об ошибке с читаемой причиной: раньше ошибка была видна только обрезанной строкой в свёрнутой панели очереди. Папка в выборке теперь объясняет, что делать, вместо тишины.
Отдельно в клиенте: загрузка не закрывала удалённый файл, поэтому ошибка, которую сервер сообщает при закрытии, отбрасывалась и перенос всегда считался успешным.
Вкладка «Proxy» больше не вводит в заблуждение
Проксирование не реализовано ни для одного протокола — ни SSH, ни SFTP, ни RDP, ни VNC, ни FTP. При этом вкладка с выбором HTTP/SOCKS4/SOCKS5 выглядела рабочей: введённые значения никогда не покидали интерфейс. Поля убраны, на их месте объяснение; значения, сохранённые прошлыми сборками, вычищаются при открытии подключения.
Скорость RDP: что измерено
Весь путь кадра инструментирован на живом хосте. Локальная обработка занимает около 1 мс из ~100 мс задержки «нажал — увидел»: очередь кадров не заполнялась ни разу из 918 отправок, отрисовка кадра — 0.1 мс, транспорт держит 5.8 ГБ/с.
Одна настоящая потеря найдена и убрана: библиотека объединяет все изменившиеся области в один охватывающий прямоугольник, и клиент пересылал его целиком — при перетаскивании окна это давало 52 МБ переданных пикселей на 0.5 МБ реальных изменений.
Остальное — на стороне сервера: он отдаёт картинку 16 битами на пиксель старым RLE-кодеком. Клиент запрашивает 32 бита и объявляет RemoteFX, но при 16 битах RemoteFX не включается. Лечится настройкой ColorDepth в ветке Terminal Server\WinStations\RDP-Tcp на самом хосте.
Прочее
- Запрос доверия к серверу отрисовывался за пределами экрана и под окном восстановления сессий — восстановление зависало без возможности ответить.
- CI впервые заработал по-настоящему и сразу поймал два бага, невидимых на машине разработчика: тесты, не собиравшиеся под Linux, и тест, который проходил только потому, что локально выключен sshd.
Тесты: Rust 492, фронтенд 961.
Conchshell 2.6.0 (macOS + Linux)
RDP работает по-настоящему
RDP был заглушкой: connect всегда возвращал «не реализовано». Теперь это рабочий клиент на IronRDP — подключение через NLA, поток кадров, клавиатура, мышь, буфер обмена и перенос файлов. Проверено на живом Windows-хосте, а не на моках.
- Подключение: TCP → X.224 → TLS 1.3 → CredSSP/NTLM → MCS → лицензирование → capability exchange, около 3 секунд.
- Клавиатура: физические клавиши вместо
keyCode, поэтому левый и правый Ctrl больше не путаются, а numpad не сливается со стрелками. - Не-ASCII печатается символами, а не позициями клавиш. Скан-код называет позицию, и удалённый хост толкует её своей раскладкой: клавиша «ж» на английской раскладке сервера приезжает как
;. Синхронизировать раскладки — заведомо проигрышная игра, поэтому кириллица уходит Unicode-событиями, и раскладка на той стороне перестаёт иметь значение. Переключать язык в Windows не нужно. - Cmd работает как Ctrl. Cmd+C/V/X/A внутри сессии делают то, что вы от них ждёте. Cmd+Q, Cmd+W, Cmd+M и Cmd+H остаются локальными — из полноэкранной сессии всегда есть выход, плюс
Cmd+Shift+Escвозвращает клавиатуру принудительно. - Буфер обмена в обе стороны и перенос файлов Mac → Windows: копируете в Finder, вставляете в проводнике.
Проверка подлинности серверов
Раньше приложение не проверяло, с кем разговаривает: любой ключ SSH и любой сертификат RDP принимались молча. Соединение шифровалось, но подмена сервера была незаметна.
Теперь при первом подключении показывается отпечаток — в том же формате, что печатает ssh-keygen -lf, так что его можно сверить глазами. При изменении ключа появляется отдельное, более строгое предупреждение.
Чтобы это не превратилось в стену диалогов, ваш ~/.ssh/known_hosts импортируется автоматически. Не импортируются хешированные записи (имя в них необратимо), записи центров сертификации и хосты с противоречивыми ключами — ложная тревога обесценила бы саму тревогу.
Пароль и подпись ключом больше не отправляются непроверенному серверу: решение принимается до аутентификации.
Кириллица в локальном терминале
Приложение, запущенное из Finder, не получает от системы ни одной переменной локали, и оболочка работала в локали C — там кириллица не символы, а байты. Отсюда кракозябры при вставке. Теперь оболочке передаётся ваша локаль.
Прочее
- SFTP-подключение по ключу не могло работать в принципе: в разбор ключа передавался путь к файлу вместо его содержимого.
- В лог не попадали никакие предупреждения — фильтр по умолчанию пропускал только ошибки. Из-за этого объяснения отказов вроде «это папка, сожмите её сначала» писались в никуда.
- Добавлен CI: тесты, проверка типов, паритет локалей.
Тесты: Rust 453, фронтенд 874.
Conchshell 2.5.6 (macOS + Linux)
Серверы без интерактивного шелла больше не «висят молча»
Подключение к SFTP-серверу (SFTPGo, internal-sftp с ForceCommand, chroot-джейл) проходило авторизацию, вкладка показывала «подключено» — и терминал оставался пустым. Ни приглашения, ни ошибки.
Причина: create_pty_session уходил в channel.request_pty(...).await без таймаута. Такие серверы канал принимают, а шелл не выдают и на запрос не отвечают — ожидание не заканчивалось никогда.
request_ptyиrequest_shellограничены таймаутом в 10 секунд.- Вместо пустого окна терминал печатает понятное объяснение (en/ru/zh-CN): у сервера нет интерактивного шелла, для файлов нужно подключение по протоколу SFTP.
- Цикл переподключений в этом случае гасится — он структурно бесполезен.
Файловый браузер открывает настоящую домашнюю директорию
Раньше SSH-вкладка всегда стартовала в захардкоженном /home. У chroot-аккаунтов, на macOS (/Users/...), в контейнерах и на BSD такого пути нет — первый листинг падал, и панель выглядела сломанной.
- Новая команда
get_remote_home_dirспрашивает у сервераpwdпо exec-каналу (MOTD в выводе не сбивает разбор). - Ответ кэшируется на подключение; браузер переходит туда, только если вкладку не переключили и пользователь сам никуда не ушёл.
- Кнопка «Home» и возврат при исчезнувшем каталоге тоже используют реальный home.
Тесты
Rust 87 passed, фронтенд 488 passed / 7 skipped. i18n-паритет: 944 ключа во всех локалях.