From a90b1a1a4a2195deb86db261a324f91416512664 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Wed, 21 Jun 2023 20:08:53 +0300 Subject: [PATCH] luci-app-sshtunnel: SSH tunnels The app helps to generate a key and configure the SSH tunnels. Signed-off-by: Sergey Ponomarev --- applications/luci-app-sshtunnel/Makefile | 13 + .../luci-static/resources/view/sshtunnel.js | 403 ++++++++++++++++++ .../luci-app-sshtunnel/po/ru/sshtunnel.po | 297 +++++++++++++ .../po/templates/sshtunnel.pot | 290 +++++++++++++ .../share/luci/menu.d/luci-app-sshtunnel.json | 13 + .../share/rpcd/acl.d/luci-app-sshtunnel.json | 20 + 6 files changed, 1036 insertions(+) create mode 100644 applications/luci-app-sshtunnel/Makefile create mode 100644 applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js create mode 100644 applications/luci-app-sshtunnel/po/ru/sshtunnel.po create mode 100644 applications/luci-app-sshtunnel/po/templates/sshtunnel.pot create mode 100644 applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json create mode 100644 applications/luci-app-sshtunnel/root/usr/share/rpcd/acl.d/luci-app-sshtunnel.json diff --git a/applications/luci-app-sshtunnel/Makefile b/applications/luci-app-sshtunnel/Makefile new file mode 100644 index 000000000000..3655f98edf12 --- /dev/null +++ b/applications/luci-app-sshtunnel/Makefile @@ -0,0 +1,13 @@ +# This is free software, licensed under the Apache License, Version 2.0 . + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for SSH Tunnels (sshtunnel package) + +PKG_MAINTAINER:=Sergey Ponomarev +PKG_LICENSE:=Apache-2.0 +LUCI_DEPENDS:=+luci-base +sshtunnel + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js b/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js new file mode 100644 index 000000000000..a8104ece8468 --- /dev/null +++ b/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js @@ -0,0 +1,403 @@ +'use strict'; +'require form'; +'require fs'; +'require uci'; +'require ui'; +'require view'; + +var allSshKeys = {}; +var hasSshKeygen = false; + +return view.extend({ + load: function () { + return L.resolveDefault(fs.list("/root/.ssh/"), []).then(function (entries) { + var tasks = [ + uci.load('sshtunnel'), + L.resolveDefault(fs.stat("/usr/bin/ssh-keygen"), {}), + fs.lines("/root/.ssh/known_hosts"), + ]; + // read pub keys + for (var i = 0; i < entries.length; i++) { + if (entries[i].type === "file" && entries[i].name.match(/\.pub$/)) { + tasks.push(Promise.resolve(entries[i].name)); + tasks.push(fs.lines("/root/.ssh/" + entries[i].name)); + } + } + return Promise.all(tasks); + }); + }, + + render: function (sshFiles) { + hasSshKeygen = sshFiles[1].type === "file"; + var knownHosts = sshFiles[2]; + var sshKeys = _splitSshKeys(sshFiles.splice(3)); + if (sshKeys.length === 0) { + ui.addNotification(null, E("p", [ + _("No any SSH key, please generate a new one") + ]), "warning"); + } + + var m, s, o; + + m = new form.Map("sshtunnel", _("SSH Tunnels"), + _("This configures SSH Tunnels. " + + "Password auth is not possible so only Public Key auth must be used.") + ); + + s = m.section(form.GridSection, "server", _("Servers")); + s.anonymous = false; + s.addremove = true; + s.nodescriptions = true; + + o = s.tab("general", _("General Settings")); + o = s.tab("advanced", _("Advanced Settings")); + + o = s.taboption("general", form.Value, "hostname", _("Hostname"), ""); + o.placeholder = "example.com"; + o.datatype = "host"; + o.rmempty = false; + + o = s.taboption("general", form.Value, "port", _("Port"), ""); + o.placeholder = "22"; + o.datatype = "port"; + + o = s.taboption("general", form.Value, "user", _("User"), ""); + o.default = "root"; + + o = s.taboption("general", form.ListValue, "IdentityFile", _("Key file"), + _("Private key file with authentication identity. The default is /root/.ssh/id_ed25519, id_rsa, id_ecdsa or id_dropbear.") + ); + o.value("", ""); + Object.keys(sshKeys).forEach(function (keyName) { + o.value("/root/.ssh/" + keyName, keyName); + }); + o.optional = true; + + o = s.taboption("advanced", form.ListValue, "CheckHostIP", _("Check host IP"), + _("CheckHostIP If enabled the ssh will check the host IP address in the known_hosts file. " + + "This allows ssh to detect if a host key changed due to DNS spoofing.") + ); + o.value("yes", _("Yes")); + o.value("no", _("No")); + o.default = "no"; + o.modalonly = true; + + o = s.taboption("advanced", form.ListValue, "VerifyHostKeyDNS", _("Verify Host Key DNS"), + _("VerifyHostKeyDNS Verify the remote key using DNS and SSHFP resource records.") + ); + o.value("yes", _("Yes")); + o.value("no", _("No")); + o.default = "no"; + o.modalonly = true; + + o = s.taboption("advanced", form.ListValue, "Compression", _("Use compression"), + _("Compression may be useful on slow connections.") + ); + o.value("yes", _("Yes")); + o.value("no", _("No")); + o.default = "no"; + o.modalonly = true; + + o = s.taboption("advanced", form.Value, "retrydelay", _("Retry delay"), + _("Delay after a connection failure before trying to reconnect..") + ); + o.placeholder = 10; + o.default = 10; + o.datatype = "uinteger"; + o.optional = true; + o.modalonly = true; + + o = s.taboption("advanced", form.Value, "ServerAliveCountMax", _("Server Alive Count Max"), + _("ServerAliveCountMax The number of server alive messages which may be sent before ssh disconnect from the server.") + ); + o.placeholder = 3; + o.datatype = "uinteger"; + o.optional = true; + o.modalonly = true; + + o = s.taboption("advanced", form.Value, "ServerAliveInterval", _("Server Alive Count Max"), + _("ServerAliveInterval Timeout interval in seconds for keep alive.") + ); + o.optional = true; + o.placeholder = 0; + o.datatype = "uinteger"; + o.modalonly = true; + + o = s.taboption("advanced", form.ListValue, "StrictHostKeyChecking", _("Strict host key checking"), + _("StrictHostKeyChecking Refuse to connect to hosts if it's key has changed.")); + o.value("accept-new", _("Accept new and check if not changed")); + o.value("yes", _("Yes")); + o.value("no", _("No")); + o.default = "accept-new"; + o.modalonly = true; + + o = s.taboption("advanced", form.ListValue, "LogLevel", _("Log level"), ""); + o.value("QUIET", "QUIET"); + o.value("FATAL", "FATAL"); + o.value("ERROR", "ERROR"); + o.value("INFO", "INFO"); + o.value("VERBOSE", "VERBOSE"); + o.value("DEBUG", "DEBUG"); + o.default = "INFO"; + o.modalonly = true; + + + s = m.section(form.GridSection, "tunnelR", _("Remote Tunnels"), + _("When the connection initiated at RemoteAddress:RemotePort and then forwarded to LocalAddress:LocalPort") + ); + s.anonymous = true; + s.addremove = true; + s.nodescriptions = true; + + o = s.option(form.Flag, "enabled", _("Enabled")); + o.default = "1"; + + o = _addServerOption(s); + + o = s.option(form.Value, "remoteaddress", _("Remote address"), + _("* means to accept a connection from any interface on the OpenWrt side") + ); + o.datatype = 'or(host, "*")'; + o.optional = true; + o.rmempty = false; + + o = s.option(form.Value, "remoteport", _("Remote port"), ""); + o.default = "22"; + o.datatype = "port"; + o.rmempty = false; + + o = s.option(form.Value, "localaddress", _("Local address"), ""); + o.placeholder = "192.168.1.1"; + o.datatype = "host"; + o.rmempty = false; + + o = s.option(form.Value, "localport", _("Local port"), ""); + o.placeholder = "80"; + o.datatype = "port"; + o.rmempty = false; + + + s = m.section(form.GridSection, "tunnelL", _("Local Tunnels"), + _("When the connection initiated at LocalAddress:LocalPort and then forwarded to RemoteAddress:RemotePort") + ); + s.anonymous = true; + s.addremove = true; + s.nodescriptions = true; + + o = s.option(form.Flag, "enabled", _("Enabled")); + o.default = "1"; + + o = _addServerOption(s); + + o = s.option(form.Value, "localaddress", _("Local address"), + _("* means to accept a connection from any interface on the OpenWrt side") + ); + o.datatype = 'or(host, "*")'; + o.optional = true; + o.rmempty = false; + + o = s.option(form.Value, "localport", _("Local port"), ""); + o.placeholder = "1022"; + o.datatype = "port"; + o.rmempty = false; + + o = s.option(form.Value, "remoteaddress", _("Remote address"), ""); + o.datatype = "host"; + o.rmempty = false; + + o = s.option(form.Value, "remoteport", _("Remote port"), ""); + o.default = "22"; + o.datatype = "port"; + o.rmempty = false; + + + s = m.section(form.GridSection, "tunnelD", _("Dynamic Tunnels"), + _("When the connection initiated with the SOCKS protocol to the LocalAddress:LocalPort and then forwarded over the remote host") + ); + s.anonymous = true; + s.addremove = true; + s.nodescriptions = true; + + o = s.option(form.Flag, "enabled", _("Enabled")); + o.default = "1"; + + o = _addServerOption(s); + + o = s.option(form.Value, "localaddress", _("Local address"), + _("* means to accept a connection from any interface on the OpenWrt side") + ); + o.datatype = 'or(host, "*")'; + o.optional = true; + o.rmempty = false; + + o = s.option(form.Value, "localport", _("Local port"), ""); + o.default = "1080"; + o.datatype = "port"; + o.rmempty = false; + + + s = m.section(form.GridSection, "tunnelW", _("VPN Tunnels"), + _("Creates TUN/TAP devices on client and server to establish a VPN tunnel between them") + ); + s.anonymous = true; + s.addremove = true; + s.nodescriptions = true; + + o = s.option(form.Flag, "enabled", _("Enabled")); + o.default = "1"; + + o = _addServerOption(s); + + o = s.option(form.ListValue, "vpntype", _("VPN type"), ""); + o.value("point-to-point", "TUN (point-to-point)"); + o.value("ethernet", "TAP (ethernet)"); + o.default = "point-to-point"; + + o = s.option(form.Value, "localdev", _("Local dev"), ""); + o.default = "any"; + o.datatype = 'or("any", min(0))'; + o.rmempty = false; + + o = s.option(form.Value, "remotedev", _("Remote dev"), ""); + o.default = "any"; + o.datatype = 'or("any", min(0))'; + o.rmempty = false; + + + s = m.section(form.GridSection, "_keys"); + s.render = L.bind(_renderSshKeys, this, sshKeys); + + s = m.section(form.GridSection, "_known_hosts"); + s.render = L.bind(_renderKnownHosts, this, knownHosts); + + return m.render(); + }, +}); + +function _addServerOption(s) { + var o = s.option(form.ListValue, "server", _("Server"), _("Type a server name from servers list above")); + o.datatype = "uciname"; + o.rmempty = false; + uci.sections('sshtunnel', 'server', function (s, sectionName) { + o.value(sectionName, s.hostname ? '%s (%s)'.format(sectionName, s.hostname) : sectionName); + }); + return o; +} + +function _splitSshKeys(sshFiles) { + var sshKeys = {}; + for (var i = 0; i < sshFiles.length; i++) { + var sshPubKeyName = sshFiles[i]; + var sshKeyName = sshPubKeyName.substring(0, sshPubKeyName.length - 4); + i++; + var sshPub = sshFiles[i]; + sshKeys[sshKeyName] = "" + sshPub + ""; + } + allSshKeys = sshKeys; + return sshKeys; +} + +function _renderSshKeys(sshKeys) { + var table = E('table', {'class': 'table cbi-section-table', 'id': 'keys_table'}, [ + E('tr', {'class': 'tr table-titles'}, [ + E('th', {'class': 'th'}, _('Name')), + E('th', {'class': 'th'}, _('Public Key')), + ]) + ]); + + var rows = Object.entries(sshKeys); + cbi_update_table(table, rows, E('em', _("No any SSH key, please generate a new one"))); + + var keyGenBtn = E('div', {}, [ + E('label', {}, _('Generate a new key') + ': '), + E('span', {'class': 'control-group'}, [ + E('input', { + 'type': 'text', + 'name': 'keyName', + 'value': 'id_ed25519', + 'keydown': function (ev) { + if (ev.keyCode === 13) _handleKeyGen(ev); + } + }), + E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'click': _handleKeyGen + }, [_('Generate')]) + ]) + ]); + return E('div', {'class': 'cbi-section cbi-tblsection'}, [ + E('h3', _('Keys')), + E('div', {'class': 'cbi-section-descr'}, + _("You need to add the pub key to /root/.ssh/authorized_keys or to /etc/dropbear/authorized_keys.") + " " + + _("In LuCI you can do that with System / Administration / SSH-Keys") + ), + keyGenBtn, table + ]); +} + +function _handleKeyGen(event) { + var keyName = document.querySelector('input[name="keyName"]').value; + if (!keyName) { + alert(_("Please specify a key name")); + return; + } + if (allSshKeys[keyName]) { + alert(_("A key with the name already exists")); + return; + } + if (/[^a-zA-Z0-9_.]/.test(keyName)) { + alert(_("Bad name")); + return; + } + + let command = "/usr/bin/ssh-keygen"; + let commandArgs = ["-t", "ed25519", "-q", "-N", "", "-f", "/root/.ssh/" + keyName]; + if (!hasSshKeygen) { + command = "/usr/bin/dropbearkey"; + commandArgs = ["-t", "ed25519", "-f", "/root/.ssh/" + keyName]; + } + return fs.exec(command, commandArgs).then(function (res) { + if (res.code === 0) { + alert("A new key was generated. Please refresh the page in a browser to see it."); + } else { + throw new Error(res.stdout + " " + res.stderr); + } + }).catch(function (err) { + alert(_("Unable to generate a key: %s").format(err.message)); + }); +} + + +function _renderKnownHosts(knownHosts) { + var table = E('table', {'class': 'table cbi-section-table', 'id': 'known_hosts'}, [ + E('tr', {'class': 'tr table-titles'}, [ + E('th', {'class': 'th'}, _('Hostname')), + E('th', {'class': 'th'}, _('Public Key')), + ]) + ]); + + var rows = _splitKnownHosts(knownHosts); + cbi_update_table(table, rows); + + return E('div', {'class': 'cbi-section cbi-tblsection'}, [ + E('h3', _('Known hosts ')), + E('div', {'class': 'cbi-section-descr'}, + _("Keys of SSH servers from /root/.ssh/known_hosts.") + ), + table + ]); +} + +function _splitKnownHosts(knownHosts) { + var knownHostsMap = []; + for (var i = 0; i < knownHosts.length; i++) { + var sp = knownHosts[i].indexOf(' '); + if (sp < 0) { + continue; + } + var hostname = knownHosts[i].substring(0, sp); + var pub = knownHosts[i].substring(sp + 1); + knownHostsMap.push([hostname, "" + pub + ""]); + } + return knownHostsMap; +} diff --git a/applications/luci-app-sshtunnel/po/ru/sshtunnel.po b/applications/luci-app-sshtunnel/po/ru/sshtunnel.po new file mode 100644 index 000000000000..f2a3cbaae430 --- /dev/null +++ b/applications/luci-app-sshtunnel/po/ru/sshtunnel.po @@ -0,0 +1,297 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:158 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:193 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:227 +msgid "* means to accept a connection from any interface on the OpenWrt side" +msgstr "* значит принимать соедениение из любого интерфейса на стороне OpenWrt" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:345 +msgid "A key with the name already exists" +msgstr "Ключ с таким именем уже существует" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:128 +msgid "Accept new and check if not changed" +msgstr "Принимать новый и проверять что не изменился" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:53 +msgid "Advanced Settings" +msgstr "Расширенные настройки" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:349 +msgid "Bad name" +msgstr "Плохое имя" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:76 +msgid "Check host IP" +msgstr "Проверять IP хоста" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:77 +msgid "" +"CheckHostIP If enabled the ssh will check the host IP address in the " +"known_hosts file. This allows ssh to detect if a host key changed due to DNS " +"spoofing." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:94 +msgid "Compression may be useful on slow connections." +msgstr "Сжатие может быть полезным на медленном соединении." + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:240 +msgid "" +"Creates TUN/TAP devices on client and server to establish a VPN tunnel " +"between them" +msgstr "Создает устройства TUN/TAP на клиенте и сервере для установления " +"VPN-туннеля между ними" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:102 +msgid "Delay after a connection failure before trying to reconnect.." +msgstr "Задержка перед переподключением" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:214 +msgid "Dynamic Tunnels" +msgstr "Динамические тунели" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:152 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:187 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:221 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:246 +msgid "Enabled" +msgstr "Включен" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:52 +msgid "General Settings" +msgstr "Общие настройки" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:325 +msgid "Generate" +msgstr "Сгенерировать" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:312 +msgid "Generate a new key" +msgstr "Сгенерировать новый ключ" + +#: applications/luci-app-sshtunnel/root/usr/share/rpcd/acl.d/luci-app-sshtunnel.json:3 +msgid "Grant UCI access for luci-app-sshtunnel" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:55 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:374 +msgid "Hostname" +msgstr "Имя хоста" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:332 +msgid "In LuCI you can do that with System / Administration / SSH-Keys" +msgstr "В LuCI вы можете это сделать через Система / Администрирование / SSH ключи" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:67 +msgid "Key file" +msgstr "Файл ключа" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:329 +msgid "Keys" +msgstr "Ключи" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:385 +msgid "Keys of SSH servers from /root/.ssh/known_hosts." +msgstr "Ключи SSH уже известных серверов из /root/.ssh/known_hosts." + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:383 +msgid "Known hosts" +msgstr "Знакомые хосты" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:180 +msgid "Local Tunnels" +msgstr "Локальные тунели" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:169 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:192 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:226 +msgid "Local address" +msgstr "Локальный адрес" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:256 +msgid "Local dev" +msgstr "Локальное устройство dev" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:174 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:199 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:233 +msgid "Local port" +msgstr "Локальный порт" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:134 +msgid "Log level" +msgstr "Уровень логирования" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:303 +msgid "Name" +msgstr "Название" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:81 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:89 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:97 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:130 +msgid "No" +msgstr "Нет" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:36 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:309 +msgid "No any SSH key, please generate a new one" +msgstr "Нет ни одного ключа, пожалуйста сгенерируйте новый." + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:341 +msgid "Please specify a key name" +msgstr "Пожалуйста укажите название ключа" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:60 +msgid "Port" +msgstr "Порт" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:68 +msgid "" +"Private key file with authentication identity. The default is /root/.ssh/" +"id_ed25519, id_rsa, id_ecdsa or id_dropbear." +msgstr "Файл приватного ключа для авторизации." +"По умолчанию /root/.ssh/id_ed25519, id_rsa, id_ecdsa или id_dropbear." + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:304 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:375 +msgid "Public Key" +msgstr "Публичный ключ" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:145 +msgid "Remote Tunnels" +msgstr "Удалённые тунели" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:157 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:204 +msgid "Remote address" +msgstr "Удалённый адресс" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:261 +msgid "Remote dev" +msgstr "Удалённое устройство dev" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:164 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:208 +msgid "Remote port" +msgstr "Удалённый порт" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:101 +msgid "Retry delay" +msgstr "Задержка попытки" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:42 +#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:3 +msgid "SSH Tunnels" +msgstr "SSH тунели" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:278 +msgid "Server" +msgstr "Сервер" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:110 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:118 +msgid "Server Alive Count Max" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:111 +msgid "" +"ServerAliveCountMax The number of server alive messages which may be sent " +"before ssh disconnect from the server." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:119 +msgid "ServerAliveInterval Timeout interval in seconds for keep alive." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:47 +msgid "Servers" +msgstr "Серверы" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:126 +msgid "Strict host key checking" +msgstr "Строгая проверка ключа хоста" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:127 +msgid "" +"StrictHostKeyChecking Refuse to connect to hosts if it's key has changed." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:43 +msgid "" +"This configures SSH Tunnels. Password auth is not possible so only Public Key " +"auth must be used." +msgstr "Настройте SSH Туннели." +"Аутентификация по паролю невозможна, поэтому используется авторизация по публичному ключу." + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:278 +msgid "Type a server name from servers list above" +msgstr "Введите имя сервера из списка серверов выше" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:366 +msgid "Unable to generate a key: %s" +msgstr "Ошибка при генерации ключа: %s" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:93 +msgid "Use compression" +msgstr "Использовать сжатие" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:64 +msgid "User" +msgstr "Пользователь" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:239 +msgid "VPN Tunnels" +msgstr "VPN тунели" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:251 +msgid "VPN type" +msgstr "Тип VPN" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:85 +msgid "Verify Host Key DNS" +msgstr "Проверять DNS хоста" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:86 +msgid "" +"VerifyHostKeyDNS Verify the remote key using DNS and SSHFP resource records." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:181 +msgid "" +"When the connection initiated at LocalAddress:LocalPort and then forwarded " +"to RemoteAddress:RemotePort" +msgstr "Когда соединение инициируется на ЛокальныйАдрес:ЛокальныйПорт, " +"а затем перенаправляется на УдалённыйАдрес:УдалённыйПорт" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:146 +msgid "" +"When the connection initiated at RemoteAddress:RemotePort and then forwarded " +"to LocalAddress:LocalPort" +msgstr "Когда соединение инициируется на УдалённыйАдрес:УдалённыйПорт, " +"а затем перенаправляется на ЛокальныйАдрес:ЛокальныйПорт" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:215 +msgid "" +"When the connection initiated with the SOCKS protocol to the " +"LocalAddress:LocalPort and then forwarded over the remote host" +msgstr "Когда соединение инициируется с помощью протокола SOCKS " +"на ЛокальныйАдрес:ЛокальныйПорт, а затем перенаправляется на удаленный хост" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:80 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:88 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:96 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:129 +msgid "Yes" +msgstr "Да" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:331 +msgid "" +"You need to add the pub key to /root/.ssh/authorized_keys or to /etc/" +"dropbear/authorized_keys." +msgstr "Вам надо добавить этот публичный ключ в /root/.ssh/authorized_keys или в " +"/etc/dropbear/authorized_keys." diff --git a/applications/luci-app-sshtunnel/po/templates/sshtunnel.pot b/applications/luci-app-sshtunnel/po/templates/sshtunnel.pot new file mode 100644 index 000000000000..627f45a94320 --- /dev/null +++ b/applications/luci-app-sshtunnel/po/templates/sshtunnel.pot @@ -0,0 +1,290 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:158 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:193 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:227 +msgid "* means to accept a connection from any interface on the OpenWrt side" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:345 +msgid "A key with the name already exists" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:128 +msgid "Accept new and check if not changed" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:53 +msgid "Advanced Settings" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:349 +msgid "Bad name" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:76 +msgid "Check host IP" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:77 +msgid "" +"CheckHostIP If enabled the ssh will check the host IP address in the " +"known_hosts file. This allows ssh to detect if a host key changed due to DNS " +"spoofing." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:94 +msgid "Compression may be useful on slow connections." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:240 +msgid "" +"Creates TUN/TAP devices on client and server to establish a VPN tunnel " +"between them" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:102 +msgid "Delay after a connection failure before trying to reconnect.." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:214 +msgid "Dynamic Tunnels" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:152 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:187 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:221 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:246 +msgid "Enabled" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:52 +msgid "General Settings" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:325 +msgid "Generate" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:312 +msgid "Generate a new key" +msgstr "" + +#: applications/luci-app-sshtunnel/root/usr/share/rpcd/acl.d/luci-app-sshtunnel.json:3 +msgid "Grant UCI access for luci-app-sshtunnel" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:55 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:374 +msgid "Hostname" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:332 +msgid "In LuCI you can do that with System / Administration / SSH-Keys" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:67 +msgid "Key file" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:329 +msgid "Keys" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:385 +msgid "Keys of SSH servers from /root/.ssh/known_hosts." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:383 +msgid "Known hosts" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:180 +msgid "Local Tunnels" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:169 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:192 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:226 +msgid "Local address" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:256 +msgid "Local dev" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:174 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:199 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:233 +msgid "Local port" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:134 +msgid "Log level" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:303 +msgid "Name" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:81 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:89 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:97 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:130 +msgid "No" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:36 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:309 +msgid "No any SSH key, please generate a new one" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:341 +msgid "Please specify a key name" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:60 +msgid "Port" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:68 +msgid "" +"Private key file with authentication identity. The default is /root/.ssh/" +"id_ed25519, id_rsa, id_ecdsa or id_dropbear." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:304 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:375 +msgid "Public Key" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:145 +msgid "Remote Tunnels" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:157 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:204 +msgid "Remote address" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:261 +msgid "Remote dev" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:164 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:208 +msgid "Remote port" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:101 +msgid "Retry delay" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:42 +#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:3 +msgid "SSH Tunnels" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:278 +msgid "Server" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:110 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:118 +msgid "Server Alive Count Max" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:111 +msgid "" +"ServerAliveCountMax The number of server alive messages which may be sent " +"before ssh disconnect from the server." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:119 +msgid "ServerAliveInterval Timeout interval in seconds for keep alive." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:47 +msgid "Servers" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:126 +msgid "Strict host key checking" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:127 +msgid "" +"StrictHostKeyChecking Refuse to connect to hosts if it's key has changed." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:43 +msgid "" +"This configures SSH Tunnels. Password auth is not possible so only Public Key " +"auth must be used." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:278 +msgid "Type a server name from servers list above" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:366 +msgid "Unable to generate a key: %s" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:93 +msgid "Use compression" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:64 +msgid "User" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:239 +msgid "VPN Tunnels" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:251 +msgid "VPN type" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:85 +msgid "Verify Host Key DNS" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:86 +msgid "" +"VerifyHostKeyDNS Verify the remote key using DNS and SSHFP resource records." +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:181 +msgid "" +"When the connection initiated at LocalAddress:LocalPort and then forwarded " +"to RemoteAddress:RemotePort" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:146 +msgid "" +"When the connection initiated at RemoteAddress:RemotePort and then forwarded " +"to LocalAddress:LocalPort" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:215 +msgid "" +"When the connection initiated with the SOCKS protocol to the LocalAddress:" +"LocalPort and then forwarded over the remote host" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:80 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:88 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:96 +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:129 +msgid "Yes" +msgstr "" + +#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel.js:331 +msgid "" +"You need to add the pub key to /root/.ssh/authorized_keys or to /etc/" +"dropbear/authorized_keys." +msgstr "" diff --git a/applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json b/applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json new file mode 100644 index 000000000000..c81bf76ebd34 --- /dev/null +++ b/applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json @@ -0,0 +1,13 @@ +{ + "admin/services/sshtunnel": { + "title": "SSH Tunnels", + "order": 50, + "action": { + "type": "view", + "path": "sshtunnel" + }, + "depends": { + "acl": [ "luci-app-sshtunnel" ] + } + } +} diff --git a/applications/luci-app-sshtunnel/root/usr/share/rpcd/acl.d/luci-app-sshtunnel.json b/applications/luci-app-sshtunnel/root/usr/share/rpcd/acl.d/luci-app-sshtunnel.json new file mode 100644 index 000000000000..5dfb1405c77e --- /dev/null +++ b/applications/luci-app-sshtunnel/root/usr/share/rpcd/acl.d/luci-app-sshtunnel.json @@ -0,0 +1,20 @@ +{ + "luci-app-sshtunnel": { + "description": "Grant UCI access for luci-app-sshtunnel", + "read": { + "file": { + "/root/.ssh/": [ "list" ], + "/root/.ssh/*.pub": [ "read" ], + "/root/.ssh/known_hosts": [ "read" ], + "/usr/bin/ssh-keygen": [ "list" ], + "/usr/bin/ssh-keygen *": [ "exec" ], + "/usr/bin/dropbearkey": [ "list" ], + "/usr/bin/dropbearkey *": [ "exec" ] + }, + "uci": [ "sshtunnel" ] + }, + "write": { + "uci": [ "sshtunnel" ] + } + } +}