LCOV - code coverage report
Current view: top level - pkg/networkmanager - firewall-client.js Coverage Total Hit
Test: cockpit Lines: 97.8 % 446 436
Test Date: 2026-07-17 07:33:01

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

Generated by: LCOV version 2.0-1