mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
- Secret is important for various functions of Django. There is no impact on existing installations due to the change. Improves the security of existing functions in minor ways and will be useful in future usage of Django. - Create the file in /var/lib/plinth/ with 0o600 permissions. - Make git ignore the file in code folder. - Don't copy the file during './setup.py install' operation. Impact to users after upgrade: - All existing sessions will get logged out. This is because SECRET_KEY is used to generate user session hash that is used to logout users when their password changes. Tests performed: - Run development version of service. File should get created in data/var/lib/plinth/django-secret.key. Permissions should be 0o600. - Run again, the file should not be overwritten. Printing django.conf.settings.SECRET_KEY should match the one in the file. - Run `setup.py install`. This should not install django-secret.key in /var/lib/plinth. - Run `sudo -u plinth plinth`. This should create the secret key file in /var/lib/plinth/django-secret.key. Permissions on the file should be 0o600. Ownership should be plinth:plinth. - Remove the file in both cases, a fresh new file should get created with new key. - Truncate the file to less than 128 chars, the existing file should get overwritten with new key. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""
|
|
Setup Django web framework.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import pathlib
|
|
import random
|
|
import stat
|
|
|
|
import django.conf
|
|
import django.core.management
|
|
import django.core.wsgi
|
|
from django.conf import global_settings
|
|
from django.contrib.messages import constants as message_constants
|
|
|
|
from . import cfg, log, module_loader, settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def init():
|
|
"""Setup Django configuration in the absence of .settings file"""
|
|
if cfg.secure_proxy_ssl_header:
|
|
settings.SECURE_PROXY_SSL_HEADER = (cfg.secure_proxy_ssl_header,
|
|
'https')
|
|
|
|
if cfg.use_x_forwarded_for:
|
|
settings.IPWARE_META_PRECEDENCE_ORDER = ('HTTP_X_FORWARDED_FOR', )
|
|
|
|
settings.DATABASES['default']['NAME'] = cfg.store_file
|
|
settings.DEBUG = cfg.develop
|
|
settings.FORCE_SCRIPT_NAME = cfg.server_dir
|
|
settings.INSTALLED_APPS += module_loader.get_modules_to_load()
|
|
settings.LANGUAGES = get_languages()
|
|
settings.LOGGING = log.get_configuration()
|
|
settings.MESSAGE_TAGS = {message_constants.ERROR: 'danger'}
|
|
settings.SECRET_KEY = _get_secret_key()
|
|
settings.SESSION_FILE_PATH = os.path.join(cfg.data_dir, 'sessions')
|
|
settings.STATIC_URL = '/'.join([cfg.server_dir,
|
|
'static/']).replace('//', '/')
|
|
settings.USE_X_FORWARDED_HOST = cfg.use_x_forwarded_host
|
|
|
|
kwargs = {}
|
|
for setting in dir(settings):
|
|
if setting.isupper():
|
|
kwargs[setting] = getattr(settings, setting)
|
|
|
|
django.conf.settings.configure(**kwargs)
|
|
django.setup(set_prefix=True)
|
|
|
|
logger.debug('Configured Django with applications - %s',
|
|
settings.INSTALLED_APPS)
|
|
|
|
logger.debug('Creating or adding new tables to data file')
|
|
verbosity = 1 if cfg.develop else 0
|
|
django.core.management.call_command('migrate', '--fake-initial',
|
|
interactive=False, verbosity=verbosity)
|
|
os.chmod(cfg.store_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
|
|
|
|
|
|
def _get_secret_key():
|
|
"""Retrieve or create a new Django secret key."""
|
|
secret_key_file = pathlib.Path(cfg.data_dir) / 'django-secret.key'
|
|
if secret_key_file.exists():
|
|
secret_key = secret_key_file.read_text()
|
|
if len(secret_key) >= 128:
|
|
return secret_key
|
|
|
|
secret_key = _generate_secret_key()
|
|
# File should be created with permission 0o700
|
|
old_umask = os.umask(0o077)
|
|
try:
|
|
secret_key_file.write_text(secret_key)
|
|
finally:
|
|
os.umask(old_umask)
|
|
|
|
return secret_key
|
|
|
|
|
|
def _generate_secret_key():
|
|
"""Generate a new random secret key for use with Django."""
|
|
# We could have used django.core.management.utils.get_random_secret_key
|
|
# but it is not documented and should be considered private.
|
|
length = 128
|
|
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
|
|
rand = random.SystemRandom()
|
|
return ''.join(rand.choice(chars) for _ in range(length))
|
|
|
|
|
|
def get_languages():
|
|
"""Return list of languages to show in the interface.
|
|
|
|
Add additional languages that FreedomBox support but Django doesn't.
|
|
|
|
"""
|
|
def gettext_noop(string):
|
|
"""Django's actual translation methods need Django to be setup."""
|
|
return string
|
|
|
|
return sorted(
|
|
list(global_settings.LANGUAGES) + [
|
|
('gu', gettext_noop('Gujarati')),
|
|
])
|
|
|
|
|
|
def get_wsgi_application():
|
|
"""Return Django wsgi application."""
|
|
return django.core.wsgi.get_wsgi_application()
|
|
|
|
|
|
def get_static_url():
|
|
"""Return Django static URL."""
|
|
return django.conf.settings.STATIC_URL
|
|
|
|
|
|
def get_ip_address_from_request(request):
|
|
"""Return the IP address of the original client."""
|
|
if cfg.use_x_forwarded_for:
|
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
|
ip_address = x_forwarded_for.split(',')[0]
|
|
else:
|
|
ip_address = request.META.get('REMOTE_ADDR')
|
|
|
|
return ip_address
|