luci-proto-yggdrasil: add `yggdrasil-jumper` support
authorRemy D. Farley <one-d-wide@protonmail.com>
Sun, 7 Jan 2024 11:50:55 +0000 (11:50 +0000)
committerPaul Donald <itsascambutmailmeanyway+github@gmail.com>
Wed, 3 Apr 2024 16:33:05 +0000 (18:33 +0200)
Signed-off-by: Remy D. Farley <one-d-wide@protonmail.com>
protocols/luci-proto-yggdrasil/Makefile
protocols/luci-proto-yggdrasil/htdocs/luci-static/resources/protocol/yggdrasil.js
protocols/luci-proto-yggdrasil/root/usr/libexec/rpcd/luci.yggdrasil-jumper [new file with mode: 0755]
protocols/luci-proto-yggdrasil/root/usr/share/rpcd/acl.d/luci-proto-yggdrasil.json

index ecd20fb6550aa71445abf0573a68238a9c7703b8..751994021796d52faf9edc8b725a240e7a41ce83 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 LUCI_TITLE:=Support for Yggdrasil Network
 LUCI_DEPENDS:=+yggdrasil
 LUCI_PKGARCH:=all
-PKG_VERSION:=1.0.0
+PKG_VERSION:=1.1.0
 
 PKG_PROVIDES:=luci-proto-yggdrasil
 
index 849242abfffc15a5877666ad175f83a38242c3f6..66159764cec0b5f98906aabdf9b6da67cca37879 100644 (file)
@@ -158,6 +158,42 @@ var getPeers = rpc.declare({
        expect:{peers:[]}
 });
 
