From 3c3b2ee62167c499f7f2a047b9d635a28a58544a Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 2 May 2019 19:15:16 -0400 Subject: [PATCH] expose more django server config options --- archivebox/config/__init__.py | 29 ++++++++++++--- archivebox/config/stubs.py | 9 ++++- archivebox/core/settings.py | 43 ++++++++++------------- archivebox/core/urls.py | 6 ++++ archivebox/core/views.py | 18 +++++++++- archivebox/main.py | 6 ++-- archivebox/themes/default/main_index.html | 2 +- etc/ArchiveBox.conf.default | 13 +++++-- 8 files changed, 89 insertions(+), 37 deletions(-) diff --git a/archivebox/config/__init__.py b/archivebox/config/__init__.py index 72baec64..04b8515c 100644 --- a/archivebox/config/__init__.py +++ b/archivebox/config/__init__.py @@ -44,10 +44,19 @@ CONFIG_DEFAULTS: Dict[str, ConfigDefaultDict] = { 'TIMEOUT': {'type': int, 'default': 60}, 'MEDIA_TIMEOUT': {'type': int, 'default': 3600}, 'OUTPUT_PERMISSIONS': {'type': str, 'default': '755'}, - 'FOOTER_INFO': {'type': str, 'default': 'Content is hosted for personal archiving purposes only. Contact server owner for any takedown requests.'}, 'URL_BLACKLIST': {'type': str, 'default': None}, }, + 'SERVER_CONFIG': { + 'SECRET_KEY': {'type': str, 'default': None}, + 'ALLOWED_HOSTS': {'type': str, 'default': '*'}, + 'DEBUG': {'type': bool, 'default': False}, + 'PUBLIC_INDEX': {'type': bool, 'default': True}, + 'PUBLIC_SNAPSHOTS': {'type': bool, 'default': True}, + 'FOOTER_INFO': {'type': str, 'default': 'Content is hosted for personal archiving purposes only. Contact server owner for any takedown requests.'}, + 'ACTIVE_THEME': {'type': str, 'default': 'default'}, + }, + 'ARCHIVE_METHOD_TOGGLES': { 'SAVE_TITLE': {'type': bool, 'default': True, 'aliases': ('FETCH_TITLE',)}, 'SAVE_FAVICON': {'type': bool, 'default': True, 'aliases': ('FETCH_FAVICON',)}, @@ -313,9 +322,6 @@ def write_config_file(config: Dict[str, str], out_dir: str=None) -> ConfigDict: with open(config_path, 'w+') as f: f.write(CONFIG_HEADER) - if not config: - return {} - config_file = ConfigParser() config_file.optionxform = str config_file.read(config_path) @@ -336,6 +342,21 @@ def write_config_file(config: Dict[str, str], out_dir: str=None) -> ConfigDict: config_file[section] = {**existing_config, key: val} + # always make sure there's a SECRET_KEY defined for Django + existing_secret_key = None + if 'SERVER_CONFIG' in config_file and 'SECRET_KEY' in config_file['SERVER_CONFIG']: + existing_secret_key = config_file['SERVER_CONFIG']['SECRET_KEY'] + + if (not existing_secret_key) or ('not a valid secret' in existing_secret_key): + from django.utils.crypto import get_random_string + chars = 'abcdefghijklmnopqrstuvwxyz0123456789-_+!.' + random_secret_key = get_random_string(50, chars) + if 'SERVER_CONFIG' in config_file: + config_file['SERVER_CONFIG']['SECRET_KEY'] = random_secret_key + else: + config_file['SERVER_CONFIG'] = {'SECRET_KEY': random_secret_key} + + f.write(CONFIG_HEADER) config_file.write(f) try: diff --git a/archivebox/config/stubs.py b/archivebox/config/stubs.py index f7d5059a..7d3925dd 100644 --- a/archivebox/config/stubs.py +++ b/archivebox/config/stubs.py @@ -22,9 +22,16 @@ class ConfigDict(BaseConfig, total=False): TIMEOUT: int MEDIA_TIMEOUT: int OUTPUT_PERMISSIONS: str - FOOTER_INFO: str URL_BLACKLIST: Optional[str] + SECRET_KEY: str + ALLOWED_HOSTS: str + DEBUG: bool + PUBLIC_INDEX: bool + PUBLIC_SNAPSHOTS: bool + FOOTER_INFO: str + ACTIVE_THEME: str + SAVE_TITLE: bool SAVE_FAVICON: bool SAVE_WGET: bool diff --git a/archivebox/core/settings.py b/archivebox/core/settings.py index e128f8d0..463a7079 100644 --- a/archivebox/core/settings.py +++ b/archivebox/core/settings.py @@ -3,26 +3,25 @@ __package__ = 'archivebox.core' import os import sys -SECRET_KEY = '---------------- not a valid secret key ! ----------------' -DEBUG = os.getenv('DEBUG', 'False').lower() == 'true' -ALLOWED_HOSTS = ['*'] -REPO_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), os.path.pardir, os.path.pardir)) -OUTPUT_DIR = os.path.abspath(os.getenv('OUTPUT_DIR', os.curdir)) -ARCHIVE_DIR = os.path.join(OUTPUT_DIR, 'archive') -DATABASE_FILE = os.path.join(OUTPUT_DIR, 'index.sqlite3') +from ..config import ( + OUTPUT_DIR, + SECRET_KEY, + DEBUG, + ALLOWED_HOSTS, + PYTHON_DIR, + ACTIVE_THEME, + SQL_INDEX_FILENAME, +) -ACTIVE_THEME = 'default' +ALLOWED_HOSTS = ALLOWED_HOSTS.split(',') IS_SHELL = 'shell' in sys.argv[:3] or 'shell_plus' in sys.argv[:3] -APPEND_SLASH = True - INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', - # 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.admin', 'django.contrib.staticfiles', @@ -40,17 +39,17 @@ MIDDLEWARE = [ 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'core.urls' +APPEND_SLASH = True TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ - os.path.join(REPO_DIR, 'themes', ACTIVE_THEME), - os.path.join(REPO_DIR, 'themes', 'default'), - os.path.join(REPO_DIR, 'themes'), + os.path.join(PYTHON_DIR, 'themes', ACTIVE_THEME), + os.path.join(PYTHON_DIR, 'themes', 'default'), + os.path.join(PYTHON_DIR, 'themes'), ], 'APP_DIRS': True, 'OPTIONS': { @@ -69,7 +68,7 @@ WSGI_APPLICATION = 'core.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': DATABASE_FILE, + 'NAME': os.path.join(OUTPUT_DIR, SQL_INDEX_FILENAME), } } @@ -104,7 +103,7 @@ SHELL_PLUS_PRINT_SQL = False IPYTHON_ARGUMENTS = ['--no-confirm-exit', '--no-banner'] IPYTHON_KERNEL_DISPLAY_NAME = 'ArchiveBox Django Shell' if IS_SHELL: - os.environ['PYTHONSTARTUP'] = os.path.join(REPO_DIR, 'core', 'welcome_message.py') + os.environ['PYTHONSTARTUP'] = os.path.join(PYTHON_DIR, 'core', 'welcome_message.py') LANGUAGE_CODE = 'en-us' @@ -118,11 +117,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' STATIC_URL = '/static/' STATICFILES_DIRS = [ - os.path.join(REPO_DIR, 'themes', ACTIVE_THEME, 'static'), - os.path.join(REPO_DIR, 'themes', 'default', 'static'), - os.path.join(REPO_DIR, 'themes', 'static'), + os.path.join(PYTHON_DIR, 'themes', ACTIVE_THEME, 'static'), + os.path.join(PYTHON_DIR, 'themes', 'default', 'static'), + os.path.join(PYTHON_DIR, 'themes', 'static'), ] - -SERVE_STATIC = True - - diff --git a/archivebox/core/urls.py b/archivebox/core/urls.py index 2a001f6b..9b4af5a5 100644 --- a/archivebox/core/urls.py +++ b/archivebox/core/urls.py @@ -22,8 +22,14 @@ urlpatterns = [ path('add/', AddLinks.as_view(), name='AddLinks'), path('static/', views.serve), + + path('accounts/login/', RedirectView.as_view(url='/admin/login/')), + path('accounts/logout/', RedirectView.as_view(url='/admin/logout/')), + path('accounts/', include('django.contrib.auth.urls')), path('admin/', admin.site.urls), + + path('', MainIndex.as_view(), name='Home'), ] diff --git a/archivebox/core/views.py b/archivebox/core/views.py index 2c140d58..7fee7408 100644 --- a/archivebox/core/views.py +++ b/archivebox/core/views.py @@ -4,11 +4,18 @@ from django.shortcuts import render, redirect from django.http import HttpResponse from django.views import View, static +from django.conf import settings from core.models import Snapshot from ..index import load_main_index, load_main_index_meta -from ..config import OUTPUT_DIR, VERSION, FOOTER_INFO +from ..config import ( + OUTPUT_DIR, + VERSION, + FOOTER_INFO, + PUBLIC_INDEX, + PUBLIC_SNAPSHOTS, +) from ..util import base_url @@ -16,6 +23,9 @@ class MainIndex(View): template = 'main_index.html' def get(self, request): + if not request.user.is_authenticated and not PUBLIC_INDEX: + return redirect(f'/admin/login/?next={request.path}') + all_links = load_main_index(out_dir=OUTPUT_DIR) meta_info = load_main_index_meta(out_dir=OUTPUT_DIR) @@ -34,6 +44,9 @@ class AddLinks(View): template = 'add_links.html' def get(self, request): + if not request.user.is_authenticated and not PUBLIC_INDEX: + return redirect(f'/admin/login/?next={request.path}') + context = {} return render(template_name=self.template, request=request, context=context) @@ -54,6 +67,9 @@ class LinkDetails(View): if '/' not in path: return redirect(f'{path}/index.html') + if not request.user.is_authenticated and not PUBLIC_SNAPSHOTS: + return redirect(f'/admin/login/?next={request.path}') + try: slug, archivefile = path.split('/', 1) except (IndexError, ValueError): diff --git a/archivebox/main.py b/archivebox/main.py index 00529743..80e4b77b 100644 --- a/archivebox/main.py +++ b/archivebox/main.py @@ -292,14 +292,14 @@ def init(force: bool=False, out_dir: str=OUTPUT_DIR) -> None: setup_django(out_dir, check_db=False) from django.conf import settings - assert settings.DATABASE_FILE == os.path.join(out_dir, SQL_INDEX_FILENAME) - print(f' √ {settings.DATABASE_FILE}') + DATABASE_FILE = os.path.join(out_dir, SQL_INDEX_FILENAME) + print(f' √ {DATABASE_FILE}') print() for migration_line in apply_migrations(out_dir): print(f' {migration_line}') - assert os.path.exists(settings.DATABASE_FILE) + assert os.path.exists(DATABASE_FILE) # from django.contrib.auth.models import User # if IS_TTY and not User.objects.filter(is_superuser=True).exists(): diff --git a/archivebox/themes/default/main_index.html b/archivebox/themes/default/main_index.html index 4ad00be7..925c4fa4 100644 --- a/archivebox/themes/default/main_index.html +++ b/archivebox/themes/default/main_index.html @@ -190,7 +190,7 @@
Add Links   |   - Admin   |   + Admin   |   Docs
diff --git a/etc/ArchiveBox.conf.default b/etc/ArchiveBox.conf.default index 31017ce4..df9abe22 100644 --- a/etc/ArchiveBox.conf.default +++ b/etc/ArchiveBox.conf.default @@ -1,6 +1,6 @@ # This is the example default configiration file for ArchiveBox. # -# Copy example config from here into your project's ArchiveBox.conf file, +# Copy lines from here into your project's ArchiveBox.conf file and uncomment, # DO NOT EDIT THIS FILE DIRECTLY! # # See the list of all the possible options. documentation, and examples here: @@ -11,10 +11,17 @@ # ONLY_NEW = False # TIMEOUT = 60 # MEDIA_TIMEOUT = 3600 -# ACTIVE_THEME = default -# FOOTER_INFO = Content is hosted for personal archiving purposes only. Contact server owner for any takedown requests. # URL_BLACKLIST = (://(.*\.)?facebook\.com)|(://(.*\.)?ebay\.com)|(.*\.exe$) +[SERVER_CONFIG] +# SECRET_KEY = ---------------- not a valid secret key ! ---------------- +# DEBUG = False +# PUBLIC_INDEX = True +# PUBLIC_SNAPSHOTS = True +# FOOTER_INFO = Content is hosted for personal archiving purposes only. Contact server owner for any takedown requests. +# ACTIVE_THEME = default + + [ARCHIVE_METHOD_TOGGLES] # SAVE_TITLE = True # SAVE_FAVICON = True