luci-app-wireguard: merge app and proto rpcd
[project/luci.git] / applications / luci-app-wireguard / root / usr / libexec / rpcd / luci.wireguard
1 #!/usr/bin/env lua
2
3 local json = require "luci.jsonc"
4 local sys = require "luci.sys"
5 local io = require "io"
6 local uci = require "uci"
7
8 local methods = {
9 generateKeyPair = {
10 call = function()
11 local prv = sys.exec("wg genkey 2>/dev/null"):sub(1, -2)
12 local pub = sys.exec("echo '" .. prv .. "' | wg pubkey 2>/dev/null"):sub(1, -2)
13
14 return {keys = {priv = prv, pub = pub}}
15 end
16 },
17 getWgInstances = {
18 call = function()
19 local data = {}
20 local last_device = ""
21 local qr_pubkey = {}
22
23 local wg_dump = io.popen("wg show all dump 2>/dev/null")
24 if wg_dump then
25 local line
26 for line in wg_dump:lines() do
27 local line = string.split(line, "\t")
28 if not (last_device == line[1]) then
29 last_device = line[1]
30 data[line[1]] = {
31 name = line[1],
32 public_key = line[3],
33 listen_port = line[4],
34 fwmark = line[5],
35 peers = {}
36 }
37 if not line[3] or line[3] == "" or line[3] == "(none)" then
38 qr_pubkey[line[1]] = ""
39 else
40 qr_pubkey[line[1]] = "PublicKey = " .. line[3]
41 end
42 else
43 local peer_name
44 local cur = uci.cursor()
45
46 cur:foreach(
47 "network",
48 "wireguard_" .. line[1],
49 function(s)
50 if s.public_key == line[2] then
51 peer_name = s.description
52 end
53 end
54 )
55
56 table.insert(
57 data[line[1]].peers,
58 {
59 name = peer_name,
60 public_key = line[2],
61 endpoint = line[4],
62 allowed_ips = {},
63 latest_handshake = line[6],
64 transfer_rx = line[7],
65 transfer_tx = line[8],
66 persistent_keepalive = line[9]
67 }
68 )
69
70 if not (line[4] == "(none)") then
71 local ipkey, ipvalue
72 for ipkey, ipvalue in pairs(string.split(line[5], ",")) do
73 if #ipvalue > 0 then
74 table.insert(data[line[1]].peers[peer_name]["allowed_ips"], ipvalue)
75 end
76 end
77 end
78 end
79 end
80 end
81
82 return data
83 end
84 }
85 }
86
87 local function parseInput()
88 local parse = json.new()
89 local done, err
90
91 while true do
92 local chunk = io.read(4096)
93 if not chunk then
94 break
95 elseif not done and not err then
96 done, err = parse:parse(chunk)
97 end
98 end
99
100 if not done then
101 print(json.stringify({error = err or "Incomplete input"}))
102 os.exit(1)
103 end
104
105 return parse:get()
106 end
107
108 local function validateArgs(func, uargs)
109 local method = methods[func]
110 if not method then
111 print(json.stringify({error = "Method not found"}))
112 os.exit(1)
113 end
114
115 if type(uargs) ~= "table" then
116 print(json.stringify({error = "Invalid arguments"}))
117 os.exit(1)
118 end
119
120 uargs.ubus_rpc_session = nil
121
122 local k, v
123 local margs = method.args or {}
124 for k, v in pairs(uargs) do
125 if margs[k] == nil or (v ~= nil and type(v) ~= type(margs[k])) then
126 print(json.stringify({error = "Invalid arguments"}))
127 os.exit(1)
128 end
129 end
130
131 return method
132 end
133
134 if arg[1] == "list" then
135 local _, method, rv = nil, nil, {}
136 for _, method in pairs(methods) do
137 rv[_] = method.args or {}
138 end
139 print((json.stringify(rv):gsub(":%[%]", ":{}")))
140 elseif arg[1] == "call" then
141 local args = parseInput()
142 local method = validateArgs(arg[2], args)
143 local result, code = method.call(args)
144 print((json.stringify(result):gsub("^%[%]$", "{}")))
145 os.exit(code or 0)
146 end