Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate a unique SECRET_KEY_FILE when deploying a new django instance (ref: build_suite.sh) #531

Merged
merged 18 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ docs/locales/**/*.mo

# Bower components
/g3w-admin/core/static/bower_components/
/g3w-admin/core/static/bower_components

# Coverage html test result reports
/g3w-admin/htmlcov/
Expand Down
10 changes: 6 additions & 4 deletions ci_scripts/build_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@
set -e

CODE_DIRECTORY='/code'
DJANGO_DIRECTORY="${CODE_DIRECTORY}/g3w-admin"
DATASOURCE_PATH='/shared-volume/project_data'
MEDIA_ROOT='/shared-volume/media'
PROJECTS_DIR="${MEDIA_ROOT}/projects"
BUILD_DONE_FILE='/shared-volume/build_done'
DJANGO_DIRECTORY="${CODE_DIRECTORY}/g3w-admin"
SECRET_KEY_FILE='/shared-volume/.secret_key'

cd '/code/'
cd "${CODE_DIRECTORY}"


if [ ! -e ${BUILD_DONE_FILE} ]; then
echo "Build started for G3W-Suite installation ..."

echo "Building javascript code ..."
echo "Install javascript dependencies ..."
yarn --ignore-engines --ignore-scripts --prod
nodejs -e "try { require('fs').symlinkSync(require('path').resolve('node_modules/@bower_components'), 'g3w-admin/core/static/bower_components', 'junction') } catch (e) { console.log(e); }"

touch ${BUILD_DONE_FILE}
else
echo "Build was already done, skipping ..."
echo "Build already done, skipping ..."
fi

8 changes: 6 additions & 2 deletions ci_scripts/setup_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
set -e

CODE_DIRECTORY='/code'
DJANGO_DIRECTORY="${CODE_DIRECTORY}/g3w-admin"
DATASOURCE_PATH='/shared-volume/project_data'
MEDIA_ROOT='/shared-volume/media'
STATIC_ROOT='/shared-volume/static'
PROJECTS_DIR="${MEDIA_ROOT}/projects"
SECRET_KEY_FILE='/shared-volume/.secret_key'
SETUP_DONE_FILE='/shared-volume/setup_done'
DJANGO_DIRECTORY="${CODE_DIRECTORY}/g3w-admin"

cd '/code/'
cd "${CODE_DIRECTORY}"


if [ ! -e ${SETUP_DONE_FILE} ]; then
Expand Down Expand Up @@ -51,6 +52,9 @@ if [ ! -e ${SETUP_DONE_FILE} ]; then
ln -s "/code/node_modules/@bower_components" bower_components
popd

echo "Creating a unique SECRET_KEY file ..."
python3 "${DJANGO_DIRECTORY}/manage.py" generate_secret_key_file -o ${SECRET_KEY_FILE}

cd ${DJANGO_DIRECTORY}
if [[ -z ${G3WSUITE_DEBUG} || ${G3WSUITE_DEBUG} != "True" ]]; then
rm -rf ${STATIC_ROOT}
Expand Down
53 changes: 53 additions & 0 deletions g3w-admin/base/management/commands/generate_secret_key_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# coding=utf-8
""""
CLI command for generation of unique SECRET_KEY
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the Mozilla Public License 2.0.

"""

__author__ = '[email protected]'
__date__ = '2023-04-26'
__copyright__ = 'Copyright 2015 - 2023, Gis3w'
__license__ = 'MPL 2.0'

from django.core.management.base import BaseCommand
from django.core.management.utils import get_random_secret_key
import os

# https://stackoverflow.com/a/53168794
def blankout(instr, r='*', s=1, e=-1):
if '@' in instr:
# Handle E-Mail addresses
a = instr.split('@')
if e == 0:
e = len(instr)
return instr.replace(a[0][s:e], r * (len(a[0][s:e])))
if e == 0:
e = len(instr)
return instr.replace(instr[s:e], r * len(instr[s:e]))

class Command(BaseCommand):
"""
Create a random SECRET_KEY setting value and put it inside a file
"""

help = 'Create a SECRET_KEY setting value and put inside a file.'

def add_arguments(self, parser):

# Positional arguments
default_file_path = f"{os.path.abspath(os.path.dirname(__file__))}/.secret_key"

parser.add_argument('-o', '--output-file', dest='output_file', default=default_file_path, nargs=1, type=str)

