luci-app-wireguard: fix dependency
[project/luci.git] / protocols / luci-proto-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 local fs = require "nixio.fs"
8
9 local methods = {
10 generateKeyPair = {
11 call = function()
12 local prv = sys.exec("wg genkey 2>/dev/null"):sub(1, -2)
13 local pub = sys.exec("echo '" .. prv .. "' | wg pubkey 2>/dev/null"):sub(1, -2)
14
15 return {keys = {priv = prv, pub = pub}}
16 end
17 },
18 generateQrCode = {
19 args = {privkey = "privkey", psk = "psk", allowed_ips = {"allowed_ips"}},
20 call = function(args)
21 local qr_code
22
23 if fs.access("/usr/bin/qrencode") then
24 local psk = args.psk
25 local listen_port = args.listen_port
26 local allowed_ips = args.allowed_ips
27
28 local pubkey = sys.exec("echo '" .. args.privkey .. "' | wg pubkey 2>/dev/null"):sub(1, -2)
29 local client_privkey = sys.exec("wg genkey 2>/dev/null"):sub(1, -2)
30
31 local iface_qr = {
32 "[Interface]",
33 "PrivateKey = " .. client_privkey,
34 }
35
36 local peer_qr = {
37 "[Peer]",
38 "PublicKey = " .. pubkey,
39 }
40
41 if not allowed_ips or next(allowed_ips) == nil then
42 allowed_ips = {"0.0.0.0/0", "::/0"}
43 end
44 table.insert(peer_qr, "AllowedIPs = " .. table.concat(allowed_ips, ", "))
45
46 if psk then
47 table.insert(peer_qr, "PresharedKey = " .. psk)
48 end
49
50 qr_enc = table.concat(iface_qr, "\n") .. "\n\n" .. table.concat(peer_qr, "\n")
51 qr_code = sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- '" .. qr_enc .. "' 2>/dev/null")
52 end
53
54 return {qr_code = qr_code}
55 end
56 },
57 getWgInstances = {
58 call = function()
59 local data = {}
60 local last_device = ""
61 local qr_pubkey = {}
62
63 local wg_dump = io.popen("wg show all dump 2>/dev/null")
64 if wg_dump then
65 local line
66 for line in wg_dump:lines() do
67 local line = string.split(line, "\t")
68 if not (last_device == line[1]) then
69 last_device = line[1]
70 data[line[1]] = {
71 name = line[1],
72 public_key = line[3],
73 listen_port = line[4],
74 fwmark = line[5],
75 peers = {}
76 }
77 if not line[3] or line[3] == "" or line[3] == "(none)" then
78 qr_pubkey[line[1]] = ""
79 else
80 qr_pubkey[line[1]] = "PublicKey = " .. line[3]
81 end
82 else
83 local peer_name
84 local cur = uci.cursor()
85
86 cur:foreach(
87 "network",
88 "wireguard_" .. line[1],
89 function(s)
90 if s.public_key == line[2] then
91 peer_name = s.description
92 end
93 end
94 )
95
96 table.insert(
97 data[line[1]].peers,
98 {
99 name = peer_name,
100 public_key = line[2],
101 endpoint = line[4],
102 allowed_ips = {},
103 latest_handshake = line[6],
104 transfer_rx = line[7],
105 transfer_tx = line[8],
106 persistent_keepalive = line[9]
107 }
108 )
109
110 if not (line[4] == "(none)") then
111 local ipkey, ipvalue
112 for ipkey, ipvalue in pairs(string.split(line[5], ",")) do
113 if #ipvalue > 0 then
114 table.insert(data[line[1]].peers[peer_name]["allowed_ips"], ipvalue)
115 end
116 end
117 end
118 end
119 end
120 end
121
122 return data
123 end
124 }
125 }
126
127 local function parseInput()
128 local parse = json.new()
129 local done, err
130
131 while true do
132 local chunk = io.read(4096)
133 if not chunk then
134 break
135 elseif not done and not err then
136 done, err = parse:parse(chunk)
137 end
138 end
139
140 if not done then
141 print(json.stringify({error = err or "Incomplete input"}))
142 os.exit(1)
143 end
144
145 return parse:get()
146 end
147
148 local function validateArgs(func, uargs)
149 local method = methods[func]
150 if not method then
151 print(json.stringify({error = "Method not found"}))
152 os.exit(1)
153 end
154
155 if type(uargs) ~= "table" then
156 print(json.stringify({error = "Invalid arguments"}))
157 os.exit(1)
158 end
159
160 uargs.ubus_rpc_session = nil
161
162 local k, v
163 local margs = method.args or {}
164 for k, v in pairs(uargs) do
165 if margs[k] == nil or (v ~= nil and type(v) ~= type(margs[k])) then
166 print(json.stringify({error = "Invalid arguments"}))
167 os.exit(1)
168 end
169 end
170
171 return method
172 end
173
174 if arg[1] == "list" then
175 local _, method, rv = nil, nil, {}
176 for _, method in pairs(methods) do
177 rv[_] = method.args or {}
178 end
179 print((json.stringify(rv):gsub(":%[%]", ":{}")))
180 elseif arg[1] == "call" then
181 local args = parseInput()
182 local method = validateArgs(arg[2], args)
183 local result, code = method.call(args)
184 print((json.stringify(result):gsub("^%[%]$", "{}")))
185 os.exit(code or 0)
186 end