luci-app-tor: Manage tor-hs onion services (#6476)
authorSergey Ponomarev <stokito@gmail.com>
Mon, 4 Dec 2023 19:09:55 +0000 (21:09 +0200)
committerGitHub <noreply@github.com>
Mon, 4 Dec 2023 19:09:55 +0000 (20:09 +0100)
* luci-app-tor: Manage Onion services (tor-hs)

The tor-hs packages provides Tor Onion (Hidden) Services.
This is a good option to bypass NAT and have stable access to a router.

Later once the main Tor package gains a support of a Proxy/Bridge configuration.
We can add this to the same luci app as a different view.

Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
applications/luci-app-tor/Makefile [new file with mode: 0644]
applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js [new file with mode: 0644]
applications/luci-app-tor/po/ru/tor.po [new file with mode: 0644]
applications/luci-app-tor/po/templates/tor.pot [new file with mode: 0644]
applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json [new file with mode: 0644]
applications/luci-app-tor/root/usr/share/rpcd/acl.d/luci-app-tor.json [new file with mode: 0644]

diff --git a/applications/luci-app-tor/Makefile b/applications/luci-app-tor/Makefile
new file mode 100644 (file)
index 0000000..caecd80
--- /dev/null
@@ -0,0 +1,14 @@
+# See /LICENSE for more information.
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI app to configure Tor
+LUCI_DEPENDS:=+luci-base +tor +tor-hs
+PKG_VERSION:=1.0.0
+PKG_RELEASE:=1
+PKG_MAINTAINER:=Sergey Ponomarev <stokito@gmail.com>
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js b/applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js
new file mode 100644 (file)
index 0000000..ef8368e
--- /dev/null
@@ -0,0 +1,108 @@
+'use strict';
+'require view';
+'require form';
+'require rpc';
+'require uci';
+
+var callTorHsList = rpc.declare({
+       object: 'tor-hs-rpc',
+       method: 'list-hs',
+});
+
+
+return view.extend({
+       load: function () {
+               return Promise.all([
+                       L.resolveDefault(callTorHsList(), {}),
+               ]);
+       },
+
+       render: function (data) {
+               var hsList = [];
+               if (data[0]['hs-list']) {
+                       hsList = data[0]['hs-list'];
+               }
+               var hsMap = new Map();
+               hsList.forEach(function (hs) {
+                       hsMap.set(hs.name, hs.hostname);
+               });
+
+               var m, s, o;
+
+               m = new form.Map('tor-hs', _('Tor Onion Services'),
+                       _('Tor Onion (Hidden) Services are proxy tunnels to your local website, SSH and other services.') + '<br />' +
+                       _('For further information <a %s>check the documentation</a>')
+                               .format('href="https://openwrt.org/docs/guide-user/services/tor/hs" target="_blank" rel="noreferrer"')
+               );
+
+               s = m.section(form.GridSection, 'hidden-service', _('Tor Onion Services'));
+               s.addremove = true;
+               s.nodescriptions = true;
+               s.sectiontitle = function (section_id) {
+                       let tor = uci.get('tor-hs', section_id);
+                       let sectionName = section_id;
+                       if (tor['.anonymous']) {
+                               sectionName = tor['Name'];
+                       }
+                       return sectionName;
+               };
+
+               o = s.option(form.Flag, 'Enabled', _('Enabled'));
+               o.default = '1';
+               o.rmempty = false;
+               // We also need to set Name field with the same name as section
+               // The only option to do that is to override write() for some other field i.e. Enabled
+               o.write = function (section_id, formvalue) {
+                       // first save the Enabled
+                       uci.set('tor-hs', section_id, 'Enabled', formvalue);
+                       // set Name field
+                       var name = this.map.data.get(this.map.config, section_id, 'Name') || '';
+                       if (!name) {
+                               // Typically the empty Name happens for new unsaved sections
+                               name = section_id;
+                               // manually set Name to trigger change
+                               uci.set('tor-hs', section_id, 'Name', name);
+                       }
+                       return name;
+               };
+
+               o = s.option(form.DummyValue, '_Domain', _('Onion domain'));
+               o.modalonly = false;
+               o.rawhtml = true;
+               o.textvalue = function (section_id) {
+                       var name = uci.get('tor-hs', section_id, 'Name');
+                       if (!name)
+                               return '';
+                       var hostname = hsMap.get(name);
+                       if (!hostname)
+                               return '';
+                       return '<a href="http://' + hostname + '" target="_blank" rel="noreferrer">' + _('Link') + '</a>';
+               };
+
+               o = s.option(form.Value, 'Description', _('Description'));
+               o.modalonly = true;
+
+               o = s.option(form.Value, 'IPv4', _('Destination address'),
+                       _('Traffic will be forwarded to the target hostname')
+               );
+               o.datatype = 'host';
+               o.default = '127.0.0.1';
+
+               o = s.option(form.DynamicList, 'PublicLocalPort', _('Public ports to local'),
+                       _('A single <code>Port</code> when the public port is the same as local e.g. <code>80</code>.') + '<br />' +
+                       _('A pair <code>PublicPort;LocalPort</code> e.g. <code>80;8080</code>.') + '<br />' +
+                       _('A pair <code>PublicPort;unix:Socket</code> e.g. <code>80;unix:/var/run/nginx.sock</code>.')
+               );
+               o.datatype = 'list(string)';
+               o.default = ['80', '443']; // by default expose http and https ports
+               o.rmempty = false;
+
+               o = s.option(form.Value, 'HookScript', _('Hook Script'),
+                       _('Path to script which is executed after starting Tor.') + '<br />' +
+                       _('The .onion domain is passed into the script via parameter <code>--update-onion HOSTNAME</code>.')
+               );
+               o.modalonly = true;
+
+               return m.render();
+       },
+});
diff --git a/applications/luci-app-tor/po/ru/tor.po b/applications/luci-app-tor/po/ru/tor.po
new file mode 100644 (file)
index 0000000..106e852
--- /dev/null
@@ -0,0 +1,93 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:93
+msgid "A pair <code>PublicPort;LocalPort</code> e.g. <code>80;8080</code>."
+msgstr "Пара <code>ПубличныйПорт;ЛокальныйПорт</code> н.п. <code>80;8080</code>"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:94
+msgid ""
+"A pair <code>PublicPort;unix:Socket</code> e.g. <code>80;unix:/var/run/nginx."
+"sock</code>."
+msgstr ""
+"Пара <code>ПубличныйПорт;unix:Сокет</code> н.п. <code>80;unix:/var/run/nginx."
+"sock</code>."
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:92
+msgid ""
+"A single <code>Port</code> when the public port is the same as local e.g. "
+"<code>80</code>."
+msgstr ""
+"Один <code>Порт</code> когда публичный порт такой же как и локальный н.п. "
+"<code>80</code>."
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:82
+msgid "Description"
+msgstr "Описание"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:85
+msgid "Destination address"
+msgstr "Aдрес назначения"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:50
+msgid "Enabled"
+msgstr "Включен"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:34
+msgid "For further information <a %s>check the documentation</a>"
+msgstr ""
+"Для получения дополнительной информации <a %s>смотрите документацию</a>"
+
+#: applications/luci-app-tor/root/usr/share/rpcd/acl.d/luci-app-tor.json:3
+msgid "Grant UCI access for luci-app-tor"
+msgstr "Предоставить UCI доступ для LuCI приложения Tor"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:100
+msgid "Hook Script"
+msgstr "Скрипт хука"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:79
+msgid "Link"
+msgstr "Ссылка"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:69
+msgid "Onion domain"
+msgstr "Домен Onion"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:101
+msgid "Path to script which is executed after starting Tor."
+msgstr "Путь к скрипту который будет выполнен после запуска Tor."
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:91
+msgid "Public ports to local"
+msgstr "Публичные порты к Локальным"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:102
+msgid ""
+"The .onion domain is passed into the script via parameter <code>--update-"
+"onion HOSTNAME</code>."
+msgstr ""
+"Домен .onion передаётся в скрипт через параметр <code>--update-onion "
+"HOSTNAME</code>."
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:33
+msgid ""
+"Tor Onion (Hidden) Services are proxy tunnels to your local website, SSH and "
+"other services."
+msgstr ""
+"Tor Onion (Hidden) Services (луковичные/скрытые сервисы Tor) это прокси "
+"тунели к вашему локальному вебсайту, SSH и другим сервисам."
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:32
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:38
+#: applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json:16
+msgid "Tor Onion Services"
+msgstr "Tor Onion Сервисы"
+
+#: applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json:3
+msgid "Tor onion router"
+msgstr "Tor луковичный роутер"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:86
+msgid "Traffic will be forwarded to the target hostname"
+msgstr "Трафик будет переправлен по этому имени хоста"
diff --git a/applications/luci-app-tor/po/templates/tor.pot b/applications/luci-app-tor/po/templates/tor.pot
new file mode 100644 (file)
index 0000000..b2c0cad
--- /dev/null
@@ -0,0 +1,84 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:93
+msgid "A pair <code>PublicPort;LocalPort</code> e.g. <code>80;8080</code>."
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:94
+msgid ""
+"A pair <code>PublicPort;unix:Socket</code> e.g. <code>80;unix:/var/run/nginx."
+"sock</code>."
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:92
+msgid ""
+"A single <code>Port</code> when the public port is the same as local e.g. "
+"<code>80</code>."
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:82
+msgid "Description"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:85
+msgid "Destination address"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:50
+msgid "Enabled"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:34
+msgid "For further information <a %s>check the documentation</a>"
+msgstr ""
+
+#: applications/luci-app-tor/root/usr/share/rpcd/acl.d/luci-app-tor.json:3
+msgid "Grant UCI access for luci-app-tor"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:100
+msgid "Hook Script"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:79
+msgid "Link"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:69
+msgid "Onion domain"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:101
+msgid "Path to script which is executed after starting Tor."
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:91
+msgid "Public ports to local"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:102
+msgid ""
+"The .onion domain is passed into the script via parameter <code>--update-"
+"onion HOSTNAME</code>."
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:33
+msgid ""
+"Tor Onion (Hidden) Services are proxy tunnels to your local website, SSH and "
+"other services."
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:32
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:38
+#: applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json:16
+msgid "Tor Onion Services"
+msgstr ""
+
+#: applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json:3
+msgid "Tor onion router"
+msgstr ""
+
+#: applications/luci-app-tor/htdocs/luci-static/resources/view/tor/tor-hs.js:86
+msgid "Traffic will be forwarded to the target hostname"
+msgstr ""
diff --git a/applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json b/applications/luci-app-tor/root/usr/share/luci/menu.d/luci-app-tor.json
new file mode 100644 (file)
index 0000000..19777f6
--- /dev/null
@@ -0,0 +1,23 @@
+{
+       "admin/services/tor": {
+               "title": "Tor onion router",
+               "order": 60,
+               "action": {
+                       "type": "alias",
+                       "path": "admin/services/tor/tor-hs"
+               },
+               "depends": {
+                       "acl": [
+                               "luci-app-tor"
+                       ]
+               }
+       },
+       "admin/services/tor/tor-hs": {
+               "title": "Tor Onion Services",
+               "order": 20,
+               "action": {
+                       "type": "view",
+                       "path": "tor/tor-hs"
+               }
+       }
+}
diff --git a/applications/luci-app-tor/root/usr/share/rpcd/acl.d/luci-app-tor.json b/applications/luci-app-tor/root/usr/share/rpcd/acl.d/luci-app-tor.json
new file mode 100644 (file)
index 0000000..81bb927
--- /dev/null
@@ -0,0 +1,22 @@
+{
+       "luci-app-tor": {
+               "description": "Grant UCI access for luci-app-tor",
+               "read": {
+                       "ubus": {
+                               "tor_rpcd.sh": [
+                                       "list-hs"
+                               ]
+                       },
+                       "uci": [
+                               "tor",
+                               "tor-hs"
+                       ]
+               },
+               "write": {
+                       "uci": [
+                               "tor",
+                               "tor-hs"
+                       ]
+               }
+       }
+}