def handle(self, *args, **options):

output_file = options['output_file'][0]

key = get_random_secret_key()
secret_file = open(output_file, "w")
secret_file.write(key)
secret_file.close()

self.stdout.write(self.style.SUCCESS(f"[SECRET_KEY] write '{blankout(key, s=5)}' into {output_file}"))
45 changes: 25 additions & 20 deletions g3w-admin/base/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,22 @@
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'y#-4cgqw2(zyt1uy_(l5sa(xq550*6$s#3y*r=v+6#wb6^3(4)'

# SECURITY WARNING: don't run with debug turned on in production!
# SECURITY WARNING: don't run with DEBUG turned on in production!
DEBUG = True

# SECURITY WARNING: keep the SECRET_KEY used in production secret!
if not hasattr(__import__(__name__), 'SECRET_KEY'):
try:
# Parse SECRET_KEY from SECRET_KEY_FILE environment variable
with open(os.getenv('SECRET_KEY_FILE', '/shared-volume/.secret_key')) as f:
SECRET_KEY = f.read().strip()
except:
print('[SECRET_KEY] setting not provided, fallback to a temporary random key')
# Generate a temporary secret key (on each reboot) until you
# provide a SECRET_KEY or SECRET_KEY_FILE variable
from django.core.management.utils import get_random_secret_key
SECRET_KEY = get_random_secret_key()

ALLOWED_HOSTS = ['localhost']


Expand All @@ -38,7 +48,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.gis',
#'django.contrib.sites'
#'django.contrib.sites',
]

THIRD_PARTY_APPS = [
Expand All @@ -62,19 +72,19 @@
'huey.contrib.djhuey',
'bx_py_utils', # required by huey_monitor
'huey_monitor',
'about'
'about',
]

G3WADMIN_APPS = [
'base',
'core',
'client',
'usersmanage',
'OWS'
'OWS',
]

G3WADMIN_PROJECT_APPS_BASE = [
'qdjango'
'qdjango',
]

G3WADMIN_PROJECT_APPS = []
Expand All @@ -90,7 +100,7 @@
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware',
'qdjango.process_events_middleware.process_events_middleware'
'qdjango.process_events_middleware.process_events_middleware',
]


Expand Down Expand Up @@ -118,9 +128,8 @@
# 'django.template.loaders.filesystem.Loader',
# 'django.template.loaders.app_directories.Loader'
#]),
]
],
},

},
]

Expand Down Expand Up @@ -149,7 +158,7 @@

AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'guardian.backends.ObjectPermissionBackend'
'guardian.backends.ObjectPermissionBackend',
)

GUARDIAN_RAISE_403 = True
Expand Down Expand Up @@ -188,9 +197,9 @@
('en', 'English'),
('fr', 'French'),
('fi', 'Finnish'),
('se', 'Swedish'),
('se', 'Swedish'), # FIXME: correct language code should be "sv"
('ro', 'Romanian'),
('de', 'Deutsch')
('de', 'Deutsch'),
)

MODELTRANSLATION_DEFAULT_LANGUAGE = 'it'
Expand All @@ -208,7 +217,7 @@
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100,
'UNICODE_JSON': False,
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

# FOR MEDIA
Expand Down Expand Up @@ -265,10 +274,6 @@
DB_LOGGER_ADMIN_LIST_PER_PAGE = 10
DB_LOGGER_ENABLE_FORMATTER = False


MGC = '-99:dodfEz3K2rziGayGnw_FyOuWdCM'
MPC = '-99:dodfEz3K2rziGayGnw_FyOuWdCM'

FRONTEND = False
FRONTEND_APP = 'frontend'

Expand All @@ -288,7 +293,7 @@


INTERNAL_IPS = [
'127.0.0.1'
'127.0.0.1',
]


Expand Down
32 changes: 0 additions & 32 deletions g3w-admin/core/utils/decorators.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,12 @@
from django.utils.decorators import wraps
from django.core.signing import Signer
from django.http.response import HttpResponseForbidden
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.conf import settings
from django.shortcuts import get_object_or_404
from django.apps import apps
from django.contrib.auth import REDIRECT_FIELD_NAME
from guardian.exceptions import GuardianError
from guardian.utils import get_40x_or_None
from .projects import countAllProjects

globalSigner = Signer()


