New app: luci-app-sshtunnel for SSH tunnels (#6424)

* luci-app-sshtunnel: SSH tunnels

The app helps to configure SSH tunnels.
You can also generate an SSH key and see known hosts.

Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
This commit is contained in:
Sergey Ponomarev 2023-12-04 20:27:53 +02:00 committed by GitHub
parent 9d746c75f4
commit 7d14746ae8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1173 additions and 0 deletions

View file

@ -0,0 +1,15 @@
# See /LICENSE for more information.
# 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 <stokito@gmail.com>
LUCI_DEPENDS:=+luci-base +sshtunnel
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View file

@ -0,0 +1,64 @@
'use strict';
'require form';
'require fs';
'require ui';
'require view';
return view.extend({
load: function () {
return Promise.all([
fs.lines('/root/.ssh/known_hosts'),
]);
},
render: function (data) {
var knownHosts = data[0];
var m, s, o;
m = new form.Map('sshtunnel', _('SSH Tunnels'),
_('This configures <a %s>SSH Tunnels</a>')
.format('href="https://openwrt.org/docs/guide-user/services/ssh/sshtunnel"')
);
s = m.section(form.GridSection, '_known_hosts');
s.render = L.bind(_renderKnownHosts, this, knownHosts);
return m.render();
},
});
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 found in %s.').format('<code>/root/.ssh/known_hosts</code>')
),
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, '<small><code>' + pub + '</code></small>']);
}
return knownHostsMap;
}

View file

@ -0,0 +1,131 @@
'use strict';
'require form';
'require fs';
'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 = [
L.resolveDefault(fs.stat('/usr/bin/ssh-keygen'), {}),
];
// 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 (data) {
hasSshKeygen = data[0].type === 'file';
var sshKeys = _splitSshKeys(data.splice(1));
var m, s, o;
m = new form.Map('sshtunnel', _('SSH Tunnels'),
_('This configures <a %s>SSH Tunnels</a>')
.format('href="https://openwrt.org/docs/guide-user/services/ssh/sshtunnel"')
);
s = m.section(form.GridSection, '_keys');
s.render = L.bind(_renderSshKeys, this, sshKeys);
return m.render();
},
});
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] = '<small><code>' + sshPub + '</code></small>';
}
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, null);
var keyGenBtn = E('div', {}, [
E('form', {
'submit': _handleKeyGenSubmit,
}, [
E('label', {}, _('Generate a new key') + ': '),
E('span', {'class': 'control-group'}, [
E('input', {
'type': 'text',
'name': 'keyName',
'value': 'id_ed25519',
'pattern': '^[a-zA-Z][a-zA-Z0-9_\.]+',
'required': 'required',
'maxsize': '35',
'autocomplete': 'off',
}),
E('button', {
'id': 'btnGenerateKey',
'type': 'submit',
'class': 'btn cbi-button cbi-button-action',
}, [_('Generate')])
])
])
]);
return E('div', {'class': 'cbi-section cbi-tblsection'}, [
E('h3', _('SSH Keys')),
E('div', {'class': 'cbi-section-descr'},
_('Add the pub key to %s or %s.')
.format('<code>/root/.ssh/authorized_keys</code>', '<code>/etc/dropbear/authorized_keys</code>') + ' ' +
_('In LuCI you can do that with <a %s>System / Administration / SSH-Keys</a>')
.format('href="/cgi-bin/luci/admin/system/admin/sshkeys"')
),
keyGenBtn, table
]);
}
function _handleKeyGenSubmit(event) {
event.preventDefault();
var keyName = document.querySelector('input[name="keyName"]').value;
if (allSshKeys[keyName]) {
document.body.scrollTop = document.documentElement.scrollTop = 0;
ui.addNotification(null, E('p', _('A key with that name already exists.'), 'error'));
return false;
}
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];
}
fs.exec(command, commandArgs).then(function (res) {
if (res.code === 0) {
// refresh the page to see the new key
location.reload();
} else {
throw new Error(res.stdout + ' ' + res.stderr);
}
}).catch(function (e) {
document.body.scrollTop = document.documentElement.scrollTop = 0;
ui.addNotification(null, E('p', _('Unable to generate a key: %s').format(e.message)), 'error');
});
return false;
}

View file

@ -0,0 +1,147 @@
'use strict';
'require form';
'require fs';
'require uci';
'require ui';
'require view';
var allSshKeys = {};
return view.extend({
load: function () {
return L.resolveDefault(fs.list('/root/.ssh/'), []).then(function (entries) {
var tasks = [];
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));
}
}
return Promise.all(tasks);
});
},
render: function (data) {
var sshKeys = _splitSshKeys(data);
if (sshKeys.length === 0) {
ui.addNotification(null, E('p', _('No SSH keys found, <a %s>generate a new one</a>').format('href="./ssh_keys"')), 'warning');
}
var m, s, o;
m = new form.Map('sshtunnel', _('SSH Tunnels'),
_('This configures <a %s>SSH Tunnels</a>')
.format('href="https://openwrt.org/docs/guide-user/services/ssh/sshtunnel"')
);
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. ' +
'See <em>ssh_config IdentityFile</em>')
);
o.value('');
Object.keys(sshKeys).forEach(function (keyName) {
o.value('/root/.ssh/' + keyName, keyName);
});
o.optional = true;
o = s.taboption('advanced', form.ListValue, 'LogLevel', _('Log level'), 'See <em>ssh_config LogLevel</em>');
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.value('DEBUG2', 'DEBUG2');
o.value('DEBUG3', 'DEBUG3');
o.default = 'INFO';
o.modalonly = true;
o = s.taboption('advanced', form.ListValue, 'Compression', _('Use compression'),
_('Compression may be useful on slow connections. ' +
'See <em>ssh_config Compression</em>')
);
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'),
_('The number of server alive messages which may be sent before SSH disconnects from the server. ' +
'See <em>ssh_config ServerAliveCountMax</em>')
);
o.placeholder = '3';
o.datatype = 'uinteger';
o.optional = true;
o.modalonly = true;
o = s.taboption('advanced', form.Value, 'ServerAliveInterval', _('Server alive interval'),
_('Keep-alive interval (seconds). ' +
'See <em>ssh_config ServerAliveInterval</em>')
);
o.optional = true;
o.default = '60';
o.datatype = 'uinteger';
o.modalonly = true;
o = s.taboption('advanced', form.ListValue, 'CheckHostIP', _('Check host IP'),
_('Check the host IP address in the <code>known_hosts</code> file. ' +
'This allows ssh to detect whether a host key changed due to DNS spoofing. ' +
'See <em>ssh_config CheckHostIP</em>')
);
o.value('yes', _('Yes'));
o.value('no', _('No'));
o.default = 'no';
o.modalonly = true;
o = s.taboption('advanced', form.ListValue, 'StrictHostKeyChecking', _('Strict host key checking'),
_('Refuse to connect to hosts whose host key has changed. ' +
'See <em>ssh_config StrictHostKeyChecking</em>'));
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;
return m.render();
},
});
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);
sshKeys[sshKeyName] = '';
}
allSshKeys = sshKeys;
return sshKeys;
}

View file

@ -0,0 +1,164 @@
'use strict';
'require form';
'require fs';
'require uci';
'require ui';
'require view';
return view.extend({
load: function () {
return Promise.all([
uci.load('sshtunnel'),
]);
},
render: function (data) {
var m, s, o;
m = new form.Map('sshtunnel', _('SSH Tunnels'),
_('This configures <a %s>SSH Tunnels</a>')
.format('href="https://openwrt.org/docs/guide-user/services/ssh/sshtunnel"')
);
s = m.section(form.GridSection, 'tunnelR', _('Remote Tunnels'),
_('Forward a port on the remote host to a service on the local 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, 'remoteaddress', _('Remote address'),
_('Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. <code>localhost</code>.') + '<br/>' +
_('<code>*</code> means to listen all interfaces <b>including public</b>.')
);
o.datatype = 'or(host, "*")';
o.default = '*';
o.rmempty = false;
o = s.option(form.Value, 'remoteport', _('Remote port'));
o.placeholder = '80';
o.datatype = 'port';
o.rmempty = false;
o = s.option(form.Value, 'localaddress', _('Local address'),
_('Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. <code>localhost</code>.')
);
o.datatype = 'host';
o.default = 'localhost';
o.rmempty = false;
o = s.option(form.Value, 'localport', _('Local port'));
o.datatype = 'port';
o.placeholder = '80';
o.rmempty = false;
s = m.section(form.GridSection, 'tunnelL', _('Local Tunnels'),
_('Forward a port on the local host to a service on 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'),
_('Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. <code>localhost</code>.') + '<br/>' +
_('<code>*</code> means to listen all interfaces <b>including public</b>.')
);
o.datatype = 'or(host, "*")';
o.placeholder = '192.168.1.1'; // not the default * public iface because a user must explicitly configure it
o.rmempty = false;
o = s.option(form.Value, 'localport', _('Local port'));
o.datatype = 'port';
o.placeholder = '80';
o.rmempty = false;
o = s.option(form.Value, 'remoteaddress', _('Remote address'),
_('Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. <code>localhost</code>.')
);
o.datatype = 'host';
o.default = 'localhost';
o.rmempty = false;
o = s.option(form.Value, 'remoteport', _('Remote port'));
o.datatype = 'port';
o.default = '80';
o.rmempty = false;
s = m.section(form.GridSection, 'tunnelD', _('Dynamic Tunnels'),
_('SOCKS proxy via 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'),
_('Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. <code>localhost</code>.') + '<br/>' +
_('<code>*</code> means to listen all interfaces <b>including public</b>.')
);
o.datatype = 'or(host, "*")';
o.placeholder = '192.168.1.1'; // not the default * public iface because a user must explicitly configure it
o.rmempty = false;
o = s.option(form.Value, 'localport', _('Local port'));
o.datatype = 'port';
o.default = '1080';
o.rmempty = false;
s = m.section(form.GridSection, 'tunnelW', _('VPN Tunnels'),
_('Configure TUN/TAP devices for VPN tunnels.')
);
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;
return m.render();
},
});
function _addServerOption(s) {
var o = s.option(form.ListValue, 'server', _('Server'));
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;
}

View file

@ -0,0 +1,303 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:37
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:75
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:113
msgid "<code>*</code> means to listen all interfaces <b>including public</b>."
msgstr ""
"<code>*</code> значит принимать соединения на всех интерфейсах <b>включая "
"публичные</b>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:109
msgid "A key with that name already exists."
msgstr "Ключ с таким именем уже существует."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:128
msgid "Accept new and check if not changed"
msgstr "Принимать новый и проверять что не изменился"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:95
msgid "Add the pub key to %s or %s."
msgstr "Добавьте этот публичный ключ в %s или в %s."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:42
msgid "Advanced Settings"
msgstr "Расширенные настройки"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:36
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:49
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:74
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:87
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:112
msgid ""
"Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. "
"<code>localhost</code>."
msgstr ""
"Принимающий соединения IP адрес н.п. <code>192.168.1.1</code> или имя хоста "
"н.п. <code>localhost</code>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:115
msgid "Check host IP"
msgstr "Проверять IP хоста"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:116
msgid ""
"Check the host IP address in the <code>known_hosts</code> file. This allows "
"ssh to detect whether a host key changed due to DNS spoofing. See "
"<em>ssh_config CheckHostIP</em>"
msgstr ""
"Проверять IP-адрес хоста в файле <code>known_hosts</code>. Это позволяет ssh "
"определить, изменился ли ключ хоста из-за спуфинга DNS."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:80
msgid ""
"Compression may be useful on slow connections. See <em>ssh_config "
"Compression</em>"
msgstr ""
"Сжатие может быть полезным на медленном соединении. См. <em>ssh_config "
"Compression</em>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:126
msgid "Configure TUN/TAP devices for VPN tunnels."
msgstr "Конифгурация устройств TUN/TAP VPN-туннелей."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:89
msgid "Delay after a connection failure before trying to reconnect."
msgstr "Задержка перед переподключением"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:99
msgid "Dynamic Tunnels"
msgstr "Динамические туннели"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:30
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:68
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:106
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:132
msgid "Enabled"
msgstr "Включен"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:62
msgid "Forward a port on the local host to a service on the remote host."
msgstr "Перенаправить порт с локального хоста на сервис на удалённом хосте."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:24
msgid "Forward a port on the remote host to a service on the local host."
msgstr "Перенаправить порт с удалённого хоста на сервис на локальном хосте."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:41
msgid "General Settings"
msgstr "Общие настройки"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:88
msgid "Generate"
msgstr "Сгенерировать"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:73
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 "Предоставить UCI доступ для luci-app-sshtunnel"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:35
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:44
msgid "Hostname"
msgstr "Имя хоста"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:97
msgid ""
"In LuCI you can do that with <a %s>System / Administration / SSH-Keys</a>"
msgstr ""
"В LuCI вы можете это сделать через <a %s>Система / Администрирование / SSH "
"ключи</a>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:107
msgid ""
"Keep-alive interval (seconds). See <em>ssh_config ServerAliveInterval</em>"
msgstr ""
"Интервал проверки подключения (секунды). См. See <em>ssh_config "
"ServerAliveInterval</em>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:56
msgid "Key file"
msgstr "Файл ключа"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:46
msgid "Keys of SSH servers found in %s."
msgstr "Ключи SSH уже известных серверов из %s."
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:38
msgid "Known Hosts"
msgstr "Знакомые хосты"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:44
msgid "Known hosts"
msgstr "Знакомые хосты"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:61
msgid "Local Tunnels"
msgstr "Локальные туннели"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:48
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:73
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:111
msgid "Local address"
msgstr "Локальный адрес"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:142
msgid "Local dev"
msgstr "Локальное устройство dev"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:55
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:81
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:119
msgid "Local port"
msgstr "Локальный порт"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:67
msgid "Log level"
msgstr "Уровень логирования"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:61
msgid "Name"
msgstr "Название"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:84
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:121
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:130
msgid "No"
msgstr "Нет"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:26
msgid "No SSH keys found, <a %s>generate a new one</a>"
msgstr ""
"Нет ни одного ключа, пожалуйста <a href=\"./ssh_keys\">сгенерируйте новый</"
"a>."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:49
msgid "Port"
msgstr "Порт"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:57
msgid ""
"Private key file with authentication identity. See <em>ssh_config "
"IdentityFile</em>"
msgstr ""
"Файл приватного ключа для авторизации. См. <em>ssh_config IdentityFile</em>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:36
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:62
msgid "Public Key"
msgstr "Публичный ключ"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:126
msgid ""
"Refuse to connect to hosts whose host key has changed. See <em>ssh_config "
"StrictHostKeyChecking</em>"
msgstr ""
"Отказывать в подключении к хосту если его ключ поменялся. См. <em>ssh_config "
"StrictHostKeyChecking</em>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:23
msgid "Remote Tunnels"
msgstr "Удалённые туннели"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:35
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:86
msgid "Remote address"
msgstr "Удалённый адресс"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:147
msgid "Remote dev"
msgstr "Удалённое устройство dev"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:43
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:93
msgid "Remote port"
msgstr "Удалённый порт"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:88
msgid "Retry delay"
msgstr "Задержка попытки"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:100
msgid "SOCKS proxy via remote host."
msgstr "SOCKS прокси через удалённый хост."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:93
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:14
msgid "SSH Keys"
msgstr "SSH Ключи"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:20
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:33
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:31
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:18
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:3
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:30
msgid "SSH Tunnels"
msgstr "SSH туннели"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:157
msgid "Server"
msgstr "Сервер"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:97
msgid "Server alive count max"
msgstr "Попыток проверки соединения"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:106
msgid "Server alive interval"
msgstr "Интервал проверки соединения"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:36
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:22
msgid "Servers"
msgstr "Серверы"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:125
msgid "Strict host key checking"
msgstr "Строгая проверка ключа хоста"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:98
msgid ""
"The number of server alive messages which may be sent before SSH disconnects "
"from the server. See <em>ssh_config ServerAliveCountMax</em>"
msgstr ""
"Сколько проверочных сообщений на сервер отправить прежде чем отключиться.См. "
"See <em>ssh_config ServerAliveCountMax</em>"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:21
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:34
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:32
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:19
msgid "This configures <a %s>SSH Tunnels</a>"
msgstr "Настройка <a %s>SSH туннелей</a>."
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:128
msgid "Unable to generate a key: %s"
msgstr "Ошибка при генерации ключа: %s"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:79
msgid "Use compression"
msgstr "Использовать сжатие"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:53
msgid "User"
msgstr "Пользователь"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:125
msgid "VPN Tunnels"
msgstr "VPN туннели"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:137
msgid "VPN type"
msgstr "Тип VPN"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:83
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:120
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:129
msgid "Yes"
msgstr "Да"

View file

@ -0,0 +1,284 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:37
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:75
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:113
msgid "<code>*</code> means to listen all interfaces <b>including public</b>."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:109
msgid "A key with that name already exists."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:128
msgid "Accept new and check if not changed"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:95
msgid "Add the pub key to %s or %s."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:42
msgid "Advanced Settings"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:36
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:49
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:74
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:87
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:112
msgid ""
"Bind IP address e.g. <code>192.168.1.1</code> or hostname e.g. "
"<code>localhost</code>."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:115
msgid "Check host IP"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:116
msgid ""
"Check the host IP address in the <code>known_hosts</code> file. This allows "
"ssh to detect whether a host key changed due to DNS spoofing. See "
"<em>ssh_config CheckHostIP</em>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:80
msgid ""
"Compression may be useful on slow connections. See <em>ssh_config "
"Compression</em>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:126
msgid "Configure TUN/TAP devices for VPN tunnels."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:89
msgid "Delay after a connection failure before trying to reconnect."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:99
msgid "Dynamic Tunnels"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:30
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:68
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:106
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:132
msgid "Enabled"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:62
msgid "Forward a port on the local host to a service on the remote host."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:24
msgid "Forward a port on the remote host to a service on the local host."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:41
msgid "General Settings"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:88
msgid "Generate"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:73
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/ssh_hosts.js:35
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:44
msgid "Hostname"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:97
msgid ""
"In LuCI you can do that with <a %s>System / Administration / SSH-Keys</a>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:107
msgid ""
"Keep-alive interval (seconds). See <em>ssh_config ServerAliveInterval</em>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:56
msgid "Key file"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:46
msgid "Keys of SSH servers found in %s."
msgstr ""
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:38
msgid "Known Hosts"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:44
msgid "Known hosts"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:61
msgid "Local Tunnels"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:48
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:73
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:111
msgid "Local address"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:142
msgid "Local dev"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:55
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:81
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:119
msgid "Local port"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:67
msgid "Log level"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:61
msgid "Name"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:84
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:121
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:130
msgid "No"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:26
msgid "No SSH keys found, <a %s>generate a new one</a>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:49
msgid "Port"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:57
msgid ""
"Private key file with authentication identity. See <em>ssh_config "
"IdentityFile</em>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:36
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:62
msgid "Public Key"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:126
msgid ""
"Refuse to connect to hosts whose host key has changed. See <em>ssh_config "
"StrictHostKeyChecking</em>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:23
msgid "Remote Tunnels"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:35
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:86
msgid "Remote address"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:147
msgid "Remote dev"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:43
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:93
msgid "Remote port"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:88
msgid "Retry delay"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:100
msgid "SOCKS proxy via remote host."
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:93
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:14
msgid "SSH Keys"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:20
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:33
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:31
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:18
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:3
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:30
msgid "SSH Tunnels"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:157
msgid "Server"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:97
msgid "Server alive count max"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:106
msgid "Server alive interval"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:36
#: applications/luci-app-sshtunnel/root/usr/share/luci/menu.d/luci-app-sshtunnel.json:22
msgid "Servers"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:125
msgid "Strict host key checking"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:98
msgid ""
"The number of server alive messages which may be sent before SSH disconnects "
"from the server. See <em>ssh_config ServerAliveCountMax</em>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_hosts.js:21
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:34
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:32
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:19
msgid "This configures <a %s>SSH Tunnels</a>"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js:128
msgid "Unable to generate a key: %s"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:79
msgid "Use compression"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:53
msgid "User"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:125
msgid "VPN Tunnels"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_tunnels.js:137
msgid "VPN type"
msgstr ""
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:83
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:120
#: applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js:129
msgid "Yes"
msgstr ""

View file

@ -0,0 +1,45 @@
{
"admin/services/sshtunnel": {
"title": "SSH Tunnels",
"order": 50,
"action": {
"type": "alias",
"path": "admin/services/sshtunnel/ssh_tunnels"
},
"depends": {
"acl": [ "luci-app-sshtunnel" ]
}
},
"admin/services/sshtunnel/ssh_keys": {
"title": "SSH Keys",
"order": 10,
"action": {
"type": "view",
"path": "sshtunnel/ssh_keys"
}
},
"admin/services/sshtunnel/ssh_servers": {
"title": "Servers",
"order": 20,
"action": {
"type": "view",
"path": "sshtunnel/ssh_servers"
}
},
"admin/services/sshtunnel/ssh_tunnels": {
"title": "SSH Tunnels",
"order": 30,
"action": {
"type": "view",
"path": "sshtunnel/ssh_tunnels"
}
},
"admin/services/sshtunnel/ssh_hosts": {
"title": "Known Hosts",
"order": 40,
"action": {
"type": "view",
"path": "sshtunnel/ssh_hosts"
}
}
}

View file

@ -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" ]
}
}
}