mirror of
https://github.com/towalink/wgfrontend.git
synced 2025-04-19 08:55:11 +00:00
Add session security headers
This commit is contained in:
parent
538ec90b1f
commit
5b3ea75164
@ -10,7 +10,7 @@ All notable changes to this project are documented in this file.
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- n/a
|
- Add session security headers
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ from . import setupenv_alpine
|
|||||||
|
|
||||||
|
|
||||||
def is_root():
|
def is_root():
|
||||||
"""Returns whether this script is run with user is 0 (root)"""
|
"""Returns whether this script is run with user id 0 (root)"""
|
||||||
return os.getuid() == 0
|
return os.getuid() == 0
|
||||||
|
|
||||||
def get_user():
|
def get_user():
|
||||||
@ -108,6 +108,14 @@ def get_primary_interface_addr4():
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_second_subnet():
|
||||||
|
"""Returns the second /28 subnet of the local network as well as the local network"""
|
||||||
|
ip = get_primary_interface_addr4()
|
||||||
|
net = ipaddress.ip_interface(ip).network
|
||||||
|
nets = net.subnets(new_prefix=28)
|
||||||
|
next(nets)
|
||||||
|
return next(nets), net
|
||||||
|
|
||||||
|
|
||||||
class QueryUser():
|
class QueryUser():
|
||||||
"""Interact with the user"""
|
"""Interact with the user"""
|
||||||
@ -116,8 +124,11 @@ class QueryUser():
|
|||||||
"""Object initialization"""
|
"""Object initialization"""
|
||||||
self._expert = None
|
self._expert = None
|
||||||
|
|
||||||
def input_yes_no(self, display_text, default='Yes'):
|
def input_yes_no(self, display_text, default='Yes', expert_question=False):
|
||||||
"""Queries the user for a yes or no answer"""
|
"""Queries the user for a yes or no answer"""
|
||||||
|
if expert_question is not None:
|
||||||
|
if expert_question and not self.expert:
|
||||||
|
return default
|
||||||
while True:
|
while True:
|
||||||
answer = input(f' {display_text} ')
|
answer = input(f' {display_text} ')
|
||||||
answer = answer.strip()
|
answer = answer.strip()
|
||||||
@ -132,7 +143,7 @@ class QueryUser():
|
|||||||
|
|
||||||
def query_expert(self):
|
def query_expert(self):
|
||||||
"""Queries the user on whether he wants expert configuration"""
|
"""Queries the user on whether he wants expert configuration"""
|
||||||
expert = self.input_yes_no('Do you want to use expert configuration? [No]:', default='No')
|
expert = self.input_yes_no('Do you want to use expert configuration? [No]:', default='No', expert_question=None)
|
||||||
return expert
|
return expert
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -244,7 +255,7 @@ class QueryUser():
|
|||||||
print(' In a home environment, this is usually a DynDNS name denoting your Internet router.')
|
print(' In a home environment, this is usually a DynDNS name denoting your Internet router.')
|
||||||
return self.get_and_validate_input('Please specify the endpoint hostname (and optionally port) to reach your WireGuard server:', default='', check_function=check, expert_question=False)
|
return self.get_and_validate_input('Please specify the endpoint hostname (and optionally port) to reach your WireGuard server:', default='', check_function=check, expert_question=False)
|
||||||
|
|
||||||
def get_wg_address(self):
|
def get_wg_address(self, default='192.168.0.17/28'):
|
||||||
"""Query the user for the IP address of the WireGuard interface incl. prefix length"""
|
"""Query the user for the IP address of the WireGuard interface incl. prefix length"""
|
||||||
|
|
||||||
def check(userdata):
|
def check(userdata):
|
||||||
@ -255,7 +266,7 @@ class QueryUser():
|
|||||||
print(' Exception: {text}'.format(text=str(e)))
|
print(' Exception: {text}'.format(text=str(e)))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.get_and_validate_input('Please specify the IP address of the WireGuard interface incl. prefix length [192.168.0.17/28]:', default='192.168.0.17/28', check_function=check, expert_question=False)
|
return self.get_and_validate_input(f'Please specify the IP address of the WireGuard interface incl. prefix length [{default}]:', default=default, check_function=check, expert_question=False)
|
||||||
|
|
||||||
def get_wg_networks(self):
|
def get_wg_networks(self):
|
||||||
"""Query the user for the network ranges that the clients shall route to the WireGuard server"""
|
"""Query the user for the network ranges that the clients shall route to the WireGuard server"""
|
||||||
@ -307,17 +318,21 @@ def setup_environment():
|
|||||||
if os.path.exists(cfg.wg_configfile):
|
if os.path.exists(cfg.wg_configfile):
|
||||||
print(f'WireGuard config file {cfg.wg_configfile} already exists. Ok.')
|
print(f'WireGuard config file {cfg.wg_configfile} already exists. Ok.')
|
||||||
else:
|
else:
|
||||||
|
network_subrange, network_local = get_second_subnet()
|
||||||
|
ip_wgif = network_subrange[1]
|
||||||
print(f'WireGuard config file {cfg.wg_configfile} does not yet exist. Let\'s create one...')
|
print(f'WireGuard config file {cfg.wg_configfile} does not yet exist. Let\'s create one...')
|
||||||
print(' For documentation on possible setups, please refer to')
|
print(' For documentation on possible setups, please refer to')
|
||||||
print(' https://github.com/towalink/wgfrontend/tree/main/doc/network-integration')
|
print(' https://github.com/towalink/wgfrontend/tree/main/doc/network-integration')
|
||||||
print(' Automated configuration is only supported for the ProxyARP setup.')
|
print(' Automated configuration is only supported for the ProxyARP setup.')
|
||||||
print(' For this, choose an unused subrange of your local network for WireGuard.')
|
print(' For this, choose an unused subrange of your local network for WireGuard.')
|
||||||
print(' If your local network were 192.168.0.0/24, you could use the subrange')
|
print(f' For your local network {network_local.exploded}, you could e.g. use the subrange')
|
||||||
print(' 192.168.0.16/28 with 192.168.0.17/28 as the WireGuard interface address.')
|
print(f' {network_subrange.exploded} with {ip_wgif}/{network_subrange.prefixlen} as the WireGuard interface address')
|
||||||
print(' Press enter to select defaults.')
|
print(f' and the other addresses for clients. For this, the addresses from {network_subrange.network_address}')
|
||||||
|
print(f' to {network_subrange.broadcast_address} must not be in use in your network.')
|
||||||
|
print(f' Press enter to select defaults.')
|
||||||
wg_listenport = qu.get_wg_listenport()
|
wg_listenport = qu.get_wg_listenport()
|
||||||
endpoint = qu.get_endpoint()
|
endpoint = qu.get_endpoint()
|
||||||
wg_address_obj = qu.get_wg_address()
|
wg_address_obj = qu.get_wg_address(default=ip_wgif.exploded + '/' + str(network_subrange.prefixlen))
|
||||||
wg_networks = qu.get_wg_networks()
|
wg_networks = qu.get_wg_networks()
|
||||||
# Check for ProxyARP setup
|
# Check for ProxyARP setup
|
||||||
proxy_arp_interface = None
|
proxy_arp_interface = None
|
||||||
@ -327,7 +342,7 @@ def setup_environment():
|
|||||||
if wg_address_obj.network.subnet_of(eth_address_obj.network):
|
if wg_address_obj.network.subnet_of(eth_address_obj.network):
|
||||||
interface_name = get_primary_interface()
|
interface_name = get_primary_interface()
|
||||||
print(' Setup for ProxyARP detected.')
|
print(' Setup for ProxyARP detected.')
|
||||||
if qu.input_yes_no(f'7e) Do you want to configure ProxyARP on interface {interface_name} when bringing up the WireGuard interface? [Yes]: '):
|
if qu.input_yes_no(f'7e) Do you want to configure ProxyARP on interface {interface_name} when bringing up the WireGuard interface? [Yes]: ', expert_question=True):
|
||||||
proxy_arp_interface = interface_name
|
proxy_arp_interface = interface_name
|
||||||
else:
|
else:
|
||||||
print(' Please configure your network setup based on the documentation referenced above.')
|
print(' Please configure your network setup based on the documentation referenced above.')
|
||||||
@ -344,7 +359,19 @@ def setup_environment():
|
|||||||
wc.write_file()
|
wc.write_file()
|
||||||
print(' Config file written. Ok.')
|
print(' Config file written. Ok.')
|
||||||
eh = exechelper.ExecHelper()
|
eh = exechelper.ExecHelper()
|
||||||
if qu.input_yes_no(f'Would you like to allow the system user of the web frontend to reload WireGuard on config on changes (using sudo)? [Yes]:'):
|
if qu.input_yes_no(f'Would you like to enable IP Forwarding so that this device can act as a router? [Yes]:', expert_question=True):
|
||||||
|
eh.execute('sysctl -w net.ipv4.ip_forward=1', suppressoutput=True, suppresserrors=False)
|
||||||
|
eh.execute('sysctl -w net.ipv6.conf.all.forwarding=1', suppressoutput=True, suppresserrors=False)
|
||||||
|
ipforwarding_content = textwrap.dedent(f'''\
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
|
net.ipv6.conf.all.forwarding = 1
|
||||||
|
''')
|
||||||
|
if os.path.isdir('/etc/sysctl.d'):
|
||||||
|
with open('/etc/sysctl.d/99-wgfrontend-forwarding.conf', 'w') as ipforwarding_file:
|
||||||
|
ipforwarding_file.write(ipforwarding_content)
|
||||||
|
else:
|
||||||
|
print(' Sorry, "/etc/sysctl.d" does not exist so that we could not install a config file there.')
|
||||||
|
if qu.input_yes_no(f'Would you like to allow the system user of the web frontend to reload WireGuard on config changes (using sudo)? [Yes]:'):
|
||||||
sudoers_content = textwrap.dedent(f'''\
|
sudoers_content = textwrap.dedent(f'''\
|
||||||
{cfg.user} ALL=(root) NOPASSWD: /etc/init.d/wgfrontend_interface start, /etc/init.d/wgfrontend_interface stop, /etc/init.d/wgfrontend_interface restart
|
{cfg.user} ALL=(root) NOPASSWD: /etc/init.d/wgfrontend_interface start, /etc/init.d/wgfrontend_interface stop, /etc/init.d/wgfrontend_interface restart
|
||||||
{cfg.user} ALL=(root) NOPASSWD: /usr/bin/wg-quick down {cfg.wg_configfile}, /usr/bin/wg-quick up {cfg.wg_configfile}
|
{cfg.user} ALL=(root) NOPASSWD: /usr/bin/wg-quick down {cfg.wg_configfile}, /usr/bin/wg-quick up {cfg.wg_configfile}
|
||||||
@ -354,14 +381,14 @@ def setup_environment():
|
|||||||
sudoers_file.write(sudoers_content)
|
sudoers_file.write(sudoers_content)
|
||||||
else:
|
else:
|
||||||
print(' Sorry, "/etc/sudoers.d" does not exist so that sudo could not be configured. Maybe "sudo" is not installed.')
|
print(' Sorry, "/etc/sudoers.d" does not exist so that sudo could not be configured. Maybe "sudo" is not installed.')
|
||||||
if qu.input_yes_no(f'Would you like to activate the WireGuard interface "{cfg.wg_interface}" now? [Yes]:'):
|
if qu.input_yes_no(f'Would you like to activate the WireGuard interface "{cfg.wg_interface}" now? [Yes]:', expert_question=True):
|
||||||
eh.run_wgquick('up', cfg.wg_interface)
|
eh.run_wgquick('up', cfg.wg_interface)
|
||||||
if qu.input_yes_no(f'Would you like to activate the WireGuard interface "{cfg.wg_interface}" on boot? [Yes]:'):
|
if qu.input_yes_no(f'Would you like to activate the WireGuard interface "{cfg.wg_interface}" on boot? [Yes]:', expert_question=True):
|
||||||
if eh.os_id == 'alpine':
|
if eh.os_id == 'alpine':
|
||||||
setupenv_alpine.start_wginterface_onboot()
|
setupenv_alpine.start_wginterface_onboot()
|
||||||
else:
|
else:
|
||||||
eh.enable_service(f'wg-quick@{cfg.wg_interface}')
|
eh.enable_service(f'wg-quick@{cfg.wg_interface}')
|
||||||
if qu.input_yes_no(f'Would you like to start wgfrontend on boot? [Yes]:'):
|
if qu.input_yes_no(f'Would you like to start wgfrontend on boot? [Yes]:', expert_question=True):
|
||||||
if eh.os_id == 'alpine':
|
if eh.os_id == 'alpine':
|
||||||
setupenv_alpine.start_wgfrontend_onboot()
|
setupenv_alpine.start_wgfrontend_onboot()
|
||||||
else:
|
else:
|
||||||
@ -379,15 +406,12 @@ def setup_environment():
|
|||||||
Group={cfg.user}
|
Group={cfg.user}
|
||||||
StandardOutput=append:/var/log/wgfrontend.log
|
StandardOutput=append:/var/log/wgfrontend.log
|
||||||
StandardError=inherit
|
StandardError=inherit
|
||||||
# journalctl -u sh-dimplex
|
|
||||||
#StandardOutput=syslog
|
|
||||||
#StandardError=syslog
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
''')
|
''')
|
||||||
if os.path.isdir('/etc/systemd/system'):
|
if os.path.isdir('/etc/systemd/system'):
|
||||||
with open('/etc/systemd/system/smarthome.service', 'w') as systemd_file:
|
with open('/etc/systemd/system/wgfrontend.service', 'w') as systemd_file:
|
||||||
systemd_file.write(systemd_content)
|
systemd_file.write(systemd_content)
|
||||||
eh.execute('systemctl daemon-reload', suppressoutput=True, suppresserrors=True)
|
eh.execute('systemctl daemon-reload', suppressoutput=True, suppresserrors=True)
|
||||||
eh.enable_service('wgfrontend')
|
eh.enable_service('wgfrontend')
|
||||||
|
@ -112,6 +112,8 @@ def run_webapp(cfg):
|
|||||||
},
|
},
|
||||||
'/': {
|
'/': {
|
||||||
'tools.sessions.on': True,
|
'tools.sessions.on': True,
|
||||||
|
'tools.sessions.secure': True,
|
||||||
|
'tools.sessions.httponly': True,
|
||||||
'tools.staticdir.root': os.path.join(script_path, 'webroot'),
|
'tools.staticdir.root': os.path.join(script_path, 'webroot'),
|
||||||
'tools.session_auth.on': True,
|
'tools.session_auth.on': True,
|
||||||
'tools.session_auth.login_screen': app.login_screen,
|
'tools.session_auth.login_screen': app.login_screen,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user