def check_madd(var, model, **kwargs):
var = globalSigner.unsign(var)
var_value = getattr(settings, var)
if not var_value:
raise Exception('MGC or MPC is not set!')

def decorator(view_func):
def _wrapped_view(request, *args, **kwargs):

if var_value == '-99:dodfEz3K2rziGayGnw_FyOuWdCM':
return view_func(request, *args, **kwargs)

if var == 'MPC:XYamtBJA_JgFGmFvEa9x193rnLg':
objects = countAllProjects()
else:
objects = model.objects.count()

if objects >= int(globalSigner.unsign(var_value)):
template_name = 'core/403_{}.html'.format(var)
response = render_to_response(template_name, {}, RequestContext(request))
response.status_code = 403
return response
return view_func(request, *args, **kwargs)
return wraps(view_func)(_wrapped_view)
return decorator


def project_type_permission_required(perm, lookup_variables=None, **kwargs):
Expand Down
2 changes: 0 additions & 2 deletions g3w-admin/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from .forms import GroupForm, GeneralSuiteDataForm, MacroGroupForm
from .models import Group, GroupProjectPanoramic, MapControl, GeneralSuiteData, MacroGroup
from .mixins.views import G3WRequestViewMixin, G3WAjaxDeleteViewMixin, G3WAjaxSetOrderViewMixin
from .utils.decorators import check_madd
from .signals import after_update_group, execute_search_on_models
import requests
import json
Expand Down Expand Up @@ -141,7 +140,6 @@ class GroupCreateView(G3WRequestViewMixin, CreateView):
form_class = GroupForm

@method_decorator(permission_required('core.add_group', return_403=True))
@method_decorator(check_madd('MGC:kTccysDKRCPgT5M5y6sv-OSWlck', Group))
def dispatch(self, *args, **kwargs):
return super(GroupCreateView, self).dispatch(*args, **kwargs)

Expand Down
21 changes: 11 additions & 10 deletions g3w-admin/qdjango/views/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@
UpdateView,
ListView,
DetailView,
TemplateView,
FormView,
View,
)
from django.views.generic.detail import SingleObjectMixin
from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.db import connections
from django.conf import settings
from django.core.cache import caches
from django.utils.translation import gettext_lazy as _
from guardian.decorators import permission_required
from guardian.shortcuts import get_objects_for_user
from core.mixins.views import *
from core.signals import pre_update_project, pre_delete_project, after_update_project, before_delete_project
from core.utils.decorators import check_madd, project_type_permission_required, is_active_required
from core.utils.decorators import project_type_permission_required, is_active_required
from django_downloadview import ObjectDownloadView
from rest_framework.response import Response
from usersmanage.mixins.views import G3WACLViewMixin
Expand All @@ -30,17 +28,21 @@
if 'editing' in settings.INSTALLED_APPS:
from editing.models import G3WEditingLayer, EDITING_ATOMIC_PERMISSIONS

from qdjango.models import GeoConstraint, SingleLayerConstraint, ColumnAcl, LayerAcl

from qdjango.signals import load_qdjango_widgets_data
from qdjango.mixins.views import *
from qdjango.forms import *
from qdjango.models import TYPE_LAYER_FOR_WIDGET, TYPE_LAYER_FOR_DOWNLOAD, LayerAcl
from qdjango.api.utils import serialize_vectorjoin
from qdjango.models import (
TYPE_LAYER_FOR_WIDGET,
TYPE_LAYER_FOR_DOWNLOAD,
LayerAcl,
GeoConstraint,
SingleLayerConstraint,
ColumnAcl
)
from qdjango.utils.models import get_widgets4layer, comparedbdatasource
from qdjango.utils.data import QGIS_LAYER_TYPE_NO_GEOM
import json
from collections import OrderedDict




Expand Down Expand Up @@ -90,7 +92,6 @@ class QdjangoProjectCreateView(QdjangoProjectCUViewMixin, G3WGroupViewMixin, G3W
@method_decorator(permission_required('core.add_project_to_group', (Group, 'slug', 'group_slug'), return_403=True))
@method_decorator(permission_required('qdjango.add_project', return_403=True))
@method_decorator(is_active_required((Group, 'slug', 'group_slug')))
@method_decorator(check_madd('MPC:XYamtBJA_JgFGmFvEa9x193rnLg', Project))
def dispatch(self, *args, **kwargs):
return super(QdjangoProjectCreateView, self).dispatch(*args, **kwargs)

Expand Down