diff --git a/plinth/__main__.py b/plinth/__main__.py
index bd1ae297f..bd65554ff 100644
--- a/plinth/__main__.py
+++ b/plinth/__main__.py
@@ -147,8 +147,6 @@ def main():
log.init()
- service.init()
-
web_framework.init()
logger.info('FreedomBox Service (Plinth) version - %s', __version__)
diff --git a/plinth/app.py b/plinth/app.py
index cb9292d45..bf69605db 100644
--- a/plinth/app.py
+++ b/plinth/app.py
@@ -74,10 +74,7 @@ class App:
"""
for component in self.components.values():
if not component.is_leader:
- if enabled:
- component.enable()
- else:
- component.disable()
+ component.set_enabled(enabled)
class Component:
@@ -93,10 +90,10 @@ class Component:
self.component_id = component_id
def enable(self):
- """Enable the component."""
+ """Run operations to enable the component."""
def disable(self):
- """Disable the component."""
+ """Run operations to disable the component."""
class FollowerComponent(Component):
@@ -117,12 +114,16 @@ class FollowerComponent(Component):
"""Return whether the component is enabled."""
return self._is_enabled
+ def set_enabled(self, enabled):
+ """Update the internal enabled state of the component."""
+ self._is_enabled = enabled
+
def enable(self):
- """Enable the component."""
+ """Run operations to enable the component."""
self._is_enabled = True
def disable(self):
- """Disable the component."""
+ """Run operations to disable the component."""
self._is_enabled = False
diff --git a/plinth/modules/apache/__init__.py b/plinth/modules/apache/__init__.py
index 9d2a96fae..536b6a4b1 100644
--- a/plinth/modules/apache/__init__.py
+++ b/plinth/modules/apache/__init__.py
@@ -18,7 +18,13 @@
FreedomBox app for Apache server.
"""
+from django.utils.translation import ugettext_lazy as _
+
from plinth import actions
+from plinth import app as app_module
+from plinth import cfg
+from plinth.modules.firewall.components import Firewall
+from plinth.utils import format_lazy
version = 7
@@ -26,9 +32,38 @@ is_essential = True
managed_packages = ['apache2', 'php-fpm']
+app = None
+
+
+class ApacheApp(app_module.App):
+ """FreedomBox app for Apache web server."""
+
+ def __init__(self):
+ """Create components for the app."""
+ super().__init__()
+
+ web_server_ports = Firewall('firewall-web', _('Web Server'),
+ ports=['http', 'https'], is_external=True)
+ self.add(web_server_ports)
+
+ freedombox_ports = Firewall(
+ 'firewall-plinth',
+ format_lazy(
+ _('{box_name} Web Interface (Plinth)'), box_name=_(
+ cfg.box_name)), ports=['http', 'https'], is_external=True)
+ self.add(freedombox_ports)
+
+
+def init():
+ """Initailze firewall module"""
+ global app
+ app = ApacheApp()
+ app.set_enabled(True)
+
def setup(helper, old_version=None):
"""Configure the module."""
helper.install(managed_packages)
- actions.superuser_run('apache',
- ['setup', '--old-version', str(old_version)])
+ actions.superuser_run(
+ 'apache',
+ ['setup', '--old-version', str(old_version)])
diff --git a/plinth/modules/avahi/__init__.py b/plinth/modules/avahi/__init__.py
index 2dd1bc15d..31e824907 100644
--- a/plinth/modules/avahi/__init__.py
+++ b/plinth/modules/avahi/__init__.py
@@ -24,6 +24,7 @@ from plinth import actions
from plinth import app as app_module
from plinth import cfg, menu
from plinth import service as service_module
+from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
from plinth.views import ServiceView
@@ -69,6 +70,10 @@ class AvahiApp(app_module.App):
'avahi:index', parent_url_name='system')
self.add(menu_item)
+ firewall = Firewall('firewall-avahi', name, ports=['mdns'],
+ is_external=False)
+ self.add(firewall)
+
def init():
"""Intialize the service discovery module."""
@@ -77,8 +82,7 @@ def init():
app.set_enabled(True)
global service # pylint: disable=W0603
- service = service_module.Service(managed_services[0], name, ports=['mdns'],
- is_external=False)
+ service = service_module.Service(managed_services[0], name)
def setup(helper, old_version=None):
diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py
index 32f6f1c05..34a341862 100644
--- a/plinth/modules/bind/__init__.py
+++ b/plinth/modules/bind/__init__.py
@@ -26,6 +26,7 @@ from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, menu
from plinth import service as service_module
+from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
from .manifest import backup
@@ -97,6 +98,10 @@ class BindApp(app_module.App):
parent_url_name='system')
self.add(menu_item)
+ firewall = Firewall('firewall-bind', name, ports=['dns'],
+ is_external=False)
+ self.add(firewall)
+
def init():
"""Intialize the BIND module."""
@@ -106,8 +111,7 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- ports=['dns'], is_external=False)
+ service = service_module.Service(managed_services[0], name)
app.set_enabled(True) # XXX: Perform better check
@@ -117,9 +121,7 @@ def setup(helper, old_version=None):
global service
if service is None:
service = service_module.Service(managed_services[0], name,
- ports=['dns'], is_external=True,
enable=enable, disable=disable)
- helper.call('post', service.notify_enabled, None, True)
helper.call('post', actions.superuser_run, 'bind', ['setup'])
helper.call('post', app.enable)
diff --git a/plinth/modules/cockpit/__init__.py b/plinth/modules/cockpit/__init__.py
index 3dc50ef80..cdbe925d1 100644
--- a/plinth/modules/cockpit/__init__.py
+++ b/plinth/modules/cockpit/__init__.py
@@ -26,6 +26,7 @@ from plinth import app as app_module
from plinth import cfg, frontpage, menu
from plinth import service as service_module
from plinth.modules import names
+from plinth.modules.firewall.components import Firewall
from plinth.signals import domain_added, domain_removed, domainname_change
from plinth.utils import format_lazy
@@ -80,6 +81,10 @@ class CockpitApp(app_module.App):
clients=clients, login_required=True)
self.add(shortcut)
+ firewall = Firewall('firewall-cockpit', name, ports=['http', 'https'],
+ is_external=True)
+ self.add(firewall)
+
def init():
"""Intialize the module."""
@@ -89,9 +94,8 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
+ service = service_module.Service(managed_services[0], name,
+ is_enabled=is_enabled, enable=enable,
disable=disable)
if is_enabled():
@@ -112,11 +116,9 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'cockpit', ['setup'] + domains)
global service
if service is None:
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
+ service = service_module.Service(managed_services[0], name,
+ is_enabled=is_enabled, enable=enable,
disable=disable)
- helper.call('post', service.notify_enabled, None, True)
helper.call('post', app.enable)
diff --git a/plinth/modules/coquelicot/__init__.py b/plinth/modules/coquelicot/__init__.py
index d8e13ba6e..fa28b3bf2 100644
--- a/plinth/modules/coquelicot/__init__.py
+++ b/plinth/modules/coquelicot/__init__.py
@@ -24,6 +24,7 @@ from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
from plinth import service as service_module
+from plinth.modules.firewall.components import Firewall
from .manifest import backup, clients
@@ -73,6 +74,11 @@ class CoquelicotApp(app_module.App):
clients=clients, login_required=True)
self.add(shortcut)
+ firewall = Firewall('firewall-coquelicot', name,
+ ports=['http', 'https'], is_external=True)
+ self.add(firewall)
+
+
def init():
"""Intialize the module."""
@@ -82,11 +88,9 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
- disable=disable,
- is_running=is_running)
+ service = service_module.Service(
+ managed_services[0], name, is_enabled=is_enabled, enable=enable,
+ disable=disable, is_running=is_running)
if is_enabled():
app.set_enabled(True)
@@ -99,12 +103,9 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'coquelicot', ['enable'])
global service
if service is None:
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
- disable=disable,
- is_running=is_running)
- helper.call('post', service.notify_enabled, None, True)
+ service = service_module.Service(
+ managed_services[0], name, is_enabled=is_enabled, enable=enable,
+ disable=disable, is_running=is_running)
helper.call('post', app.enable)
diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py
index d6b014f5b..2b7b40681 100644
--- a/plinth/modules/datetime/__init__.py
+++ b/plinth/modules/datetime/__init__.py
@@ -70,18 +70,15 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_external=True)
+ service = service_module.Service(managed_services[0], name)
def setup(helper, old_version=None):
"""Install and configure the module."""
global service
if service is None:
- service = service_module.Service(managed_services[0], name,
- is_external=True)
+ service = service_module.Service(managed_services[0], name)
service.enable()
- helper.call('post', service.notify_enabled, None, True)
helper.call('post', app.enable)
diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py
index 7df379187..915a9ccd5 100644
--- a/plinth/modules/deluge/__init__.py
+++ b/plinth/modules/deluge/__init__.py
@@ -24,6 +24,7 @@ from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
from plinth import service as service_module
+from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
from .manifest import backup, clients
@@ -75,6 +76,10 @@ class DelugeApp(app_module.App):
allowed_groups=[group[0]])
self.add(shortcut)
+ firewall = Firewall('firewall-deluge', name, ports=['http', 'https'],
+ is_external=True)
+ self.add(firewall)
+
def init():
"""Initialize the Deluge module."""
@@ -85,9 +90,8 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
+ service = service_module.Service(managed_services[0], name,
+ is_enabled=is_enabled, enable=enable,
disable=disable)
if is_enabled():
app.set_enabled(True)
@@ -99,11 +103,9 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'deluge', ['enable'])
global service
if service is None:
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
+ service = service_module.Service(managed_services[0], name,
+ is_enabled=is_enabled, enable=enable,
disable=disable)
- helper.call('post', service.notify_enabled, None, True)
helper.call('post', app.enable)
diff --git a/plinth/modules/diaspora/__init__.py b/plinth/modules/diaspora/__init__.py
index ab32ac417..d737cfade 100644
--- a/plinth/modules/diaspora/__init__.py
+++ b/plinth/modules/diaspora/__init__.py
@@ -24,6 +24,7 @@ from plinth import app as app_module
from plinth import frontpage, menu
from plinth import service as service_module
from plinth.errors import DomainNotRegisteredError
+from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
domain_name_file = "/etc/diaspora/domain_name"
@@ -92,6 +93,10 @@ class DiasporaApp(app_module.App):
icon='diaspora', url=None, clients=clients, login_required=True)
self.add(shortcut)
+ firewall = Firewall('firewall-diaspora', name, ports=['http', 'https'],
+ is_external=True)
+ self.add(firewall)
+
class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut to use configured domain name for URL."""
@@ -110,9 +115,8 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
+ service = service_module.Service(managed_services[0], name,
+ is_enabled=is_enabled, enable=enable,
disable=disable)
if is_enabled():
@@ -131,11 +135,9 @@ def setup_domain_name(domain_name):
actions.superuser_run('diaspora', ['setup', '--domain-name', domain_name])
global service
if service is None:
- service = service_module.Service(managed_services[0], name, ports=[
- 'http', 'https'
- ], is_external=True, is_enabled=is_enabled, enable=enable,
+ service = service_module.Service(managed_services[0], name,
+ is_enabled=is_enabled, enable=enable,
disable=disable)
- service.notify_enabled(None, True)
app.enable()
diff --git a/plinth/modules/ejabberd/__init__.py b/plinth/modules/ejabberd/__init__.py
index 7d73857a6..ba2a36575 100644
--- a/plinth/modules/ejabberd/__init__.py
+++ b/plinth/modules/ejabberd/__init__.py
@@ -28,6 +28,7 @@ from plinth import app as app_module
from plinth import cfg, frontpage, menu
from plinth import service as service_module
from plinth.modules import config
+from plinth.modules.firewall.components import Firewall
from plinth.signals import (domainname_change, post_hostname_change,
pre_hostname_change)
from plinth.utils import format_lazy
@@ -94,6 +95,11 @@ class EjabberdApp(app_module.App):
login_required=True)
self.add(shortcut)
+ firewall = Firewall('firewall-ejabberd', name,
+ ports=['xmpp-client', 'xmpp-server',
+ 'xmpp-bosh'], is_external=True)
+ self.add(firewall)
+
def init():
"""Initialize the ejabberd module"""
@@ -103,11 +109,9 @@ def init():
global service
setup_helper = globals()['setup_helper']
if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- 'ejabberd', name,
- ports=['xmpp-client', 'xmpp-server',
- 'xmpp-bosh'], is_external=True, is_enabled=is_enabled,
- enable=enable, disable=disable)
+ service = service_module.Service('ejabberd', name,
+ is_enabled=is_enabled, enable=enable,
+ disable=disable)
if is_enabled():
app.set_enabled(True)
@@ -127,12 +131,9 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'ejabberd', ['setup'])
global service
if service is None:
- service = service_module.Service(
- 'ejabberd', name,
- ports=['xmpp-client', 'xmpp-server',
- 'xmpp-bosh'], is_external=True, is_enabled=is_enabled,
- enable=enable, disable=disable)
- helper.call('post', service.notify_enabled, None, True)
+ service = service_module.Service('ejabberd', name,
+ is_enabled=is_enabled, enable=enable,
+ disable=disable)
helper.call('post', app.enable)
diff --git a/plinth/modules/firewall/__init__.py b/plinth/modules/firewall/__init__.py
index 1076cfa5f..540f1c3dd 100644
--- a/plinth/modules/firewall/__init__.py
+++ b/plinth/modules/firewall/__init__.py
@@ -18,15 +18,11 @@
FreedomBox app to configure a firewall.
"""
-import logging
-
from django.utils.translation import ugettext_lazy as _
-import plinth.service as service_module
from plinth import actions
from plinth import app as app_module
from plinth import cfg, menu
-from plinth.signals import service_enabled
from plinth.utils import Version, format_lazy
from .manifest import backup
@@ -49,8 +45,6 @@ description = [
manual_page = 'Firewall'
-LOGGER = logging.getLogger(__name__)
-
_port_details = {}
app = None
@@ -73,8 +67,6 @@ def init():
app = FirewallApp()
app.set_enabled(True)
- service_enabled.connect(on_service_enabled)
-
def setup(helper, old_version=None):
"""Install and configure the module."""
@@ -139,51 +131,6 @@ def remove_service(port, zone):
_run(['remove-service', port, '--zone', zone], superuser=True)
-def on_service_enabled(sender, service_id, enabled, **kwargs):
- """
- Enable/disable firewall ports when a service is
- enabled/disabled.
- """
- del sender # Unused
- del kwargs # Unused
-
- internal_enabled_services = get_enabled_services(zone='internal')
- external_enabled_services = get_enabled_services(zone='external')
-
- LOGGER.info('Service enabled - %s, %s', service_id, enabled)
- service = service_module.services[service_id]
- for port in service.ports:
- if enabled:
- if port not in internal_enabled_services:
- add_service(port, zone='internal')
-
- if (service.is_external and port not in external_enabled_services):
- add_service(port, zone='external')
- else:
- # service already configured.
- pass
- else:
- if port in internal_enabled_services:
- enabled_services_on_port = [
- service_.is_enabled()
- for service_ in service_module.services.values()
- if port in service_.ports
- and service_id != service_.service_id
- ]
- if not any(enabled_services_on_port):
- remove_service(port, zone='internal')
-
- if port in external_enabled_services:
- enabled_services_on_port = [
- service_.is_enabled()
- for service_ in service_module.services.values()
- if port in service_.ports and
- service_id != service_.service_id and service_.is_external
- ]
- if not any(enabled_services_on_port):
- remove_service(port, zone='external')
-
-
def _run(arguments, superuser=False):
"""Run an given command and raise exception if there was an error"""
command = 'firewall'
diff --git a/plinth/modules/firewall/components.py b/plinth/modules/firewall/components.py
new file mode 100644
index 000000000..525a3f1d0
--- /dev/null
+++ b/plinth/modules/firewall/components.py
@@ -0,0 +1,106 @@
+#
+# This file is part of FreedomBox.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see