5a7798587a00d777b824ffcadcee8c47f0d2b948
[project/luci.git] / applications / luci-app-wireguard / luasrc / view / wireguard.htm
1 <%#
2  Copyright 2016-2017 Dan Luedtke <mail@danrl.com>
3  Licensed to the public under the Apache License 2.0.
4 -%>
5
6 <%
7   function strip(s)
8     return (s:gsub("^%s*(.-)%s*$", "%1"))
9   end
10
11   function is_valid(s)
12     return (string.len(strip(s)) > 0)
13   end
14
15   function peer_add(peers, public_key)
16     table.insert(peers, {
17       public_key = public_key,
18       endpoint = "",
19       transfer_rx = 0,
20       transfer_tx = 0,
21       latest_handshake = -1,
22       persistent_keepalive = "",
23       allowed_ips = { }
24     })
25   end
26
27   function peer_set_transfer(peers, public_key, rx, tx)
28     for key, peer in pairs(peers) do
29       if peer.public_key == public_key then
30         peers[key].transfer_rx = rx
31         peers[key].transfer_tx = tx
32         break
33       end
34     end
35   end
36
37   function peer_set_latest_handshake(peers, public_key, latest_handshake)
38     for key, peer in pairs(peers) do
39       if peer.public_key == public_key then
40         peers[key].latest_handshake = latest_handshake
41         break
42       end
43     end
44   end
45
46   function peer_set_endpoint(peers, public_key, endpoint)
47     for key, peer in pairs(peers) do
48       if peer.public_key == public_key then
49         peers[key].endpoint = endpoint
50         break
51       end
52     end
53   end
54
55   function peer_set_persistent_keepalive(peers, public_key, persistent_keepalive)
56     for key, peer in pairs(peers) do
57       if peer.public_key == public_key then
58         peers[key].persistent_keepalive = persistent_keepalive
59         break
60       end
61     end
62   end
63
64   function peer_set_allowed_ips(peers, public_key, allowed_ips)
65     for key, peer in pairs(peers) do
66       if peer.public_key == public_key then
67         for ipkey, ipvalue in pairs(string.split(allowed_ips, " ")) do
68           if is_valid(ipvalue) then
69             table.insert(peers[key].allowed_ips, strip(ipvalue))
70           end
71         end
72         break
73       end
74     end
75   end
76
77   local data = { }
78
79   local wg_ifaces = luci.sys.exec("wg show interfaces")
80   for key, name in pairs(string.split(wg_ifaces, "\n")) do
81     if not is_valid(name) then break end
82     name = strip(name)
83     local public_key = luci.sys.exec("wg show \"" .. name .. "\" public-key")
84     local listening_port = luci.sys.exec("wg show \"" .. name .. "\" listen-port")
85
86     local peers = { }
87     local wg_peers = luci.sys.exec("wg show \"" .. name .. "\" peers")
88     for key, public_key in pairs(string.split(wg_peers, "\n")) do
89       if not is_valid(public_key) then break end
90       peer_add(peers, public_key)
91     end
92
93     local wg_endpoints = luci.sys.exec("wg show \"" .. name .. "\" endpoints")
94     for key, endpoint in pairs(string.split(wg_endpoints, "\n")) do
95       if not is_valid(endpoint) then break end
96       local ln = string.split(strip(endpoint), "\t")
97       peer_set_endpoint(peers, ln[1], strip(ln[2]))
98     end
99
100     local wg_allowed_ips = luci.sys.exec("wg show \"" .. name .. "\" allowed-ips")
101     for key, allowed_ips in pairs(string.split(wg_allowed_ips, "\n")) do
102       if not is_valid(allowed_ips) then break end
103       local ln = string.split(strip(allowed_ips), "\t", 2)
104       peer_set_allowed_ips(peers, ln[1], strip(ln[2]))
105     end
106
107     local wg_persistent_keepalives = luci.sys.exec("wg show \"" .. name .. "\" persistent-keepalive")
108     for key, persistent_keepalive in pairs(string.split(wg_persistent_keepalives, "\n")) do
109       if not is_valid(persistent_keepalive) then break end
110       local ln = string.split(strip(persistent_keepalive), "\t")
111       peer_set_persistent_keepalive(peers, strip(ln[1]), strip(ln[2]))
112     end
113
114     local wg_latest_handshakes = luci.sys.exec("wg show \"" .. name .. "\" latest-handshakes")
115     for key, latest_handshake in pairs(string.split(wg_latest_handshakes, "\n")) do
116       if not is_valid(latest_handshake) then break end
117       local ln = string.split(strip(latest_handshake), "\t")
118       peer_set_latest_handshake(peers, strip(ln[1]), tonumber(ln[2]))
119     end
120
121     local wg_transfers = luci.sys.exec("wg show \"" .. name .. "\" transfer")
122     for key, transfer in pairs(string.split(wg_transfers, "\n")) do
123       if not is_valid(transfer) then break end
124       local ln = string.split(strip(transfer), "\t")
125       peer_set_transfer(peers, ln[1], strip(ln[2]), strip(ln[3]))
126     end
127
128     table.insert(data, {
129       name = name,
130       public_key = strip(public_key),
131       listening_port = tonumber(strip(listening_port)),
132       peers = peers
133     })
134   end
135
136   if luci.http.formvalue("status") == "1" then
137     luci.http.prepare_content("application/json")
138     luci.http.write_json(data)
139     return
140   end
141 -%>
142
143 <%+header%>
144
145 <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
146 <script type="text/javascript">//<![CDATA[
147
148   function bytes_to_str(bytes) {
149      var sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'];
150      var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
151      return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
152   };
153
154   function timestamp_to_str(timestamp) {
155     var now = new Date();
156     var seconds = (now.getTime() / 1000) - timestamp;
157     if (seconds < 60){
158       return parseInt(seconds) + '<%:s ago%>';
159     }
160     else if (seconds < 3600){
161       return parseInt(seconds / 60) + '<%:m ago%>';
162     }
163     else if (seconds < 86400){
164       return parseInt(seconds / 3600) + '<%:h ago%>';
165     } else {
166       return '<%:over a day ago%>';
167     }
168   }
169
170   XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
171    function(x, data) {
172     for (var i = 0, ilen = data.length; i < ilen; i++) {
173       var iface = data[i];
174       var ifid = iface['public_key'] + "_";
175       var s = String.format(
176         '<strong><%:Public Key%>: </strong>%s' +
177         '<br /><strong><%:Listening Port%>: </strong>%<%:s%>',
178         iface['public_key'],
179         iface['listening_port']
180       );
181       document.getElementById(ifid + "info").innerHTML = s;
182       for (var j = 0, jlen = iface['peers'].length; j < jlen; j++) {
183         var peer = iface['peers'][j];
184         var pid = ifid + peer['public_key'] + "_";
185         s = String.format(
186           '<strong><%:Public Key%>: </strong>%s',
187           peer['public_key']
188         );
189         if (peer['endpoint'] != '(none)') {
190           s += String.format(
191             '<br /><strong><%:Endpoint%>: </strong>%s',
192             peer['endpoint']
193           );
194         }
195         if (peer['allowed_ips'].length > 0) {
196           s += '<br /><strong><%:Allowed IPs%>:</strong>';
197           for (var k = 0, klen = peer['allowed_ips'].length; k < klen; k++) {
198             s += '<br />&nbsp;&nbsp;&bull;&nbsp;' + peer['allowed_ips'][k];
199           }
200         }
201         if (peer['persistent_keepalive'] != 'off') {
202           s += String.format(
203             '<br /><strong><%:Persistent Keepalive%>: </strong>%ss',
204             peer['persistent_keepalive']
205           );
206         }
207         var icon = '<img src="<%=resource%>/icons/tunnel_disabled.png" />';
208         if (((now.getTime() / 1000) - peer['latest_handshake']) < 140) {
209           icon = '<img src="<%=resource%>/icons/tunnel.png" />';
210           s += String.format(
211             '<br /><strong><%:Latest Handshake%>: </strong>%s',
212             timestamp_to_str(peer['latest_handshake'])
213           );
214         }
215         s += String.format(
216           '<br /><strong><%:Data Received%>: </strong>%s' +
217           '<br /><strong><%:Data Transmitted%>: </strong>%s',
218           bytes_to_str(peer['transfer_rx']),
219           bytes_to_str(peer['transfer_tx'])
220         );
221         document.getElementById(pid + "icon").innerHTML = icon;
222         document.getElementById(pid + "info").innerHTML = s;
223       }
224     }
225   });
226 //]]></script>
227
228 <h2>WireGuard Status</h2>
229
230
231 <fieldset class="cbi-section">
232 <%-
233 for key, iface in pairs(data) do
234   local ifid = iface.public_key .. "_"
235   -%>
236   <legend><%:Interface%> <%=iface.name%></legend>
237   <table width="100%" cellspacing="10">
238     <tr>
239       <td width="33%" style="vertical-align:top"><%:Configuration%></td>
240       <td>
241         <table>
242           <tr>
243             <td id="<%=ifid%>icon" style="width:16px; text-align:center; padding:3px">
244               &nbsp;
245             </td>
246             <td id="<%=ifid%>info" style="vertical-align:middle; padding: 3px">
247               <em><%:Collecting data...%></em>
248             </td>
249         </tr></table>
250       </td>
251     </tr>
252   <%-
253   for key, peer in pairs(iface.peers) do
254     local pid = ifid .. peer.public_key .. "_"
255     -%>
256     <tr>
257       <td width="33%" style="vertical-align:top"><%:Peer%></td>
258       <td>
259         <table>
260           <tr>
261             <td id="<%=pid%>icon" style="width:16px; text-align:center; padding:3px">
262               <img src="<%=resource%>/icons/tunnel_disabled.png" /><br />
263               <small>?</small>
264             </td>
265             <td id="<%=pid%>info" style="vertical-align:middle; padding: 3px">
266               <em><%:Collecting data...%></em>
267             </td>
268         </tr></table>
269       </td>
270     </tr>
271     <%-
272   end
273   -%>
274   </table>
275   <%-
276 end
277 -%>
278 </fieldset>
279
280 <%+footer%>