d0a936cc6e179b9ab4e88cf0a0bf8af8107d379f
[project/luci.git] /
1 'use strict';
2 'require view';
3 'require dom';
4 'require poll';
5 'require fs';
6 'require ui';
7
8 function formatTime(seconds, selectCount) {
9 var days = Math.floor(seconds / (60 * 60 * 24));
10 var hours = Math.floor(seconds / (60 * 60)) % 24;
11 var minutes = Math.floor(seconds / 60) % 60;
12 var seconds = Math.floor(seconds % 60);
13
14 var times = [
15 [days, _('Day'), _('Days')],
16 [hours, _('Hour'), _('Hours')],
17 [minutes, _('Minute'), _('Minutes')],
18 [seconds, _('Second'), _('Seconds')]
19 ].filter(function ([time, singular, plural]) {
20 return time > 0;
21 });
22
23 var selectedTimes = times.slice(0, selectCount);
24 return selectedTimes.map(function ([time, singular, plural]) {
25 var unit = time > 1 ? plural : singular;
26 return '%d %s'.format(time, unit);
27 }).join(', ');
28 }
29
30 function buildSection(name, table) {
31 return E('div', { 'class': 'cbi-section' }, [
32 E('h2', [name]),
33 table
34 ]);
35 }
36
37 function buildTable(rows) {
38 return E('table', { 'class': 'table', }, rows);
39 }
40
41 function buildKeyValueTable(kvPairs) {
42 var rows = kvPairs.map(function (row) {
43 return E('tr', { 'class': 'tr' }, [
44 E('td', { 'class': 'td', 'width': '33%' }, E('strong', [row[0]])),
45 E('td', { 'class': 'td' }, [row[1]])
46 ]);
47 });
48 return buildTable(rows);
49 }
50
51 function collectErrorMessages(results) {
52 var errorMessages = results.reduce(function (messages, result) {
53 return messages.concat(result.errors.map(function (error) {
54 return error.message;
55 }));
56 }, []);
57 var uniqueErrorMessages = new Set(errorMessages);
58
59 return [...uniqueErrorMessages];
60 }
61
62 return view.extend({
63 load: function () {
64 return Promise.all([
65 fs.exec_direct('/usr/sbin/swanmon', ['version'], 'json'),
66 fs.exec_direct('/usr/sbin/swanmon', ['stats'], 'json'),
67 fs.exec_direct('/usr/sbin/swanmon', ['list-sas'], 'json')
68 ]);
69 },
70
71 pollData: function (container) {
72 poll.add(L.bind(function () {
73 return this.load().then(L.bind(function (results) {
74 dom.content(container, this.renderContent(results));
75 }, this));
76 }, this));
77 },
78
79 renderContent: function (results) {
80 var node = E('div', [E('div')]);
81 var firstNode = node.firstElementChild;
82
83 var errorMessages = collectErrorMessages(results);
84 if (errorMessages.length > 0) {
85 var messageEls = errorMessages.map(function (message) {
86 return E('li', message);
87 });
88
89 firstNode.appendChild(E('h4', _('Querying strongSwan failed')));
90 firstNode.appendChild(E('ul', messageEls));
91
92 return node;
93 }
94
95 var [version, stats, sas] = results.map(function (r) {
96 return r.data;
97 });
98
99 var uptimeSeconds = (new Date() - new Date(stats.uptime.since)) / 1000;
100 var statsSection = buildSection(_('Stats'), buildKeyValueTable([
101 [_('Version'), version.version],
102 [_('Uptime'), formatTime(uptimeSeconds, 2)],
103 [_('Daemon'), version.daemon],
104 [_('Active IKE_SAs'), stats.ikesas.total],
105 [_('Half-Open IKE_SAs'), stats.ikesas['half-open']]
106 ]));
107 firstNode.appendChild(statsSection);
108
109 var tableRows = sas.map(function (conn) {
110 var name = Object.keys(conn)[0];
111 var data = conn[name];
112 var childSas = [];
113
114 Object.entries(data['child-sas']).forEach(function ([name, data]) {
115 var table = buildKeyValueTable([
116 [_('State'), data.state],
117 [_('Mode'), data.mode],
118 [_('Protocol'), data.protocol],
119 [_('Local Traffic Selectors'), data['local-ts'].join(', ')],
120 [_('Remote Traffic Selectors'), data['remote-ts'].join(', ')],
121 [_('Encryption Algorithm'), data['encr-alg']],
122 [_('Encryption Keysize'), data['encr-keysize']],
123 [_('Bytes in'), data['bytes-in']],
124 [_('Bytes out'), data['bytes-out']],
125 [_('Life Time'), formatTime(data['life-time'], 2)],
126 [_('Install Time'), formatTime(data['install-time'], 2)],
127 [_('Rekey in'), formatTime(data['rekey-time'], 2)],
128 [_('SPI in'), data['spi-in']],
129 [_('SPI out'), data['spi-out']]
130 ]);
131 childSas.push(E('div', { 'class': 'cbi-section' }, [
132 E('h4', { 'style': 'margin-top: 0; padding-top: 0;' }, [name]),
133 table
134 ]));
135 });
136 childSas.push(E('button', {
137 'class': 'btn cbi-button cbi-button-apply',
138 'click': ui.hideModal
139 }, _('Close')));
140
141 return E('tr', { 'class': 'tr' }, [
142 E('td', { 'class': 'td' }, [name]),
143 E('td', { 'class': 'td' }, [data.state]),
144 E('td', { 'class': 'td' }, [data['remote-host']]),
145 E('td', { 'class': 'td' }, [data.version]),
146 E('td', { 'class': 'td' }, [formatTime(data.established, 2)]),
147 E('td', { 'class': 'td' }, [formatTime(data['reauth-time'], 2)]),
148 E('td', { 'class': 'td' }, [E('button', {
149 'class': 'btn cbi-button cbi-button-apply',
150 'click': function (ev) {
151 ui.showModal(_('CHILD_SAs'), childSas)
152 }
153 }, _('Show Details'))])
154 ]);
155 });
156 var connSection = buildSection(_('Security Associations (SAs)'), buildTable([
157 E('tr', { 'class': 'tr' }, [
158 E('th', { 'class': 'th' }, [_('Name')]),
159 E('th', { 'class': 'th' }, [_('State')]),
160 E('th', { 'class': 'th' }, [_('Remote')]),
161 E('th', { 'class': 'th' }, [_('IKE Version')]),
162 E('th', { 'class': 'th' }, [_('Established for')]),
163 E('th', { 'class': 'th' }, [_('Reauthentication in')]),
164 E('th', { 'class': 'th' }, [_('Details')])
165 ]),
166 ...tableRows
167 ]));
168 firstNode.appendChild(connSection);
169
170 return node;
171 },
172
173 render: function (results) {
174 var content = E([], [
175 E('h2', [_('strongSwan Status')]),
176 E('div')
177 ]);
178 var container = content.lastElementChild;
179
180 dom.content(container, this.renderContent(results));
181 this.pollData(container);
182
183 return content;
184 },
185
186 handleSaveApply: null,
187 handleSave: null,
188 handleReset: null
189 });