/* * Copyright (C) 2021 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import React, { useState } from 'react'; import { Alert, AlertActionCloseButton, AlertActionLink } from "@patternfly/react-core/dist/esm/components/Alert/index.js"; import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js"; import { Toolbar, ToolbarContent, ToolbarGroup, ToolbarItem } from "@patternfly/react-core/dist/esm/components/Toolbar/index.js"; import { PageSection } from "@patternfly/react-core/dist/esm/components/Page/index.js"; import { SimpleSelect } from "cockpit-components-simple-select"; import cockpit from 'cockpit'; const _ = cockpit.gettext; const firewalld = cockpit.dbus('org.fedoraproject.FirewallD1', { superuser: "try" }); function debug() { if (window.debugging === "all" || window.debugging?.includes("firewall")) console.debug.apply(console, arguments); } /* React component for an info alert to enable some new service in firewalld. * Use this when enabling some network-facing service. The alert will only be shown * if firewalld is running, has at least one active zone, and the service is not enabled * in any zone yet. It will allow the user to enable the service in any active zone, * or go to the firewall page for more fine-grained configuration. * * Properties: * - service (string, required): firewalld service name * - title (string, required): Human readable/translated alert title * - pageSection (bool, optional, default false): Render the alert inside a */ export const FirewalldRequest = ({ service, title, pageSection }) => { const [zones, setZones] = useState(null); const [selectedZone, setSelectedZone] = useState(null); const [enabledAnywhere, setEnabledAnywhere] = useState(null); const [enableError, setEnableError] = useState(null); debug("FirewalldRequest", service, "zones", JSON.stringify(zones), "selected zone", selectedZone, "enabledAnywhere", enabledAnywhere); if (!service) return null; // query zones on component initialization if (zones === null) { firewalld.call("/org/fedoraproject/FirewallD1", "org.fedoraproject.FirewallD1.zone", "getActiveZones") .then(([info]) => { const names = Object.keys(info); Promise.all(names.map(name => firewalld.call("/org/fedoraproject/FirewallD1", "org.fedoraproject.FirewallD1.zone", "getZoneSettings2", [name]))) .then(zoneInfos => { setEnabledAnywhere(!!zoneInfos.find(zoneInfo => ((zoneInfo[0].services || {}).v || []).indexOf(service) >= 0)); setZones(names); }) .catch(ex => { console.warn("FirewalldRequest: getZoneSettings failed:", JSON.stringify(ex)); setZones([]); }); firewalld.call("/org/fedoraproject/FirewallD1", "org.fedoraproject.FirewallD1", "getDefaultZone") .then(([zone]) => setSelectedZone(zone)) .catch(ex => console.warn("FirewalldRequest: getDefaultZone failed:", JSON.stringify(ex))); }) .catch(ex => { // firewalld not running debug("FirewalldRequest: getActiveZones failed, considering firewall inactive:", JSON.stringify(ex)); setZones([]); }); } const onAddService = () => { firewalld.call("/org/fedoraproject/FirewallD1", "org.fedoraproject.FirewallD1.zone", "addService", [selectedZone, service, 0]) // permanent config .then(() => firewalld.call("/org/fedoraproject/FirewallD1/config", "org.fedoraproject.FirewallD1.config", "getZoneByName", [selectedZone])) .then(([path]) => firewalld.call(path, "org.fedoraproject.FirewallD1.config.zone", "addService", [service])) // all successful, hide alert .then(() => setEnabledAnywhere(true)) .catch(ex => { // may already be enabled in permanent config, that's ok if (ex.message && ex.message.indexOf("ALREADY_ENABLED") >= 0) { setEnabledAnywhere(true); return; } setEnableError(ex.toString()); setEnabledAnywhere(true); console.error("Failed to enable", service, "in firewalld:", JSON.stringify(ex)); }); }; let alert; if (enableError) { alert = ( setEnableError(null) } /> } actionLinks={ cockpit.jump("/network/firewall")}> { _("Visit firewall") } }> {enableError} ); // don't show anything if firewalld is not active, or service is already enabled somewhere } else if (!zones || zones.length === 0 || !selectedZone || enabledAnywhere) { return null; } else { alert = ( { _("Zone") } ({ value: zone, content: zone }))} toggleProps={{ id: "firewalld-request-" + service, "aria-label": _("Zone"), }} /> ); } if (pageSection) return {alert}; else return alert; };