commit eb360786be35d4790b29a7170a58434e515fab7a Author: Klaus-Uwe Mitterer Date: Sun Aug 1 12:39:34 2021 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e589ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.swp +*.pyc +__pycache__/ +build/ +dist/ +dbsettings.egg-info/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9de488d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2021, Kumi Systems e.U. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..689e50f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include LICENSE +include README.md \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d23d636 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# django-autosecretkey + +autosecretkey is a simple reusable Django app which will make it easier to +distribute your Django project by taking care of generating a secure SECRET_KEY +and storing it outside of your project's settings.py + +## Quick start + +1. In your project's settings.py, import the app like so: + + ```from autosecretkey import AutoSecretKey``` + +2. Still in the settings.py file, replace the existing SECRET_KEY line with + something like this: + + ```SECRET_KEY = AutoSecretKey(BASE_DIR / "config.ini").secret_key``` + + (N.B.: Of course, this line has to be after the BASE_DIR line.) + + This will store the key in a file called `config.ini` in your project's base + directory (i.e. the one containing `manage.py`). + + Make sure not to ship this file with your code distribution. For example, + you may want to add it to your .gitignore file if you publish the project in + a git repository. + +## Additional configuration + +For additional security, you may want to store your secret key in a different +location than your project's base directory. You could, for example, do +something like this: + +```AutoSecretKey("/etc/your_project/configuration")``` + +You need to manually make sure that the user your Django project runs as has +the permission to read and write this file. Running something like this as +root should do the trick in Linux (replacing "djangouser" with the actual user +name): + +``` +mkdir /etc/your_project/ +touch /etc/your_project/configuration +chown djangouser /etc/your_project/configuration +``` + +In the end, this is just a simple wrapper around configparser.ConfigParser, so +you can store custom configuration values in the file that holds your secret +key. You can access the ConfigParser object as the `config` attribute of your +AutoSecretKey object. + +This is a simple example you could have in your `settings.py`: + +``` +from autosecretkey import AutoSecretKey +my_config_file = AutoSecretKey(BASE_DIR / "config.ini") +SECRET_KEY = my_config_file.secret_key +TIME_ZONE = my_config_file.config["MY_SETTINGS"]["TIME_ZONE"] +``` + +For reference, the corresponding `config.ini` might look like this: + +``` +[AutoSecretKey] +SecretKey = WellThisIsWhereYouWillFindYourSecretKey + +[MY_SETTINGS] +TIME_ZONE = UTC +``` + +All methods you can use on any other ConfigParser object can be used on that +object as well, of course, like get(), getboolean(), etc. For convenience, you +can use the AutoSecretKey object's update() method to re-read the contents of +the config file, and the write() method to write back any changes you have made +on the object to the configuration file. + +Note that the ConfigParser behaves like a RawConfigParser in that it does not +support interpolation. \ No newline at end of file diff --git a/autosecretkey/__init__.py b/autosecretkey/__init__.py new file mode 100644 index 0000000..da868fc --- /dev/null +++ b/autosecretkey/__init__.py @@ -0,0 +1,48 @@ +import configparser + +from django.core.management.utils import get_random_secret_key + +class AutoSecretKey: + @staticmethod + def write_config_file(path, config): + with open(path, "w") as outfile: + config.write(outfile) + + @classmethod + def read_config_file(cls, path, create=True): + config = configparser.ConfigParser(interpolation=None) + + try: + config.read(path) + + except FileNotFoundError: + if not create: + raise + + cls.write_config_file(path, config) + + return config + + def write(self): + self.__class__.write_config_file(self.path, self.config) + + def update(self): + self.config = self.__class__.read_config_file(self.path) + + @property + def secret_key(self): + try: + return self.config[self.section][self.config_key] + except (KeyError, TypeError): + new_key = get_random_secret_key() + + self.config[self.section] = { self.config_key: new_key } + self.write() + + return new_key + + def __init__(self, path, section="AutoSecretKey", config_key="SecretKey"): + self.path = path + self.section = section + self.config_key = config_key + self.update() diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..8752bf9 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,32 @@ +[metadata] +name = django-autosecretkey +version = 0.9 +description = A simple Django app to store secret keys outside of settings.py +long_description = file: README.md +long_description_content_type = text/markdown +url = https://kumig.it/kumisystems/django-autosecretkey +author = Kumi Systems e.U. +author_email = support@kumi.systems +license = BSD-2-Clause +classifiers = + Environment :: Web Environment + Framework :: Django + Framework :: Django :: 3.0 + Intended Audience :: Developers + License :: OSI Approved :: BSD License + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Topic :: Internet :: WWW/HTTP + Topic :: Internet :: WWW/HTTP :: Dynamic Content + +[options] +include_package_data = true +packages = find: +install_requires = + django \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6068493 --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup()