diff --git a/frontend/ui/elements/common_settings_menu_table.lua b/frontend/ui/elements/common_settings_menu_table.lua index d9a527112..66d51b4d3 100644 --- a/frontend/ui/elements/common_settings_menu_table.lua +++ b/frontend/ui/elements/common_settings_menu_table.lua @@ -100,8 +100,8 @@ common_settings.night_mode = { } common_settings.network = { text = _("Network"), - sub_item_table = NetworkMgr:getMenuTable() } +NetworkMgr:getMenuTable(common_settings) common_settings.screen = { text = _("Screen"), diff --git a/frontend/ui/elements/filemanager_menu_order.lua b/frontend/ui/elements/filemanager_menu_order.lua index 06ad04ad6..98347b009 100644 --- a/frontend/ui/elements/filemanager_menu_order.lua +++ b/frontend/ui/elements/filemanager_menu_order.lua @@ -33,6 +33,15 @@ local order = { "time", -- end common settings }, + network = { + "network_wifi", + "network_proxy", + "network_restore", + "network_info", + "network_before_wifi_action", + "----------------------------", + "ssh", + }, tools = { "calibre_wireless_connection", "evernote", diff --git a/frontend/ui/elements/reader_menu_order.lua b/frontend/ui/elements/reader_menu_order.lua index b1354e6d7..ad058a011 100644 --- a/frontend/ui/elements/reader_menu_order.lua +++ b/frontend/ui/elements/reader_menu_order.lua @@ -52,6 +52,15 @@ local order = { "djvu_render_mode", "status_bar", }, + network = { + "network_wifi", + "network_proxy", + "network_restore", + "network_info", + "network_before_wifi_action", + "----------------------------", + "ssh", + }, tools = { "read_timer", "calibre_wireless_connection", diff --git a/frontend/ui/network/manager.lua b/frontend/ui/network/manager.lua index 736a7bf16..563612886 100644 --- a/frontend/ui/network/manager.lua +++ b/frontend/ui/network/manager.lua @@ -244,14 +244,12 @@ function NetworkMgr:getBeforeWifiActionMenuTable() } end -function NetworkMgr:getMenuTable() - return { - self:getWifiMenuTable(), - self:getProxyMenuTable(), - self:getRestoreMenuTable(), - self:getInfoMenuTable(), - self:getBeforeWifiActionMenuTable(), - } +function NetworkMgr:getMenuTable(common_settings) + common_settings.network_wifi = self:getWifiMenuTable() + common_settings.network_proxy = self:getProxyMenuTable() + common_settings.network_restore = self:getRestoreMenuTable() + common_settings.network_info = self:getInfoMenuTable() + common_settings.network_before_wifi_action = self:getBeforeWifiActionMenuTable() end function NetworkMgr:showNetworkMenu(complete_callback) diff --git a/plugins/SSH.koplugin/main.lua b/plugins/SSH.koplugin/main.lua new file mode 100644 index 000000000..ccebbfda5 --- /dev/null +++ b/plugins/SSH.koplugin/main.lua @@ -0,0 +1,158 @@ +local DataStorage = require("datastorage") +local Device = require("device") +local InfoMessage = require("ui/widget/infomessage") -- luacheck:ignore +local InputDialog = require("ui/widget/inputdialog") +local UIManager = require("ui/uimanager") +local WidgetContainer = require("ui/widget/container/widgetcontainer") +local logger = require("logger") +local util = require("util") +local _ = require("gettext") + +-- This plugin use a patched dropbear that add two things : +-- the -n option to allow login without password +-- read the keyfile from the relative path: settings/SSH/authorized_keys + +local path = DataStorage:getFullDataDir() +if not util.pathExists("dropbearmulti") then + return { disabled = true, } +end + +local SSH = WidgetContainer:new{ + name = 'SSH', + is_doc_only = false, +} + +function SSH:init() + self.SSH_port = G_reader_settings:readSetting("SSH_port") or "2222" + self.allow_no_password = false + self.ui.menu:registerToMainMenu(self) +end + +function SSH:start() + local cmd = string.format("%s %s %s %s%s %s %s %s", + "./dropbearmulti dropbear", + "-E", "-r ", path, "/settings/SSH/dropbear_rsa_host_key", + "-p", self.SSH_port, + "-P /tmp/dropbear_koreader.pid") + if self.allow_no_password then + cmd = string.format("%s %s", cmd, "-n") + end + if os.execute("command -v iptables") then + os.execute(string.format("%s %s %s", + "iptables -A INPUT -p tcp --dport", self.SSH_port, + "-m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT")) + os.execute(string.format("%s %s %s", + "iptables -A OUTPUT -p tcp --sport", self.SSH_port, + "-m conntrack --ctstate ESTABLISHED -j ACCEPT")) + end + -- An SSH/telnet server of course needs to be able to manipulate pseudoterminals... + -- Some Kobo don't have this, so we check it on every platfrom, it can't hurt. + os.execute([[if [ ! -d "/dev/pts" ] ; then + mkdir -p /dev/pts + mount -t devpts devpts /dev/pts + fi]]) + if not util.pathExists(path.."/settings/SSH/") then + os.execute("mkdir "..path.."/settings/SSH") + end + if not util.pathExists(path.."/settings/SSH/dropbear_rsa_host_key") then + os.execute("./dropbearmulti dropbearkey -t rsa -f "..path.."/settings/SSH/dropbear_rsa_host_key") + end + logger.dbg("[Network] Launching SSH server : ", cmd) + if os.execute(cmd) == 0 then + local info = InfoMessage:new{ + timeout = 5, + text = string.format("%s %s \n %s", + _("SSH port: "), self.SSH_port, + Device.retrieveNetworkInfo and Device:retrieveNetworkInfo() or _("Could not retrieve network info.")), + } + UIManager:show(info) + else + local info = InfoMessage:new{ + timeout = 5, + text = _("Error"), + } + UIManager:show(info) + end +end + +function SSH:isRunning() + return util.pathExists("/tmp/dropbear_koreader.pid") +end + +function SSH:stop() + os.execute("cat /tmp/dropbear_koreader.pid | xargs kill") +end + +function SSH:show_port_dialog() + self.port_dialog = InputDialog:new{ + title = _("Choose SSH port"), + input = self.SSH_port, + input_type = "number", + input_hint = self.SSH_port, + buttons = { + { + { + text = _("Cancel"), + callback = function() + UIManager:close(self.port_dialog) + end, + }, + { + text = _("Save"), + is_enter_default = true, + callback = function() + local value = tonumber(self.port_dialog:getInputText()) + if value then + self.SSH_port = value + G_reader_settings:saveSetting("SSH_port", self.SSH_port) + UIManager:close(self.port_dialog) + end + end + }, + }, + }, + } + UIManager:show(self.port_dialog) + self.port_dialog:onShowKeyboard() +end + +function SSH:addToMainMenu(menu_items) + menu_items.ssh = { + text = _("SSH server"), + sub_item_table = { + { + text = _("Start SSH server"), + callback = function() return self:start() end, + enabled_func = function() return not self:isRunning() end, + }, + { + text = _("Stop SSH server"), + callback = self.stop, + enabled_func = self.isRunning, + }, + { + text = _("Change SSH port"), + enabled_func = function() return not self:isRunning() end, + callback = function() return self:show_port_dialog() end, + }, + { + text = _("Login without password (DANGEROUS)"), + checked_func = function() return self.allow_no_password end, + enabled_func = function() return not self:isRunning() end, + callback = function() self.allow_no_password = not self.allow_no_password end, + }, + { + text = _("SSH public key"), + callback = function() + local info = InfoMessage:new{ + timeout = 60, + text = _("Put your public SSH keys in "..path.."/settings/SSH/authorized_keys"), + } + UIManager:show(info) + end, + }, + } + } +end + +return SSH