+var callIsJumperInstalled = rpc.declare({
+       object:'luci.yggdrasil-jumper',
+       method:'isInstalled',
+       expect:{isInstalled: false}
+});
+
+var callValidateJumperConfig = rpc.declare({
+       object:'luci.yggdrasil-jumper',
+       method:'validateConfig',
+       params:['config'],
+       expect:{output: "Unknown error."}
+});
+
+function validateJumperConfig(section) {
+       var last_input = "", last_output = "";
+
+       return function(section_id, input) {
+               if (last_input != input) {
+                       last_input = input
+
+                       callValidateJumperConfig(input).then(function(output) {
+                               last_output = output;
+
+                               var option = section.getUIElement(section_id).jumper_config;
+                               option.triggerValidation(section_id);
+                       });
+               }
+
+               if (last_output.length == 0) {
+                       return true;
+               }
+
+               return _(last_output);
+       };
+};
+
 return network.registerProtocol('yggdrasil',
        {
                getI18n: function() {
@@ -257,6 +293,87 @@ return network.registerProtocol('yggdrasil',
                        o=ss.option(form.Value,"password",_("Password"));
                        o.optional=true;
 
+                       // Jumper tab
+                       try {
+                               s.tab('jumper',_('Jumper'));
+                       } catch(e) {};
+
+                       o=s.taboption(
+                               'jumper',
+                               form.HiddenValue,
+                               'hidden_value',
+                               ' ',
+                               _('%s is an independent project that aims to transparently reduce latency of a connection over Yggdrasil network, utilizing NAT traversal to bypass intermediary nodes.'.format('<a href="https://github.com/one-d-wide/yggdrasil-jumper">Yggdrasil Jumper</a>'))
+                                       + ' ' + _('It periodically probes for active sessions and automatically establishes direct peerings over internet with remote nodes running Yggdrasil Jumper without requiring firewall or port configuration.')
+                       );
+
+                       o=s.taboption(
+                               'jumper',
+                               form.Flag,
+                               'jumper_enable',
+                               _('Enable Yggdrasil Jumper'),
+                               _('The checkbox cannot be modified unless the <code>yggdrasil-jumper</code> package is installed.')
+                       );
+                       o.default=false;
+                       o.rmempty=false;
+                       o.readonly=true;
+
+                       // Unlock enable option if jumper is installed
+                       callIsJumperInstalled().then(function(isInstalled) {
+                               if (isInstalled) {
+                                       var o = s.children.find(function(o) { return o.option == "jumper_enable"; });
+                                       o.readonly = false;
+                                       // Explicit rerendering request isn't needed because the protocol tab
+                                       // is constructed only after all async functions is done
+                               }
+                       });
+
+                       o=s.taboption(
+                               'jumper',
+                               form.ListValue,
+                               'jumper_loglevel',
+                               _('Log level'),
+                               _('')
+                       );
+                       o.value('off', _('Off'));
+                       o.value('error', _('Error'));
+                       o.value('warn', _('Warn'));
+                       o.value('info', _('Info'));
+                       o.value('debug', _('Debug'));
+                       o.value('trace', _('Trace'));
+                       o.default='info';
+                       o.rmempty=false;
+
+                       o=s.taboption(
+                               'jumper',
+                               form.Flag,
+                               'allocate_listen_addresses',
+                               _('Allocate listen addresses'),
+                               _('Allow Yggdrasil Jumper to automatically configure Yggdrasil with proper listen address and random port.')
+                       );
+                       o.default=true;
+                       o.rmempty=false;
+
+                       o=s.taboption(
+                               'jumper',
+                               form.Flag,
+                               'jumper_autofill_listen_addresses',
+                               _('Autofill listen addresses'),
+                               _('Retrieve the listener addresses from the Yggdrasil interface configuration.')
+                       );
+                       o.default=true;
+                       o.rmempty=false;
+
+                       o=s.taboption(
+                               'jumper',
+                               form.TextValue,
+                               'jumper_config',
+                               _('Extra config'),
+                               _('Additional configuration settings (in TOML format).')
+                       );
+                       o.optional=true;
+                       o.validate=validateJumperConfig(s);
+
                        return;
                },
                deleteConfiguration: function() {
diff --git a/protocols/luci-proto-yggdrasil/root/usr/libexec/rpcd/luci.yggdrasil-jumper b/protocols/luci-proto-yggdrasil/root/usr/libexec/rpcd/luci.yggdrasil-jumper
new file mode 100755 (executable)
index 0000000..62c35b0
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+. /usr/share/libubox/jshn.sh
+
+isInstalled() {
+       [ -f /usr/sbin/yggdrasil-jumper ]
+}
+
+case "$1" in
+       list)
+               json_init
+               json_add_object "isInstalled"
+               json_close_object
+               json_add_object "validateConfig"
+               json_add_string "config"
+               json_close_object
+               json_dump
+       ;;
+       call)
+               case "$2" in
+                       isInstalled)
+                               json_init
+                               json_add_boolean "isInstalled" "$(isInstalled && echo 1 || echo 0)"
+                               json_dump
+                       ;;
+                       validateConfig)
+                               read -r input
+                               json_load "$input"
+                               json_get_vars config
+
+                               output="Can't locate `yggdrasil-jumper`"
+                               isInstalled && \
+                                       output="$(echo "$config" \
+                                               | yggdrasil-jumper --validate --config - 2&>1 \
+                                               | sed -E 's/(.{100}[^ ]*) /\1\n/g')"
+
+                               json_init
+                               json_add_string output "$output"
+                               json_dump
+                       ;;
+               esac
+       ;;
+esac
+
index 0351d8610db72bd4043982a0996b83ad6ceb781f..cb8bd9ff561f647120d6f971b5dad03c9107fd3e 100644 (file)
@@ -3,7 +3,8 @@
                "description": "Grant access to LuCI Yggdrasil procedures",
                "write": {
                        "ubus": {
-                               "luci.yggdrasil": [ "generateKeyPair", "getPeers" ]
+                               "luci.yggdrasil": [ "generateKeyPair", "getPeers" ],
+                               "luci.yggdrasil-jumper": [ "isInstalled", "validateConfig" ]
                        }
                }
        }