From 8530232f518150141a756e7a9fe4297dcf326639 Mon Sep 17 00:00:00 2001 From: lvoegl Date: Wed, 8 Sep 2021 12:56:10 +0200 Subject: [PATCH] luci-proto-wireguard: client qr code generation Signed-off-by: lvoegl --- .../root/usr/libexec/rpcd/luci.wireguard | 17 +++++ .../resources/protocol/wireguard.js | 69 +++++++++++++++++++ .../usr/share/rpcd/acl.d/luci-wireguard.json | 5 +- 3 files changed, 90 insertions(+), 1 deletion(-) mode change 100644 => 100755 applications/luci-app-wireguard/root/usr/libexec/rpcd/luci.wireguard diff --git a/applications/luci-app-wireguard/root/usr/libexec/rpcd/luci.wireguard b/applications/luci-app-wireguard/root/usr/libexec/rpcd/luci.wireguard old mode 100644 new mode 100755 index 7354ad4922..fd3b4c8c44 --- a/applications/luci-app-wireguard/root/usr/libexec/rpcd/luci.wireguard +++ b/applications/luci-app-wireguard/root/usr/libexec/rpcd/luci.wireguard @@ -4,6 +4,7 @@ local json = require "luci.jsonc" local sys = require "luci.sys" local io = require "io" local uci = require "uci" +local fs = require "nixio.fs" local methods = { generateKeyPair = { @@ -14,6 +15,22 @@ local methods = { return {keys = {priv = prv, pub = pub}} end }, + generateQrCode = { + args = {privkey = "privkey"}, + call = function(args) + local qr_code + + if fs.access("/usr/bin/qrencode") then + local pubkey = sys.exec("echo '" .. args.privkey .. "' | wg pubkey 2>/dev/null"):sub(1, -2) + local client_privkey = sys.exec("wg genkey 2>/dev/null"):sub(1, -2) + local qr_enc = "[Interface]\nPrivateKey = " .. client_privkey .. "\n[Peer]\nPublicKey = " .. pubkey .. "\nAllowedIPs = 0.0.0.0/0, ::/0" + + qr_code = sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- '" .. qr_enc .. "' 2>/dev/null") + end + + return {qr_code = qr_code} + end + }, getWgInstances = { call = function() local data = {} diff --git a/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js b/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js index e7e69a3d5b..68dfb5bae6 100644 --- a/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js +++ b/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js @@ -11,6 +11,13 @@ var generateKey = rpc.declare({ expect: { keys: {} } }); +var generateQrCode = rpc.declare({ + object: 'luci.wireguard', + method: 'generateQrCode', + params: ['privkey'], + expect: { qr_code: '' } +}); + function validateBase64(section_id, value) { if (value.length == 0) return true; @@ -24,6 +31,15 @@ function validateBase64(section_id, value) { return true; } +function findSection(sections, name) { + for (var i = 0; i < sections.length; i++) { + var section = sections[i]; + if (section['.name'] == name) return section; + } + + return null; +} + return network.registerProtocol('wireguard', { getI18n: function() { return _('WireGuard VPN'); @@ -131,6 +147,59 @@ return network.registerProtocol('wireguard', { o.datatype = 'string'; o.optional = true; + o = ss.option(form.Value, 'description', _('QR-Code')); + o.render = L.bind(function (view, section_id) { + var sections = uci.sections('network'); + var serverName = this.getIfname(); + var server = findSection(sections, serverName); + + var description = '%s:
• [Interface] %s
• [Peer] %s'.format( + _('The QR-Code works per wg interface, it will be refreshed with every button click and transfers the following information'), + _('A random, on the fly generated "PrivateKey", the key will not be saved on the router'), + _('The "PublicKey" of that wg interface and the "AllowedIPs" with the default of "0.0.0.0/0, ::/0" to allow sending traffic to any IPv4 and IPv6 address') + ); + + return E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('QR-Code')), + E('div', { + 'style': 'display: flex; flex-direction: column; align-items: baseline;', + 'id': 'qr-' + section_id + }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-apply', + 'click': ui.createHandlerFn(this, function (publicKey, section_id) { + var qrDiv = document.getElementById('qr-' + section_id); + var qrEl = qrDiv.querySelector('value'); + var qrBtn = qrDiv.querySelector('button'); + var qrencodeErr = '%q'.format( + _('For QR-Code support please install the qrencode package!')); + + if (qrEl.innerHTML != '' && qrEl.innerHTML != qrencodeErr) { + qrEl.innerHTML = ''; + qrBtn.innerHTML = _('Generate New QR-Code') + } else { + qrEl.innerHTML = _('Loading QR-Code...'); + + generateQrCode(publicKey).then(function (qrCode) { + if (qrCode == '') { + qrEl.innerHTML = qrencodeErr; + } else { + qrEl.innerHTML = qrCode; + qrBtn.innerHTML = _('Hide QR-Code'); + } + }); + } + }, server.private_key, section_id) + }, _('Generate new QR-Code')), + E('value', { + 'class': 'cbi-section', + 'style': 'margin: 0;' + }), + E('div', { 'class': 'cbi-value-description' }, description) + ]) + ]); + }, this); + o = ss.option(form.Value, 'public_key', _('Public Key'), _('Required. Base64-encoded public key of peer.')); o.validate = validateBase64; o.rmempty = false; diff --git a/protocols/luci-proto-wireguard/root/usr/share/rpcd/acl.d/luci-wireguard.json b/protocols/luci-proto-wireguard/root/usr/share/rpcd/acl.d/luci-wireguard.json index 4bbcb81578..04877d4f49 100644 --- a/protocols/luci-proto-wireguard/root/usr/share/rpcd/acl.d/luci-wireguard.json +++ b/protocols/luci-proto-wireguard/root/usr/share/rpcd/acl.d/luci-wireguard.json @@ -3,7 +3,10 @@ "description": "Grant access to LuCI Wireguard procedures", "write": { "ubus": { - "luci.wireguard": [ "generateKeyPair" ] + "luci.wireguard": [ + "generateKeyPair", + "generateQrCode" + ] } } } -- 2.30.2