Line data Source code
1 : /*
2 : * Copyright (C) 2018 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 2 : import cockpit from 'cockpit';
7 : import * as service from 'service';
8 : import { debounce } from 'throttle-debounce';
9 : import * as utils from './utils.js';
10 :
11 2 : const firewall = {
12 2 : owner: undefined,
13 2 : installed: true,
14 2 : enabled: false,
15 2 : readonly: true,
16 2 : services: {},
17 2 : enabledServices: new Set(),
18 : /* Dictionary where zone ID is the key and zone information, as fetched by
19 : * fetchZoneInfos, the value */
20 2 : zones: {},
21 2 : activeZones: new Set(),
22 : /* Zones predefined by firewalld, from untrusted to trusted */
23 2 : predefinedZones: ['drop', 'block', 'public', 'external',
24 2 : 'dmz', 'work', 'home', 'internal', 'trusted'],
25 2 : defaultZone: null,
26 2 : availableInterfaces: [],
27 2 : ready: false
28 2 : };
29 :
30 2 : cockpit.event_target(firewall);
31 :
32 2 : utils.list_interfaces().then(interfaces => {
33 2 : firewall.availableInterfaces = interfaces;
34 2 : });
35 :
36 2 : const firewalld_service = service.proxy('firewalld');
37 2 : let firewalld_dbus = null;
38 :
39 2 : function debug() {
40 0 : if (window.debugging == "all" || window.debugging?.includes("firewalld")) // not-covered: debugging
41 0 : console.debug("firewalld:", ...arguments); // not-covered: debugging
42 2 : }
43 :
44 2 : firewall.debouncedGetZones = debounce(300, () => {
45 2 : if (firewalld_dbus)
46 2 : getZones()
47 2 : .then(() => getServices())
48 2 : .then(() => firewall.debouncedEvent('changed'))
49 0 : .catch(error => console.warn(error));
50 2 : });
51 :
52 : /* As certain dbus signal callbacks might change the firewall frequently
53 : * in a short period of time, prevent rapid succession of renders by
54 : * debouncing the ('changed') event */
55 2 : firewall.debouncedEvent = debounce(300, event => firewall.dispatchEvent(event));
56 :
57 : /* As a service might be removed from multiple zones at the same time,
58 : * prevent rapid succession of GetServices call */
59 1 : firewall.debouncedGetServices = debounce(300, () => {
60 1 : getServices().then(() => firewall.debouncedEvent('changed'));
61 1 : });
62 :
63 2 : function initFirewalldDbus(owner) {
64 2 : debug("initializing D-Bus connection", owner);
65 2 : firewall.owner = owner;
66 2 : firewall.enabled = !!owner;
67 :
68 2 : firewall.zones = {};
69 2 : firewall.activeZones = new Set();
70 2 : firewall.services = {};
71 2 : firewall.enabledServices = new Set();
72 :
73 0 : if (!firewall.enabled) {
74 0 : firewall.ready = true;
75 0 : firewall.dispatchEvent('changed');
76 0 : return;
77 0 : }
78 :
79 2 : firewalld_dbus = cockpit.dbus(owner, { superuser: "try", track: true });
80 :
81 2 : firewalld_dbus.subscribe({
82 2 : interface: 'org.fedoraproject.FirewallD1.zone',
83 2 : path: '/org/fedoraproject/FirewallD1',
84 2 : member: 'ServiceAdded'
85 1 : }, (path, iface, signal, args) => {
86 1 : const zone = args[0];
87 1 : const service = args[1];
88 1 : fetchZoneInfos([zone])
89 1 : .then(() => fetchServiceInfos([service]))
90 1 : .then(info => firewall.enabledServices.add(info[0].id))
91 1 : .then(() => firewall.debouncedEvent('changed'))
92 0 : .catch(error => console.warn(error));
93 1 : });
94 :
95 2 : firewalld_dbus.subscribe({
96 2 : interface: 'org.fedoraproject.FirewallD1.zone',
97 2 : path: '/org/fedoraproject/FirewallD1',
98 2 : member: 'ServiceRemoved'
99 1 : }, (path, iface, signal, args) => {
100 1 : const zone = args[0];
101 1 : const service = args[1];
102 :
103 1 : firewall.zones[zone].services = firewall.zones[zone].services.filter(s => s !== service);
104 1 : firewall.enabledServices.delete(service);
105 1 : firewall.debouncedGetServices();
106 1 : });
107 :
108 2 : firewalld_dbus.subscribe({
109 2 : interface: 'org.fedoraproject.FirewallD1.zone',
110 2 : path: '/org/fedoraproject/FirewallD1',
111 2 : member: 'PortAdded'
112 0 : }, (path, iface, signal, args) => {
113 0 : const zone = args[0];
114 0 : const port = args[1];
115 0 : const protocol = args[2];
116 0 : if (!firewall.zones[zone].ports.some(p => p.port === port && p.protocol === protocol)) {
117 0 : firewall.zones[zone].ports.push({ port, protocol });
118 0 : firewall.debouncedEvent('changed');
119 0 : }
120 0 : });
121 :
122 2 : firewalld_dbus.subscribe({
123 2 : interface: 'org.fedoraproject.FirewallD1.zone',
124 2 : path: '/org/fedoraproject/FirewallD1',
125 2 : member: 'PortRemoved'
126 0 : }, (path, iface, signal, args) => {
127 0 : const zone = args[0];
128 0 : const port = args[1];
129 0 : const protocol = args[2];
130 0 : firewall.zones[zone].ports = firewall.zones[zone].ports
131 0 : .filter(p => p.port !== port || p.protocol !== protocol);
132 0 : firewall.debouncedEvent('changed');
133 0 : });
134 :
135 2 : firewalld_dbus.subscribe({
136 2 : interface: 'org.fedoraproject.FirewallD1',
137 2 : path: '/org/fedoraproject/FirewallD1',
138 2 : member: 'Reloaded'
139 1 : }, () => firewall.debouncedGetZones());
140 :
141 : /* There are two APIs available, changeZoneOf(Interface|Source) and
142 : * add(Interface|Source). Listen to both of them for any background changes
143 : * to zones. */
144 2 : firewalld_dbus.subscribe({
145 2 : interface: 'org.fedoraproject.FirewallD1.zone',
146 2 : path: '/org/fedoraproject/FirewallD1',
147 2 : member: 'ZoneOfInterfaceChanged'
148 1 : }, () => firewall.debouncedGetZones());
149 2 : firewalld_dbus.subscribe({
150 2 : interface: 'org.fedoraproject.FirewallD1.zone',
151 2 : path: '/org/fedoraproject/FirewallD1',
152 2 : member: 'ZoneOfSourceChanged'
153 0 : }, () => firewall.debouncedGetZones());
154 :
155 2 : firewalld_dbus.subscribe({
156 2 : interface: 'org.fedoraproject.FirewallD1.zone',
157 2 : path: '/org/fedoraproject/FirewallD1',
158 2 : member: 'InterfaceAdded'
159 0 : }, () => firewall.debouncedGetZones());
160 2 : firewalld_dbus.subscribe({
161 2 : interface: 'org.fedoraproject.FirewallD1.zone',
162 2 : path: '/org/fedoraproject/FirewallD1',
163 2 : member: 'SourceAdded'
164 0 : }, () => firewall.debouncedGetZones());
165 2 : firewalld_dbus.subscribe({
166 2 : interface: 'org.fedoraproject.FirewallD1.zone',
167 2 : path: '/org/fedoraproject/FirewallD1',
168 2 : member: 'InterfaceRemoved'
169 0 : }, () => firewall.debouncedGetZones());
170 2 : firewalld_dbus.subscribe({
171 2 : interface: 'org.fedoraproject.FirewallD1.zone',
172 2 : path: '/org/fedoraproject/FirewallD1',
173 2 : member: 'SourceRemoved'
174 0 : }, () => firewall.debouncedGetZones());
175 :
176 2 : getZones()
177 2 : .then(() => getServices())
178 0 : .catch(error => console.warn(error))
179 2 : .then(() => { firewall.ready = true })
180 2 : .then(() => firewall.debouncedEvent('changed'));
181 2 : }
182 :
183 2 : firewalld_service.addEventListener('changed', () => {
184 2 : const installed = !!firewalld_service.exists;
185 2 : const is_running = firewalld_service.state === 'running';
186 :
187 : // we get lots of these events, for internal property changes; filter interesting changes
188 2 : if (is_running === firewalld_service.prev_running && firewall.installed === installed)
189 2 : return;
190 2 : firewall.installed = installed;
191 2 : firewalld_service.prev_running = is_running;
192 :
193 2 : debug("systemd service changed: exists", firewalld_service.exists, "state", firewalld_service.state,
194 2 : "firewall.enabled:", JSON.stringify(firewall.enabled));
195 :
196 2 : firewall.dispatchEvent('changed');
197 2 : });
198 :
199 2 : function getZones() {
200 2 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
201 2 : 'org.fedoraproject.FirewallD1.zone',
202 2 : 'getActiveZones', [])
203 2 : .then(reply => fetchZoneInfos(Object.keys(reply[0])))
204 2 : .then(zones => {
205 2 : firewall.activeZones = new Set(zones.map(z => z.id));
206 2 : debug("getActiveZones succeeded:", JSON.stringify([...firewall.activeZones]));
207 2 : })
208 2 : .then(() => firewalld_dbus.call('/org/fedoraproject/FirewallD1',
209 2 : 'org.fedoraproject.FirewallD1',
210 2 : 'getDefaultZone', []))
211 2 : .then(reply => {
212 2 : firewall.defaultZone = reply[0];
213 2 : })
214 2 : .then(() => firewalld_dbus.call('/org/fedoraproject/FirewallD1',
215 2 : 'org.fedoraproject.FirewallD1.zone',
216 2 : 'getZones', []))
217 2 : .then(reply => fetchZoneInfos(reply[0]));
218 2 : }
219 :
220 2 : function getServices() {
221 2 : if (firewall.readonly)
222 0 : return Promise.resolve();
223 2 : firewall.enabledServices = new Set();
224 2 : return Promise.all([...firewall.activeZones].map(z => {
225 2 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
226 2 : 'org.fedoraproject.FirewallD1.zone',
227 2 : 'getServices', [z])
228 2 : .then(reply => fetchServiceInfos(reply[0]))
229 2 : .then(services => {
230 2 : const promises = [];
231 2 : for (const s of services) {
232 2 : firewall.enabledServices.add(s.id);
233 2 : if (s.includes.length)
234 0 : promises.push(fetchServiceInfos(s.includes));
235 2 : }
236 2 : return Promise.all(promises);
237 2 : });
238 2 : }));
239 2 : }
240 :
241 2 : function fetchServiceInfos(services) {
242 2 : return Promise.all(services.map(service => {
243 2 : if (firewall.services[service])
244 2 : return firewall.services[service];
245 :
246 2 : let info;
247 2 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
248 2 : 'org.fedoraproject.FirewallD1',
249 2 : 'getServiceSettings2', [service])
250 2 : .then(([{ short, description, ports }]) => {
251 0 : short = short ? short.v : "";
252 0 : description = description ? description.v : "";
253 0 : ports = ports ? ports.v : [];
254 2 : info = {
255 2 : id: service,
256 2 : name: short,
257 2 : description,
258 2 : ports: ports.map(p => ({ port: p[0], protocol: p[1] })),
259 2 : includes: [],
260 2 : };
261 :
262 2 : firewall.services[service] = info;
263 2 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
264 2 : 'org.fedoraproject.FirewallD1.config',
265 2 : 'getServiceByName', [service]);
266 2 : })
267 2 : .then(path => firewalld_dbus.call(path[0],
268 2 : 'org.fedoraproject.FirewallD1.config.service',
269 2 : 'getSettings2', []))
270 2 : .then(reply => {
271 0 : if (reply[0].includes) {
272 0 : info.includes = reply[0].includes.v;
273 0 : firewall.services[service] = info;
274 0 : }
275 2 : return info;
276 2 : })
277 0 : .catch(error => {
278 0 : if (error.name === 'org.freedesktop.DBus.Error.UnknownMethod')
279 0 : return info;
280 0 : return Promise.reject(error);
281 0 : });
282 2 : }));
283 2 : }
284 :
285 2 : function fetchZoneInfos(zones) {
286 2 : return Promise.all(zones.map(zone => {
287 0 : if (firewall.readonly) {
288 0 : const info = {
289 0 : id: zone,
290 0 : name: zone,
291 0 : description: null,
292 0 : target: null,
293 0 : services: [],
294 0 : ports: [],
295 0 : interfaces: [],
296 0 : source: [],
297 0 : };
298 0 : firewall.zones[zone] = info;
299 0 : return info;
300 0 : }
301 2 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
302 2 : 'org.fedoraproject.FirewallD1.zone',
303 2 : 'getZoneSettings2', [zone])
304 2 : .then(([zoneInfo]) => {
305 2 : const info = {
306 2 : id: zone,
307 1 : name: (zoneInfo.short || {}).v,
308 1 : description: (zoneInfo.description || {}).v,
309 0 : target: (zoneInfo.target || {}).v,
310 2 : services: ((zoneInfo.services || {}).v || []),
311 2 : ports: ((zoneInfo.ports || {}).v || []).map(p => ({ port: p[0], protocol: p[1] })),
312 2 : interfaces: ((zoneInfo.interfaces || {}).v || []),
313 2 : source: ((zoneInfo.sources || {}).v || []),
314 2 : };
315 2 : firewall.zones[zone] = info;
316 2 : return info;
317 2 : });
318 2 : }));
319 2 : }
320 :
321 : /* We watch the name owner explicitly.
322 :
323 : The org.fedoraproject.FirewallD service might appear on D-Bus only
324 : some time after the firewalld.service is active and thus we want to
325 : only try connecting to it once we know that it is definitely there.
326 : However, while cockpit.dbus() does work with services that
327 : disappear and then reappear on the bus while the channel is open,
328 : it doesn't work with names that are not present when the channel is
329 : initially opened (see
330 : https://github.com/cockpit-project/cockpit/pull/9125).
331 :
332 : Thus, we track the name explicitly via the org.freedesktop.DBus
333 : API.
334 : */
335 :
336 2 : function dbus_watch_name_owner(name, owner_callback) {
337 2 : const bus = cockpit.dbus('org.freedesktop.DBus', { superuser: "try" });
338 2 : let owner = null;
339 :
340 2 : function owner_changed(new_owner) {
341 2 : if (new_owner != owner) {
342 2 : owner = new_owner;
343 2 : owner_callback(owner);
344 2 : }
345 2 : }
346 :
347 2 : bus.subscribe({
348 2 : path: "/org/freedesktop/DBus",
349 2 : interface: "org.freedesktop.DBus",
350 2 : member: "NameOwnerChanged",
351 2 : arg0: name,
352 0 : }, (_path, _iface, _member, [_name, _old_owner, new_owner]) => {
353 0 : owner_changed(new_owner);
354 0 : });
355 :
356 2 : bus.call(
357 2 : "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetNameOwner",
358 2 : [name]
359 2 : )
360 2 : .then(([owner]) => {
361 2 : owner_changed(owner);
362 2 : })
363 0 : .catch(ex => {
364 0 : if (ex.name == "org.freedesktop.DBus.Error.NameHasNoOwner")
365 0 : owner_changed("");
366 : else
367 0 : throw ex;
368 0 : });
369 2 : }
370 :
371 2 : dbus_watch_name_owner('org.fedoraproject.FirewallD1', initFirewalldDbus);
372 :
373 2 : cockpit.spawn(['sh', '-c', 'pkcheck --action-id org.fedoraproject.FirewallD1.all --process $$ --allow-user-interaction 2>&1'], { superuser: "try" })
374 2 : .then(() => {
375 2 : firewall.readonly = false;
376 2 : firewall.debouncedEvent('changed');
377 2 : firewall.debouncedGetZones();
378 2 : })
379 0 : .catch(error => {
380 0 : console.log("pkcheck failed", error);
381 :
382 : // Fall back to cockpit.permissions, "pkcheck" might not be available,
383 : // always allow edits by admins
384 0 : const permission = cockpit.permission({ admin: true });
385 0 : const update_permissions = () => {
386 0 : firewall.readonly = !permission.allowed;
387 0 : firewall.debouncedEvent('changed');
388 0 : firewall.debouncedGetZones();
389 0 : };
390 0 : permission.addEventListener("changed", update_permissions);
391 0 : });
392 :
393 0 : firewall.enable = () => firewalld_service.enable().then(() => firewalld_service.start());
394 0 : firewall.disable = () => firewalld_service.disable().then(() => firewalld_service.stop());
395 :
396 0 : firewall.getAvailableServices = () => {
397 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
398 0 : 'org.fedoraproject.FirewallD1',
399 0 : 'listServices', [])
400 0 : .then(reply => fetchServiceInfos(reply[0]))
401 0 : .catch(error => console.warn(error));
402 0 : };
403 :
404 : /*
405 : * Only call this after defining a new service, as it will remove existing
406 : * non-permanent configurations.
407 : */
408 0 : firewall.reload = () => {
409 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
410 0 : 'org.fedoraproject.FirewallD1',
411 0 : 'reload', [])
412 0 : .catch(error => console.warn(error));
413 0 : };
414 :
415 : /*
416 : * Remove a service from the specified zone (i.e., close its ports).
417 : *
418 : * Returns a promise that resolves when the service is removed.
419 : */
420 0 : firewall.removeService = (zone, service) => {
421 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
422 0 : 'org.fedoraproject.FirewallD1.zone',
423 0 : 'removeService', [zone, service])
424 0 : .then(reply => firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
425 0 : 'org.fedoraproject.FirewallD1.config',
426 0 : 'getZoneByName', [zone]))
427 0 : .then(path => firewalld_dbus.call(path[0], 'org.fedoraproject.FirewallD1.config.zone',
428 0 : 'removeService', [service]));
429 0 : };
430 :
431 0 : firewall.removePort = (zone, port, protocol) => {
432 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
433 0 : 'org.fedoraproject.FirewallD1.zone',
434 0 : 'removePort', [zone, port, protocol])
435 0 : .then(reply => firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
436 0 : 'org.fedoraproject.FirewallD1.config',
437 0 : 'getZoneByName', [zone]))
438 0 : .then(path => firewalld_dbus.call(path[0], 'org.fedoraproject.FirewallD1.config.zone',
439 0 : 'removePort', [port, protocol]));
440 0 : };
441 :
442 : /*
443 : * Create new firewalld service.
444 : *
445 : * Returns a promise that resolves when the service is created.
446 : * It will also reload firewalld and enable the new service.
447 : */
448 0 : firewall.createService = (service, ports, zones, desc = "") => {
449 0 : const subscription = firewalld_dbus.subscribe({
450 0 : interface: 'org.fedoraproject.FirewallD1',
451 0 : path: '/org/fedoraproject/FirewallD1',
452 0 : member: 'Reloaded'
453 0 : }, () => {
454 0 : firewall.addServices(zones, [service]);
455 0 : subscription.remove();
456 0 : });
457 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
458 0 : 'org.fedoraproject.FirewallD1.config',
459 0 : 'addService2', [service, { description: { t: 's', v: desc }, ports: { t: 'a(ss)', v: ports } }])
460 0 : .then(() => firewall.reload());
461 0 : };
462 :
463 : /*
464 : * Edit firewalld service.
465 : *
466 : * Returns a promise that resolves when the service is edited.
467 : */
468 0 : firewall.editService = (service, ports, desc = "") => {
469 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
470 0 : 'org.fedoraproject.FirewallD1.config',
471 0 : 'getServiceByName', [service])
472 0 : .then(path => firewalld_dbus.call(path[0],
473 0 : 'org.fedoraproject.FirewallD1.config.service',
474 0 : 'update2', [{ description: { t: 's', v: desc }, ports: { t: 'a(ss)', v: ports } }])
475 0 : .then(() => {
476 : // No signal for updated service so we need to manually update it
477 0 : firewall.services[service].description = desc;
478 0 : firewall.services[service].ports = ports.map(port => ({ port: port[0], protocol: port[1] }));
479 0 : firewall.debouncedEvent('changed');
480 0 : return firewall.reload();
481 0 : })
482 0 : );
483 0 : };
484 :
485 : /*
486 : * Add a predefined firewalld service to the specified zone (i.e., open its
487 : * ports).
488 : *
489 : * Returns a promise that resolves when the service is added.
490 : */
491 0 : firewall.addService = (zone, service) => {
492 0 : return firewalld_dbus.call('/org/fedoraproject/FirewallD1',
493 0 : 'org.fedoraproject.FirewallD1.zone',
494 0 : 'addService', [zone, service, 0])
495 0 : .then(reply => firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
496 0 : 'org.fedoraproject.FirewallD1.config',
497 0 : 'getZoneByName', [zone]))
498 0 : .then(path => firewalld_dbus.call(path[0], 'org.fedoraproject.FirewallD1.config.zone',
499 0 : 'addService', [service]));
500 0 : };
501 :
502 : /*
503 : * Like addService(), but adds multiple predefined firewalld services at once
504 : * to the specified zones.
505 : *
506 : * Returns a promise that resolves when all services are added.
507 : */
508 0 : firewall.addServices = (zone, services) =>
509 0 : Promise.all(services.map(s => firewall.addService(zone, s)));
510 :
511 0 : firewall.removeServiceFromZones = (zones, service) =>
512 0 : Promise.all(zones.map(z => firewall.removeService(z, service)));
513 :
514 0 : firewall.activateZone = (zone, interfaces, sources) => {
515 0 : let promises = interfaces.map(i => firewalld_dbus.call('/org/fedoraproject/FirewallD1',
516 0 : 'org.fedoraproject.FirewallD1.zone',
517 0 : 'addInterface', [zone, i]));
518 :
519 0 : promises = promises.concat(sources.map(s => firewalld_dbus.call('/org/fedoraproject/FirewallD1',
520 0 : 'org.fedoraproject.FirewallD1.zone',
521 0 : 'addSource', [zone, s])));
522 0 : let p = Promise.all(promises).then(() => firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
523 0 : 'org.fedoraproject.FirewallD1.config',
524 0 : 'getZoneByName', [zone]));
525 0 : p = p.then(path => {
526 : /* Once this signal is received, it's safe to actually emit the changed
527 : * signal and thus update the UI */
528 0 : const subscription = firewalld_dbus.subscribe({
529 0 : interface: 'org.fedoraproject.FirewallD1.config.zone',
530 0 : path: path[0],
531 0 : member: 'Updated'
532 0 : }, (path, iface, signal, args) => {
533 0 : getZones().then(() => getServices());
534 0 : subscription.remove();
535 0 : });
536 :
537 0 : return firewalld_dbus.call(path[0],
538 0 : 'org.fedoraproject.FirewallD1.config.zone',
539 0 : 'update2', [{ interfaces: { t: 'as', v: interfaces }, sources: { t: 'as', v: sources } }]);
540 0 : });
541 0 : return p;
542 0 : };
543 :
544 : /*
545 : * A zone is considered deactivated when it has no interfaces or sources.
546 : */
547 0 : firewall.deactiveateZone = (zone) => {
548 0 : const zoneObject = firewall.zones[zone];
549 0 : let promises = zoneObject.interfaces.map(i => firewalld_dbus.call('/org/fedoraproject/FirewallD1',
550 0 : 'org.fedoraproject.FirewallD1.zone',
551 0 : 'removeInterface', [zone, i]));
552 0 : promises = promises.concat(zoneObject.source.map(s => firewalld_dbus.call('/org/fedoraproject/FirewallD1',
553 0 : 'org.fedoraproject.FirewallD1.zone',
554 0 : 'removeSource', [zone, s])));
555 0 : let p = Promise.all(promises).then(() => firewalld_dbus.call('/org/fedoraproject/FirewallD1/config',
556 0 : 'org.fedoraproject.FirewallD1.config',
557 0 : 'getZoneByName', [zone]));
558 0 : p = p.then(path => {
559 : /* Once this signal is received, it's safe to actually emit the changed
560 : * signal and thus update the UI */
561 0 : const subscription = firewalld_dbus.subscribe({
562 0 : interface: 'org.fedoraproject.FirewallD1.config.zone',
563 0 : path: path[0],
564 0 : member: 'Updated'
565 0 : }, (path, iface, signal, args) => {
566 0 : firewall.activeZones.delete(args[0]);
567 0 : getZones().then(() => getServices());
568 0 : subscription.remove();
569 0 : });
570 :
571 0 : return firewalld_dbus.call(path[0],
572 0 : 'org.fedoraproject.FirewallD1.config.zone',
573 0 : 'update2', [{ interfaces: { t: 'as', v: [] }, sources: { t: 'as', v: [] } }]);
574 0 : });
575 :
576 0 : return p.catch(error => console.warn(error));
577 0 : };
578 :
579 2 : export default firewall;
|