Sunil Mohan Adapa ed3363105a
networks: Remove first boot steps for connectivity/topology
- We have not yet implemented the main reason they exist. To guide users to
establish reachability with Tor hidden services, Pagekite, Dynamic DNS, etc.

- We now have a 'Next steps' page that talks about configuring network
connections. The networks page linked from here has these steps prominently
listed.

- In the future we will implement a wizard for reachability and these steps will
still be used. However, they don't have to part of first setup. They can add
them as notification and as part of next steps page.

- It is good to have a simplified first setup wizard. It is seldom tested
properly.

Tests:

- Run the first setup wizard by removing /var/lib/plinth/plinth.sqlite3 and
running the service. Notice that the software update step is not shown and
wizard completes successfully.

[vexch: Minor quote fix in functional tests]
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Veiko Aasa <veiko17@disroot.org>
2024-10-10 09:19:01 +03:00

149 lines
4.9 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""FreedomBox app to interface with network-manager."""
import subprocess
from logging import Logger
from django.utils.translation import gettext_lazy as _
from plinth import app as app_module
from plinth import daemon, kvstore, menu, network
from plinth.config import DropinConfigs
from plinth.diagnostic_check import DiagnosticCheck
from plinth.modules.firewall.components import Firewall
from plinth.package import Packages
from . import privileged
_description = [
_('Configure network devices. Connect to the Internet via Ethernet, Wi-Fi '
'or PPPoE. Share that connection with other devices on the network.'),
_('Devices administered through other methods may not be available for '
'configuration here.'),
]
logger = Logger(__name__)
class NetworksApp(app_module.App):
"""FreedomBox app for Networks."""
app_id = 'networks'
_version = 2
can_be_disabled = False
def __init__(self) -> None:
"""Create components for the app."""
super().__init__()
info = app_module.Info(app_id=self.app_id, version=self._version,
is_essential=True, name=_('Networks'),
icon='fa-signal', description=_description,
manual_page='Networks')
self.add(info)
menu_item = menu.Menu('menu-networks', info.name, None, info.icon,
'networks:index',
parent_url_name='system:system', order=20)
self.add(menu_item)
packages = Packages('packages-networks', ['network-manager', 'batctl'])
self.add(packages)
# For 'shared' network connections
firewall = Firewall('firewall-networks', info.name,
ports=['dns', 'dhcp'], is_external=False)
self.add(firewall)
dropin_configs = DropinConfigs('dropin-configs-networks', [
'/etc/NetworkManager/dispatcher.d/10-freedombox-batman',
])
self.add(dropin_configs)
def diagnose(self) -> list[DiagnosticCheck]:
"""Run diagnostics and return the results."""
results = super().diagnose()
interfaces = _get_shared_interfaces()
addresses = _get_interface_addresses(interfaces)
for address in addresses:
results.append(daemon.diagnose_port_listening(53, 'tcp', address))
results.append(daemon.diagnose_port_listening(53, 'udp', address))
return results
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
privileged.setup()
self.enable()
def get_network_topology_type():
"""Return the currently configured network topology type or default."""
return kvstore.get_default('networks_topology_type', 'to_router')
def set_network_topology_type(network_topology_type):
"""Store the network topology type."""
kvstore.set('networks_topology_type', network_topology_type)
def get_internet_connection_type():
"""Return the currently configured internet connection type or default."""
return kvstore.get_default('networks_internet_type', 'unknown')
def set_internet_connection_type(internet_connection_type):
"""Store the internet connection type."""
return kvstore.set('networks_internet_type', internet_connection_type)
def get_router_configuration_type():
"""Return the currently configured router configuration type or default."""
return kvstore.get_default('networks_router_configuration_type',
'not_configured')
def set_router_configuration_type(router_configuration_type):
"""Store the router configuration type."""
return kvstore.set('networks_router_configuration_type',
router_configuration_type)
def _get_shared_interfaces():
"""Get active network interfaces in shared mode."""
shared_interfaces = []
for connection in network.get_connection_list():
if not connection['is_active']:
continue
connection_uuid = connection['uuid']
connection = network.get_connection(connection_uuid)
settings_ipv4 = connection.get_setting_ip4_config()
if settings_ipv4.get_method() == 'shared':
settings_connection = connection.get_setting_connection()
interface = settings_connection.get_interface_name()
if interface:
shared_interfaces.append(interface)
return shared_interfaces
def _get_interface_addresses(interfaces):
"""Get the IPv4 addresses for the given interfaces."""
output = subprocess.check_output(['ip', '-o', 'addr'])
lines = output.decode().splitlines()
addresses = []
for line in lines:
parts = line.split()
if parts[1] in interfaces and parts[2] == 'inet':
addresses.append(parts[3].split('/')[0])
return addresses