+++ /dev/null
-#!/usr/bin/env lua
-
-local json = require "luci.jsonc"
-local util = require "luci.util"
-local sys = require "luci.sys"
-local io = require "io"
-local uci = require "uci"
-local fs = require "nixio.fs"
-
-local methods = {
- generatePsk = {
- call = function()
- local psk = sys.exec("wg genpsk"):sub(1, -2)
-
- return {psk = psk}
- end
- },
- generateKeyPair = {
- call = function()
- local prv = sys.exec("wg genkey 2>/dev/null"):sub(1, -2)
- local pub = sys.exec("echo %s | wg pubkey 2>/dev/null" % util.shellquote(prv)):sub(1, -2)
-
- return {keys = {priv = prv, pub = pub}}
- end
- },
- getPublicAndPrivateKeyFromPrivate = {
- args = {privkey = "privkey"},
- call = function(args)
- local pubkey = sys.exec("echo %s | wg pubkey 2>/dev/null" % util.shellquote(args.privkey)):sub(1, -2)
-
- return {keys = {priv = args.privkey, pub = pubkey}}
- end
- },
- getWgInstances = {
- call = function()
- local data = {}
- local last_device = ""
- local qr_pubkey = {}
-
- local wg_dump = io.popen("wg show all dump 2>/dev/null")
- if wg_dump then
- local line
- for line in wg_dump:lines() do
- local line = string.split(line, "\t")
- if not (last_device == line[1]) then
- last_device = line[1]
- data[line[1]] = {
- name = line[1],
- public_key = line[3],
- listen_port = line[4],
- fwmark = line[5],
- peers = {}
- }
- if not line[3] or line[3] == "" or line[3] == "(none)" then
- qr_pubkey[line[1]] = ""
- else
- qr_pubkey[line[1]] = "PublicKey = " .. line[3]
- end
- else
- local peer_name
- local cur = uci.cursor()
-
- cur:foreach(
- "network",
- "wireguard_" .. line[1],
- function(s)
- if s.public_key == line[2] then
- peer_name = s.description
- end
- end
- )
-
- local peer = {
- name = peer_name,
- public_key = line[2],
- endpoint = line[4],
- allowed_ips = {},
- latest_handshake = line[6],
- transfer_rx = line[7],
- transfer_tx = line[8],
- persistent_keepalive = line[9]
- }
-
- if not (line[4] == "(none)") then
- local ipkey, ipvalue
- for ipkey, ipvalue in pairs(string.split(line[5], ",")) do
- if #ipvalue > 0 then
- table.insert(peer["allowed_ips"], ipvalue)
- end
- end
- end
-
- table.insert(data[line[1]].peers, peer)
- end
- end
- end
-
- return data
- end
- }
-}
-
-local function parseInput()
- local parse = json.new()
- local done, err
-
- while true do
- local chunk = io.read(4096)
- if not chunk then
- break
- elseif not done and not err then
- done, err = parse:parse(chunk)
- end
- end
-
- if not done then
- print(json.stringify({error = err or "Incomplete input"}))
- os.exit(1)
- end
-
- return parse:get()
-end
-
-local function validateArgs(func, uargs)
- local method = methods[func]
- if not method then
- print(json.stringify({error = "Method not found"}))
- os.exit(1)
- end
-
- if type(uargs) ~= "table" then
- print(json.stringify({error = "Invalid arguments"}))
- os.exit(1)
- end
-
- uargs.ubus_rpc_session = nil
-
- local k, v
- local margs = method.args or {}
- for k, v in pairs(uargs) do
- if margs[k] == nil or (v ~= nil and type(v) ~= type(margs[k])) then
- print(json.stringify({error = "Invalid arguments"}))
- os.exit(1)
- end
- end
-
- return method
-end
-
-if arg[1] == "list" then
- local _, method, rv = nil, nil, {}
- for _, method in pairs(methods) do
- rv[_] = method.args or {}
- end
- print((json.stringify(rv):gsub(":%[%]", ":{}")))
-elseif arg[1] == "call" then
- local args = parseInput()
- local method = validateArgs(arg[2], args)
- local result, code = method.call(args)
- print((json.stringify(result):gsub("^%[%]$", "{}")))
- os.exit(code or 0)
-end
--- /dev/null
+// Copyright 2022 Jo-Philipp Wich <jo@mein.io>
+// Licensed to the public under the Apache License 2.0.
+
+'use strict';
+
+import { cursor } from 'uci';
+import { popen } from 'fs';
+
+
+function shellquote(s) {
+ return `'${replace(s ?? '', "'", "'\\''")}'`;
+}
+
+function command(cmd) {
+ return trim(popen(cmd)?.read?.('all'));
+}
+
+
+const methods = {
+ generatePsk: {
+ call: function() {
+ return { psk: command('wg genpsk 2>/dev/null') };
+ }
+ },
+
+ generateKeyPair: {
+ call: function() {
+ const priv = command('wg genkey 2>/dev/null');
+ const pub = command(`echo ${shellquote(priv)} | wg pubkey 2>/dev/null`);
+
+ return { keys: { priv, pub } };
+ }
+ },
+
+ getPublicAndPrivateKeyFromPrivate: {
+ args: { privkey: "privkey" },
+ call: function(req) {
+ const priv = req.args?.privkey;
+ const pub = command(`echo ${shellquote(priv)} | wg pubkey 2>/dev/null`);
+
+ return { keys: { priv, pub } };
+ }
+ },
+
+ getWgInstances: {
+ call: function() {
+ const data = {};
+ let last_device;
+ let qr_pubkey = {};
+
+ const uci = cursor();
+ const wg_dump = popen("wg show all dump 2>/dev/null");
+
+ if (wg_dump) {
+ for (let line = wg_dump.read('line'); length(line); line = wg_dump.read('line')) {
+ const record = split(rtrim(line, '\n'), '\t');
+
+ if (last_device != record[0]) {
+ last_device = record[0];
+ data[last_device] = {
+ name: last_device,
+ public_key: record[2],
+ listen_port: record[3],
+ fwmark: record[4],
+ peers: []
+ };
+
+ if (!length(record[2]) || record[2] == '(none)')
+ qr_pubkey[last_device] = '';
+ else
+ qr_pubkey[last_device] = `PublicKey = ${record[2]}`;
+ }
+ else {
+ let peer_name;
+
+ uci.foreach('network', `wireguard_${last_device}`, (s) => {
+ if (s.public_key == record[1])
+ peer_name = s.description;
+ });
+
+ const peer = {
+ name: peer_name,
+ public_key: record[1],
+ endpoint: record[3],
+ allowed_ips: [],
+ latest_handshake: record[5],
+ transfer_rx: record[6],
+ transfer_tx: record[7],
+ persistent_keepalive: record[8]
+ };
+
+ if (record[3] != '(none)' && length(record[4]))
+ push(peer.allowed_ips, ...split(record[4], ','));
+
+ push(data[last_device].peers, peer);
+ }
+ }
+ }
+
+ return data;
+ }
+ }
+};
+
+return { 'luci.wireguard': methods };