Задать вопрос
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    начало скрипта

    class UI {
        constructor() {
            TLN.append_line_numbers('config');
    
            this.$tabs = document.querySelector('nav');
    
            this.buttons = this._initButtons();
            this.tabs = this._initTabs();
            this.textarea = this._initTextarea();
            this.version = this._initVersion();
            this.popup = this._initPopups();
            this.login = this._initLoginForm();
        }
    
        _initTabs() {
            const tabs = {};
            let currentFile = '';
    
            const add = (filename) => {
                const tab = document.createElement('div');
                tab.classList.add('nav-tab');
                tab.textContent = filename;
    
                const isConf = filename.endsWith('.conf');
                const isList = filename.endsWith('.list');
                const isLog = filename.endsWith('.log');
    
                if (isLog) {
                    const clear = document.createElement('div');
                    clear.classList.add('nav-clear');
                    clear.setAttribute('title', 'Clear log');
    
                    clear.addEventListener('click', async (e) => {
                        e.preventDefault();
                        e.stopPropagation();
    
                        const yesno = await this.popup.confirm('Clear log?');
                        if (!yesno) {
                            return;
                        }
    
                        const result = await saveFile(filename, '');
                        if (!result.status) {
                            if (filename === currentFile) {
                                this.textarea.value = '';
                            }
                        } else {
                            this.popup.alert(`clear ${filename}`, `Error: ${result.status}`);
                        }
                    });
    
                    tab.appendChild(clear);
                } else if (!isConf && !isList) {
                    tab.classList.add('secondary');
                    const trash = document.createElement('div');
                    trash.classList.add('nav-trash');
                    trash.setAttribute('title', 'Delete file');
    
                    trash.addEventListener('click', async (e) => {
                        e.preventDefault();
                        e.stopPropagation();
    
                        const yesno = await this.popup.confirm('Delete file?');
                        if (!yesno) {
                            return;
                        }
    
                        const result = await removeFile(filename);
                        if (!result.status) {
                            remove(filename);
                        } else {
                            this.popup.alert(`remove ${filename}`, `Error: ${result.status}`);
                        }
                    });
    
                    tab.appendChild(trash);
                }
    
                tab.addEventListener('click', async () => this.loadFile(filename));
    
                this.$tabs.appendChild(tab);
                tabs[filename] = tab;
            };
    
            const remove = (filename) => {
                for (const [key, tab] of Object.entries(tabs)) {
                    if (key === filename) {
                        tab.parentNode.removeChild(tab);
                        delete tabs[key];
    
                        if (filename === currentFile) {
                            this.textarea.save();
                            activateFirst();
                        }
                        break;
                    }
                }
            };
    
            const activate = (filename) => {
                for (const [key, tab] of Object.entries(tabs)) {
                    tab.classList.toggle('active', filename === key);
                    if (filename === key) {
                        currentFile = filename;
                    }
                }
            };
    
            const activateFirst = () => {
                Object.values(tabs)[0].click();
            };
    
            return {
                add,
                remove,
                activate,
                activateFirst,
                get currentFileName() {
                    return currentFile;
                }
            };
        }
    
        _initTextarea() {
            const element = document.getElementById('config');
            let originalText = element.value;
            let textChanged = false;
    
            const save = () => {
                originalText = element.value;
                textChanged = false;
                this.setChanged(false);
            };
    
            element.addEventListener('input', _debounce(() => {
                textChanged = element.value !== originalText;
                this.setChanged(textChanged);
            }, 300));
    
            element.addEventListener('keydown', (e) => {
                if ((e.ctrlKey || e.metaKey) && e.key === 's') {
                    e.preventDefault();
                    this.buttons.click();
                }
            });
    
            return {
                get value() {
                    return element.value;
                },
                set value(text) {
                    element.value = text;
                    save();
                    // Update line numbers
                    const event = new Event('input');
                    element.dispatchEvent(event);
                },
                get changed() {
                    return textChanged;
                },
                save,
                disabled(status) {
                    if (status) {
                        element.setAttribute('disabled', 'disabled');
                    } else {
                        element.removeAttribute('disabled');
                    }
                },
                readonly(status) {
                    if (status) {
                        element.setAttribute('readonly', 'readonly');
                    } else {
                        element.removeAttribute('readonly');
                    }
                },
            };
        }
    
        _initVersion() {
            const element = document.getElementById('version');
            const match = element.textContent.match(/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/);
    
            const value = () => {
                return match ? [match[1], match[2], match[3]] : null;
            };
    
            const checkUpdate = async () => {
                if (!value()) {
                    return;
                }
    
                const latest = await getLatestVersion();
                if (!latest) {
                    return;
                }
    
                const updateAvailable = compareVersions(value(), latest);
                if (updateAvailable) {
                    const link = document.createElement('a');
                    const tag = `v${latest[0]}.${latest[1]}.${latest[2]}`;
                    link.textContent = `(${tag})`;
                    link.href = `https://github.com/Anonym-tsk/nfqws-keenetic/releases/tag/${tag}`;
                    link.target = '_blank';
                    element.appendChild(link);
                }
            };
    
            return {
                get value() {
                    return value();
                },
                checkUpdate,
            }
        }
    
        _initPopups() {
            const element = document.getElementById('alert');
            const alertContent = element.querySelector('.popup-content');
            const buttonClose = element.querySelector('.popup-close');
            const buttonYes = element.querySelector('.popup-yes');
            const buttonNo = element.querySelector('.popup-no');
    
            const alert = (...text) => {
                this.disableUI();
                alertContent.textContent = `> ${text.join("\n")}`;
                element.classList.add('alert');
                element.classList.remove('hidden', 'confirm', 'locked');
            };
    
            const hide = () => {
                element.classList.add('hidden');
                element.classList.remove('locked');
                this.enableUI();
            }
    
            const confirm = async (text) => {
                this.disableUI();
                alertContent.textContent = text;
                element.classList.add('confirm');
                element.classList.remove('hidden', 'alert', 'locked');
    
                return new Promise((resolve) => {
                    buttonYes.addEventListener('click', function ok() {
                        buttonYes.removeEventListener('click', ok);
                        resolve(true);
                    });
                    buttonNo.addEventListener('click', function fail() {
                        buttonNo.removeEventListener('click', fail);
                        resolve(false);
                    });
                });
            };
    
            const process = async (text, fn, ...args) => {
                this.disableUI();
                alertContent.textContent = `> ${text}\n`;
                element.classList.add('alert', 'locked');
                element.classList.remove('hidden', 'confirm');
                let status = true;
    
                const result = await fn(...args);
                if (!result.status) {
                    alertContent.textContent += Array.from(result.output).join("\n");
                } else {
                    alertContent.textContent += `Error: ${result.status}`;
                    status = false;
                }
                element.classList.remove('locked');
    
                return new Promise((resolve) => {
                    buttonClose.addEventListener('click', function close() {
                        buttonYes.removeEventListener('click', close);
                        resolve(status);
                    });
                });
            };
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    AUser0,
    Хотите - в HTTP-запросе представляйтесь веб браузером, не хотите - не представляйтесь...

    ну так именно этот момент и неясен. как это варьировать?
    в s_client кроме [-connect host:port] [-servername name]
    другие параметры не использовал и ихнее влияние неясно
    [-connect host:port] в случае извне
    могу два варианта. как домен 3го или 4го уровня - порт полюбасу 443 -- попадает извне на прокси
    а [-servername name] задаёт sni строго 4го уровня. именно по этому sni прокси переправлять и должен на внутренний ip\порт s_server. и с браузером работает (см.выше)

    но получается принудительно расшифровывается по пути?
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    AUser0, ну так а что именно не так? какбы вы написали труЪ команду для s_client ?
    и как быть с тем что посередине между client и server стоит https reverse proxy?
    браузер тоже например не тот серт использует при подключении извне(но до server таки долазит и кажет именно его страницу, но серт в свойствах от прокси). а изнутри таки серт от openssl s_server
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    ValdikSS,
    самого web-интерфейса роутера

    это-то вполне.
    любой внутренний и даже не очень ip(типа момеда который какбы "вовне" по отношению к роутеру)
    не пропустит не-web-трафик

    а вот это да. но начиналось то всё (в гугле) что ssh в этот самый web можно завернуть. но оказывается нельзя или нетольколишьвсе варианты tls заворачиваются
    но как-то труЪ https браузеров идёт, а остальное уже не очень. хотя обещали(в гугле) с три короба
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    ответить то ответили - но я не могу поставить рекомендованные "усложнения" nginx

    а s_client такое впечатление не может сквозь nginx прокси пролезть - и "руки-жмёт" с ним а не s_server (который тоже вовнутри сети)

    осталось только в этом на 146% убедится

    или совет как заставить таки "пробится" вовнутрь
    и тогда уже вовнутре ssl пойдёт ssh (но это да уже обсудили)
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    в случае браузера серт не сервака, а прокси становится (в самом браузере) но показывает именно страницу сервера
    может и s_client на первом попавшемся tls пытается соединится?
    хотя мысль что должен проходить через прокси внутрь до сервака.
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    AUser0, даже излишне много
    а понимания дошло до сервера или нет - не добавляет
    что именно в выводе надо искать?
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    но где такое в
    location / {
    proxy_pass http://127.0.0.1:22;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    }
    ?
    за вычетом того что у меня не localhost а другой ip
    https://dev.to/udara_dananjaya/how-to-access-ssh-o...
    тут некий стрим правда
    https://iyzico.engineering/proxy-ssh-using-tls-sni...
    но это на мой "ngnix " не поставить - можно лишь как в вопросе
    внутренний ip/порт и выбор https|http

    в обоих случаях с sshd ничего не делают
    и всё равно не понимаю как ssh сервер понимает https ? или из прокси он уже чистым ssh выходит? но назад обратно в https заворачивается?
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    нигде в советах про ковыряние на стороне ssh сервера ни слова
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    Т.е. чтобы приведённый пример работал, нужно чтобы на целевом сервере на 443 порту крутился какой-то реверс-прокси (точнее, TLS termination proxy), который распакует трафик из туннеля и пробросит его на порт, который слушает SSH-сервер. Имхо, SSH-сервер про эти фокусы вообще ничего не знает.

    это выполняется
    reverse proxy настроен
    слушает 443 и направляет на 222

    но вот на счёт что "распаковывает" не уверен и наоборот имхо вредно, либо ещё один прокси нужен? помимо внешнего ещё и внутренний?

    советы(читал и больше)
    https://dev.to/udara_dananjaya/how-to-access-ssh-o...

    https://iyzico.engineering/proxy-ssh-using-tls-sni...
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    Vindicar, надо ковырять... и смотреть, может и можно отдельный порт с openssl сервером прикрутить. но точно что сам opensll ещё надо както туда поставить....

    т.е. в примерах из которых я подчерпнул метод - все эти советчики не говорили что у них сервер debian и поэтому ихний ssh из коробки понимал что делать когда на ssh порт долбится openssl?
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    AlexVWill,
    а не переводит трафик из протокола в протокол, из Https в SSH

    именно
    поэтому советы (а их в гугле не 1 и не 2 и разные люди =не копипаста) и вызывают вопросы и удивление.

    но как я понял именно часть команды про openssl превращает ssh в https
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса

    Что значит "только по HTTPS"?
    Но соответствие HTTPS может контролироваться более жёстко. Нужно использовать заданный хостером HTTP-прокси/реверс-прокси для работы с сетью? Или, скажем, слишком долго висящие соединения принудительно рвутся? Или TLS-хэндшейк проверяется на соответствие популярным браузерам? Во всех этих случаях простым туннелем ты не обойдёшься.

    встроенный в кинетик http туннель ихней облачной службы
    заведомо известно что если просто tcp поток то не летит
    сам tls client hello отслеживают чётко
    какое sni туда и попадает на внутренний адрес\порт
    и если на адресе-порте web всё ок
    а с ssh неясно. заведомо не веб

    openssl отдельно по sni как-будто попадает куда надо(т.е. на порт ssh), но не держит туннель - данных то нету+непонимаю с чего вдруг ssh сервер должен этот openssl понимать? я его не настраивал. и в примерах\советах тоже никто не настраивает а якобы сразу соединяются

    вся "надежда" что я не так пишу команду
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    обновил

    как можно сделать ещё понятней вам не понимаю сам
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    Dmitry, по ssh к серваку подключиться
    извне
    Написано
  • Можно ли настроить PuTTY, чтобы отображалось как в консоли?

    @Quqas Автор вопроса
    Кот Абсолютный, именно, но раз уже xterm а "тут" putty то пространство для манёвра?
    я с твоих же слов понял что putty=xterm only (вариации ***color не в счёт)
    Написано
  • Можно ли настроить PuTTY, чтобы отображалось как в консоли?

    @Quqas Автор вопроса
    Кот Абсолютный, после того как echo $TERM сказал что он xtermвариантов то не было других
    Написано
  • Можно ли настроить PuTTY, чтобы отображалось как в консоли?

    @Quqas Автор вопроса
    xterm

    putty в принципе у меня по дефолту
    т.е. видимо текст онли
    ты имеешь ввиду что его можно в некий Х режим перевести?
    Написано
  • Можно ли настроить PuTTY, чтобы отображалось как в консоли?

    @Quqas Автор вопроса
    т.е. трабл 146% со стороны серверной бубунты?
    Написано
  • Не отображаются активные подключения к шлюзу удаленных рабочих столов?

    @Quqas
    неплохо было бы скрины
    наличие rdgateway не панацея что клиент не может подключится напрямую к серваку rds
    особенно если речь про тесты внутри локалки
    Написано